Merge branch 'develop' into bug-fixing-140223
This commit is contained in:
@@ -4,9 +4,9 @@ import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import axios from "axios";
|
||||
import formidable from "formidable-serverless";
|
||||
import {getStorage, ref, uploadBytes} from "firebase/storage";
|
||||
import {ref, uploadBytes} from "firebase/storage";
|
||||
import fs from "fs";
|
||||
import {app} from "@/firebase";
|
||||
import {storage} from "@/firebase";
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
@@ -16,8 +16,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
return;
|
||||
}
|
||||
|
||||
const storage = getStorage(app);
|
||||
|
||||
const form = formidable({keepExtensions: true});
|
||||
await form.parse(req, async (err: any, fields: any, files: any) => {
|
||||
if (err) console.log(err);
|
||||
|
||||
@@ -4,9 +4,9 @@ import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import axios from "axios";
|
||||
import formidable from "formidable-serverless";
|
||||
import {getStorage, ref, uploadBytes} from "firebase/storage";
|
||||
import {ref, uploadBytes} from "firebase/storage";
|
||||
import fs from "fs";
|
||||
import {app} from "@/firebase";
|
||||
import {storage} from "@/firebase";
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
@@ -16,8 +16,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
return;
|
||||
}
|
||||
|
||||
const storage = getStorage(app);
|
||||
|
||||
const form = formidable({keepExtensions: true});
|
||||
await form.parse(req, async (err: any, fields: any, files: any) => {
|
||||
if (err) console.log(err);
|
||||
|
||||
194
src/pages/api/payments/files/[type]/[paymentId].ts
Normal file
194
src/pages/api/payments/files/[type]/[paymentId].ts
Normal file
@@ -0,0 +1,194 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { app, storage } from "@/firebase";
|
||||
import {
|
||||
getFirestore,
|
||||
getDoc,
|
||||
doc,
|
||||
updateDoc,
|
||||
deleteField,
|
||||
} from "firebase/firestore";
|
||||
import { withIronSessionApiRoute } from "iron-session/next";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { FilesStorage } from "@/interfaces/storage.files";
|
||||
|
||||
import { Payment } from "@/interfaces/paypal";
|
||||
import fs from "fs";
|
||||
import {
|
||||
ref,
|
||||
uploadBytes,
|
||||
deleteObject,
|
||||
getDownloadURL,
|
||||
} from "firebase/storage";
|
||||
import formidable from "formidable-serverless";
|
||||
|
||||
const db = getFirestore(app);
|
||||
|
||||
const getPaymentField = (type: FilesStorage) => {
|
||||
switch (type) {
|
||||
case "commission":
|
||||
return "commissionTransfer";
|
||||
case "corporate":
|
||||
return "corporateTransfer";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async (
|
||||
paymentId: string,
|
||||
paymentField: "commissionTransfer" | "corporateTransfer"
|
||||
) => {
|
||||
const paymentRef = doc(db, "payments", paymentId);
|
||||
const paymentDoc = await getDoc(paymentRef);
|
||||
const { [paymentField]: paymentFieldPath } = paymentDoc.data() as Payment;
|
||||
// Create a reference to the file to delete
|
||||
const documentRef = ref(storage, paymentFieldPath);
|
||||
await deleteObject(documentRef);
|
||||
await updateDoc(paymentRef, {
|
||||
[paymentField]: deleteField(),
|
||||
});
|
||||
};
|
||||
|
||||
const handleUpload = async (
|
||||
req: NextApiRequest,
|
||||
paymentId: string,
|
||||
paymentField: "commissionTransfer" | "corporateTransfer"
|
||||
) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const form = formidable({ keepExtensions: true });
|
||||
form.parse(req, async (err: any, fields: any, files: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const { file } = files;
|
||||
const fileName = Date.now() + "-" + file.name;
|
||||
const fileRef = ref(storage, fileName);
|
||||
|
||||
const binary = fs.readFileSync(file.path).buffer;
|
||||
const snapshot = await uploadBytes(fileRef, binary);
|
||||
fs.rmSync(file.path);
|
||||
|
||||
const paymentRef = doc(db, "payments", paymentId);
|
||||
|
||||
await updateDoc(paymentRef, {
|
||||
[paymentField]: snapshot.ref.fullPath,
|
||||
});
|
||||
resolve(snapshot.ref.fullPath);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session.user) {
|
||||
res.status(401).json({ ok: false });
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method === "GET") return await get(req, res);
|
||||
if (req.method === "POST") return await post(req, res);
|
||||
if (req.method === "DELETE") return await del(req, res);
|
||||
if (req.method === "PATCH") return await patch(req, res);
|
||||
|
||||
res.status(404).json(undefined);
|
||||
}
|
||||
|
||||
async function get(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { type, paymentId } = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({ error: "Failed to identify payment field" });
|
||||
return;
|
||||
}
|
||||
const paymentRef = doc(db, "payments", paymentId);
|
||||
const { [paymentField]: paymentFieldPath } = (
|
||||
await getDoc(paymentRef)
|
||||
).data() as Payment;
|
||||
|
||||
// Create a reference to the file to delete
|
||||
const documentRef = ref(storage, paymentFieldPath);
|
||||
const url = await getDownloadURL(documentRef);
|
||||
res.status(200).json({ url, name: documentRef.name });
|
||||
}
|
||||
|
||||
async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { type, paymentId } = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({ error: "Failed to identify payment field" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const ref = await handleUpload(req, paymentId, paymentField);
|
||||
res.status(200).json({ ref });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error });
|
||||
}
|
||||
}
|
||||
|
||||
async function del(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { type, paymentId } = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({ error: "Failed to identify payment field" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await handleDelete(paymentId, paymentField);
|
||||
res.status(200).json({ ok: true });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: "Failed to delete file" });
|
||||
}
|
||||
}
|
||||
|
||||
async function patch(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { type, paymentId } = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({ error: "Failed to identify payment field" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await handleDelete(paymentId, paymentField);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: "Failed to delete file" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const ref = await handleUpload(req, paymentId, paymentField);
|
||||
res.status(200).json({ ref });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: "Failed to upload file" });
|
||||
}
|
||||
}
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
@@ -3,7 +3,7 @@ import type {NextApiRequest, NextApiResponse} from "next";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import {getDownloadURL, getStorage, ref} from "firebase/storage";
|
||||
import {app} from "@/firebase";
|
||||
import {app, storage} from "@/firebase";
|
||||
import axios from "axios";
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
@@ -14,7 +14,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
return;
|
||||
}
|
||||
|
||||
const storage = getStorage(app);
|
||||
const {path} = req.body as {path: string};
|
||||
|
||||
const pathReference = ref(storage, path);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type {NextApiRequest, NextApiResponse} from "next";
|
||||
import {app} from "@/firebase";
|
||||
import {app, storage} from "@/firebase";
|
||||
import {getFirestore, collection, getDocs, getDoc, doc, setDoc, query, where} from "firebase/firestore";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
@@ -11,9 +11,8 @@ import {errorMessages} from "@/constants/errors";
|
||||
import moment from "moment";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import {Payment} from "@/interfaces/paypal";
|
||||
|
||||
import { toFixedNumber } from "@/utils/number";
|
||||
const db = getFirestore(app);
|
||||
const storage = getStorage(app);
|
||||
const auth = getAuth(app);
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
@@ -33,7 +32,7 @@ const managePaymentRecords = async (user: User, userId: string | undefined): Pro
|
||||
corporate: userId,
|
||||
agent: user.corporateInformation.referralAgent,
|
||||
agentCommission: user.corporateInformation.payment!.commission,
|
||||
agentValue: (user.corporateInformation.payment!.commission / 100) * user.corporateInformation.payment!.value,
|
||||
agentValue: toFixedNumber((user.corporateInformation.payment!.commission / 100) * user.corporateInformation.payment!.value, 2),
|
||||
currency: user.corporateInformation.payment!.currency,
|
||||
value: user.corporateInformation.payment!.value,
|
||||
isPaid: false,
|
||||
|
||||
@@ -24,6 +24,8 @@ import Select from "react-select";
|
||||
import Input from "@/components/Low/Input";
|
||||
import ReactDatePicker from "react-datepicker";
|
||||
import moment from "moment";
|
||||
import PaymentAssetManager from "@/components/PaymentAssetManager";
|
||||
import { toFixedNumber } from "@/utils/number";
|
||||
|
||||
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
||||
const user = req.session.user;
|
||||
@@ -88,7 +90,7 @@ const PaymentCreator = ({onClose, reload, showComission = false}: {onClose: () =
|
||||
corporate: corporate?.id,
|
||||
agent: referralAgent?.id,
|
||||
agentCommission: commission,
|
||||
agentValue: (commission / 100) * price,
|
||||
agentValue: toFixedNumber((commission / 100) * price, 2),
|
||||
currency,
|
||||
value: price,
|
||||
isPaid: false,
|
||||
@@ -306,6 +308,107 @@ export default function PaymentRecord() {
|
||||
.finally(reload);
|
||||
};
|
||||
|
||||
const getFileAssetsColumns = () => {
|
||||
if (user) {
|
||||
const containerClassName = "flex gap-2 text-mti-purple-light hover:text-mti-purple-dark ease-in-out duration-300 cursor-pointer";
|
||||
switch (user.type) {
|
||||
case "corporate":
|
||||
return [
|
||||
columnHelper.accessor("corporateTransfer", {
|
||||
header: "Corporate transfer",
|
||||
cell: (info) => (
|
||||
<div className={containerClassName}>
|
||||
<PaymentAssetManager
|
||||
permissions={info.row.original.isPaid ? "read" : "write"}
|
||||
asset={info.row.original.corporateTransfer}
|
||||
paymentId={info.row.original.id}
|
||||
type="corporate"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
];
|
||||
case "agent":
|
||||
return [
|
||||
columnHelper.accessor("commissionTransfer", {
|
||||
header: "Commission transfer",
|
||||
cell: (info) => (
|
||||
<div className={containerClassName}>
|
||||
<PaymentAssetManager
|
||||
permissions="read"
|
||||
asset={info.row.original.commissionTransfer}
|
||||
paymentId={info.row.original.id}
|
||||
type="commission"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
];
|
||||
case "admin":
|
||||
return [
|
||||
columnHelper.accessor("corporateTransfer", {
|
||||
header: "Corporate transfer",
|
||||
cell: (info) => (
|
||||
<div className={containerClassName}>
|
||||
<PaymentAssetManager
|
||||
permissions="read"
|
||||
asset={info.row.original.corporateTransfer}
|
||||
paymentId={info.row.original.id}
|
||||
type="corporate"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
columnHelper.accessor("commissionTransfer", {
|
||||
header: "Commission transfer",
|
||||
cell: (info) => (
|
||||
<div className={containerClassName}>
|
||||
<PaymentAssetManager
|
||||
permissions={info.row.original.isPaid ? "read" : "write"}
|
||||
asset={info.row.original.commissionTransfer}
|
||||
paymentId={info.row.original.id}
|
||||
type="commission"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
];
|
||||
case "developer":
|
||||
return [
|
||||
columnHelper.accessor("corporateTransfer", {
|
||||
header: "Corporate transfer",
|
||||
cell: (info) => (
|
||||
<div className={containerClassName}>
|
||||
<PaymentAssetManager
|
||||
permissions="write"
|
||||
asset={info.row.original.corporateTransfer}
|
||||
paymentId={info.row.original.id}
|
||||
type="corporate"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
columnHelper.accessor("commissionTransfer", {
|
||||
header: "Commission transfer",
|
||||
cell: (info) => (
|
||||
<div className={containerClassName}>
|
||||
<PaymentAssetManager
|
||||
permissions="write"
|
||||
asset={info.row.original.commissionTransfer}
|
||||
paymentId={info.row.original.id}
|
||||
type="commission"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
const defaultColumns = [
|
||||
columnHelper.accessor("id", {
|
||||
header: "ID",
|
||||
@@ -332,7 +435,7 @@ export default function PaymentRecord() {
|
||||
header: "Amount",
|
||||
cell: (info) => (
|
||||
<span>
|
||||
{info.getValue()} {CURRENCIES.find((x) => x.currency === info.row.original.currency)?.label}
|
||||
{toFixedNumber(info.getValue(), 2)} {CURRENCIES.find((x) => x.currency === info.row.original.currency)?.label}
|
||||
</span>
|
||||
),
|
||||
}),
|
||||
@@ -354,7 +457,7 @@ export default function PaymentRecord() {
|
||||
header: "Commission Value",
|
||||
cell: (info) => (
|
||||
<span>
|
||||
{info.getValue()} {CURRENCIES.find((x) => x.currency === info.row.original.currency)?.label}
|
||||
{toFixedNumber(info.getValue(), 2)} {CURRENCIES.find((x) => x.currency === info.row.original.currency)?.label}
|
||||
</span>
|
||||
),
|
||||
}),
|
||||
@@ -368,6 +471,7 @@ export default function PaymentRecord() {
|
||||
</Checkbox>
|
||||
),
|
||||
}),
|
||||
...getFileAssetsColumns(),
|
||||
{
|
||||
header: "",
|
||||
id: "actions",
|
||||
|
||||
Reference in New Issue
Block a user