Enabled payment for Corporate along with increasing every single one of their students/teachers expiry date as well
This commit is contained in:
@@ -10,10 +10,11 @@ interface Props {
|
|||||||
price: number;
|
price: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
duration_unit: DurationUnit;
|
duration_unit: DurationUnit;
|
||||||
|
setIsLoading: (isLoading: boolean) => void;
|
||||||
onSuccess: (duration: number, duration_unit: DurationUnit) => void;
|
onSuccess: (duration: number, duration_unit: DurationUnit) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PayPalPayment({price, currency, duration, duration_unit, onSuccess}: Props) {
|
export default function PayPalPayment({price, currency, duration, duration_unit, setIsLoading, onSuccess}: Props) {
|
||||||
const [{options}, dispatch] = usePayPalScriptReducer();
|
const [{options}, dispatch] = usePayPalScriptReducer();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -28,7 +29,7 @@ export default function PayPalPayment({price, currency, duration, duration_unit,
|
|||||||
}, [currency]);
|
}, [currency]);
|
||||||
|
|
||||||
const createOrder = async (data: CreateOrderData, actions: CreateOrderActions): Promise<string> => {
|
const createOrder = async (data: CreateOrderData, actions: CreateOrderActions): Promise<string> => {
|
||||||
console.log(data, actions);
|
setIsLoading(true);
|
||||||
|
|
||||||
return axios
|
return axios
|
||||||
.post<OrderResponseBody>("/api/paypal", {currencyCode: currency, price})
|
.post<OrderResponseBody>("/api/paypal", {currencyCode: currency, price})
|
||||||
@@ -49,13 +50,11 @@ export default function PayPalPayment({price, currency, duration, duration_unit,
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onError = async (data: Record<string, unknown>) => {
|
const onError = async (data: Record<string, unknown>) => {
|
||||||
console.log(data);
|
setIsLoading(false);
|
||||||
toast.error("ERROR!");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCancel = async (data: Record<string, unknown>, actions: OnCancelledActions) => {
|
const onCancel = async (data: Record<string, unknown>, actions: OnCancelledActions) => {
|
||||||
console.log(data, actions);
|
setIsLoading(false);
|
||||||
toast.error("CANCEL!");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -20,10 +20,9 @@ import Input from "@/components/Low/Input";
|
|||||||
import Button from "@/components/Low/Button";
|
import Button from "@/components/Low/Button";
|
||||||
|
|
||||||
export default function PaymentDue({user, reload}: {user: User; reload: () => void}) {
|
export default function PaymentDue({user, reload}: {user: User; reload: () => void}) {
|
||||||
const [selectedPackage, setPackage] = useState<string>();
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [code, setCode] = useState<string>();
|
|
||||||
|
|
||||||
const {packages, isLoading} = usePackages();
|
const {packages} = usePackages();
|
||||||
const {users} = useUsers();
|
const {users} = useUsers();
|
||||||
const {groups} = useGroups();
|
const {groups} = useGroups();
|
||||||
|
|
||||||
@@ -38,13 +37,25 @@ export default function PaymentDue({user, reload}: {user: User; reload: () => vo
|
|||||||
return userGroupsAdminTypes.every((t) => t !== "admin");
|
return userGroupsAdminTypes.every((t) => t !== "admin");
|
||||||
};
|
};
|
||||||
|
|
||||||
return user ? (
|
return (
|
||||||
|
<>
|
||||||
|
{isLoading && (
|
||||||
|
<div className="w-screen h-screen absolute top-0 left-0 overflow-hidden z-[999] bg-black/60">
|
||||||
|
<div className="w-fit h-fit absolute top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2 animate-pulse flex flex-col gap-8 items-center text-white">
|
||||||
|
<span className={clsx("loading loading-infinity w-48")} />
|
||||||
|
<span className={clsx("font-bold text-2xl")}>Completing your payment...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{user ? (
|
||||||
<Layout user={user} navDisabled>
|
<Layout user={user} navDisabled>
|
||||||
<div className="flex flex-col items-center justify-center text-center w-full gap-4">
|
<div className="flex flex-col items-center justify-center text-center w-full gap-4">
|
||||||
<span className="font-bold text-lg">You do not have time credits for your account type!</span>
|
<span className="font-bold text-lg">You do not have time credits for your account type!</span>
|
||||||
{isIndividual() && (
|
{isIndividual() && (
|
||||||
<div className="flex flex-col items-center w-full overflow-x-scroll scrollbar-hide gap-12">
|
<div className="flex flex-col items-center w-full overflow-x-scroll scrollbar-hide gap-12">
|
||||||
<span className="max-w-lg">To add to your use of EnCoach, please purchase one of the time packages available below:</span>
|
<span className="max-w-lg">
|
||||||
|
To add to your use of EnCoach, please purchase one of the time packages available below:
|
||||||
|
</span>
|
||||||
<div className="w-full flex flex-wrap justify-center gap-8">
|
<div className="w-full flex flex-wrap justify-center gap-8">
|
||||||
{packages.map((p) => (
|
{packages.map((p) => (
|
||||||
<div key={p.id} className={clsx("p-4 bg-white rounded-xl flex flex-col gap-6 items-start")}>
|
<div key={p.id} className={clsx("p-4 bg-white rounded-xl flex flex-col gap-6 items-start")}>
|
||||||
@@ -52,7 +63,9 @@ export default function PaymentDue({user, reload}: {user: User; reload: () => vo
|
|||||||
<img src="/logo_title.png" alt="EnCoach's Logo" className="w-32" />
|
<img src="/logo_title.png" alt="EnCoach's Logo" className="w-32" />
|
||||||
<span className="font-semibold text-xl">
|
<span className="font-semibold text-xl">
|
||||||
EnCoach - {p.duration}{" "}
|
EnCoach - {p.duration}{" "}
|
||||||
{capitalize(p.duration === 1 ? p.duration_unit.slice(0, p.duration_unit.length - 1) : p.duration_unit)}
|
{capitalize(
|
||||||
|
p.duration === 1 ? p.duration_unit.slice(0, p.duration_unit.length - 1) : p.duration_unit,
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-2 items-start w-full">
|
<div className="flex flex-col gap-2 items-start w-full">
|
||||||
@@ -62,6 +75,7 @@ export default function PaymentDue({user, reload}: {user: User; reload: () => vo
|
|||||||
</span>
|
</span>
|
||||||
<PayPalPayment
|
<PayPalPayment
|
||||||
{...p}
|
{...p}
|
||||||
|
setIsLoading={setIsLoading}
|
||||||
onSuccess={(duration, duration_unit) => {
|
onSuccess={(duration, duration_unit) => {
|
||||||
setTimeout(reload, 500);
|
setTimeout(reload, 500);
|
||||||
}}
|
}}
|
||||||
@@ -88,7 +102,7 @@ export default function PaymentDue({user, reload}: {user: User; reload: () => vo
|
|||||||
<div className={clsx("p-4 bg-white rounded-xl flex flex-col gap-6 items-start")}>
|
<div className={clsx("p-4 bg-white rounded-xl flex flex-col gap-6 items-start")}>
|
||||||
<div className="flex flex-col items-start mb-2">
|
<div className="flex flex-col items-start mb-2">
|
||||||
<img src="/logo_title.png" alt="EnCoach's Logo" className="w-32" />
|
<img src="/logo_title.png" alt="EnCoach's Logo" className="w-32" />
|
||||||
<span className="font-semibold text-xl">EnCoach - {user.corporateInformation?.monthlyDuration} Month(s)</span>
|
<span className="font-semibold text-xl">EnCoach - {user.corporateInformation?.monthlyDuration} Months</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-2 items-start w-full">
|
<div className="flex flex-col gap-2 items-start w-full">
|
||||||
<span className="text-2xl">
|
<span className="text-2xl">
|
||||||
@@ -96,11 +110,13 @@ export default function PaymentDue({user, reload}: {user: User; reload: () => vo
|
|||||||
{getSymbolFromCurrency(user.corporateInformation.payment.currency)}
|
{getSymbolFromCurrency(user.corporateInformation.payment.currency)}
|
||||||
</span>
|
</span>
|
||||||
<PayPalPayment
|
<PayPalPayment
|
||||||
|
setIsLoading={setIsLoading}
|
||||||
currency={user.corporateInformation.payment.currency}
|
currency={user.corporateInformation.payment.currency}
|
||||||
price={user.corporateInformation.payment.value}
|
price={user.corporateInformation.payment.value}
|
||||||
duration={user.corporateInformation.monthlyDuration}
|
duration={user.corporateInformation.monthlyDuration}
|
||||||
duration_unit="months"
|
duration_unit="months"
|
||||||
onSuccess={(duration, duration_unit) => {
|
onSuccess={(duration, duration_unit) => {
|
||||||
|
setIsLoading(false);
|
||||||
setTimeout(reload, 500);
|
setTimeout(reload, 500);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -109,8 +125,8 @@ export default function PaymentDue({user, reload}: {user: User; reload: () => vo
|
|||||||
<span>This includes:</span>
|
<span>This includes:</span>
|
||||||
<ul className="flex flex-col items-start text-sm">
|
<ul className="flex flex-col items-start text-sm">
|
||||||
<li>
|
<li>
|
||||||
- Allow a total of {user.corporateInformation.companyInformation.userAmount} students and teachers to use
|
- Allow a total of {user.corporateInformation.companyInformation.userAmount} students and teachers to
|
||||||
EnCoach
|
use EnCoach
|
||||||
</li>
|
</li>
|
||||||
<li>- Train their abilities for the IELTS exam</li>
|
<li>- Train their abilities for the IELTS exam</li>
|
||||||
<li>- Gain insights into your students' weaknesses and strengths</li>
|
<li>- Gain insights into your students' weaknesses and strengths</li>
|
||||||
@@ -123,15 +139,19 @@ export default function PaymentDue({user, reload}: {user: User; reload: () => vo
|
|||||||
{!isIndividual() && (!user?.corporateInformation || !user?.corporateInformation?.payment) && (
|
{!isIndividual() && (!user?.corporateInformation || !user?.corporateInformation?.payment) && (
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<span className="max-w-lg">
|
<span className="max-w-lg">
|
||||||
An admin nor your agent have yet set the price intended to your requirements in terms of the amount of users you desire
|
An admin nor your agent have yet set the price intended to your requirements in terms of the amount of users you
|
||||||
and your expected monthly duration.
|
desire and your expected monthly duration.
|
||||||
|
</span>
|
||||||
|
<span className="max-w-lg">
|
||||||
|
Please try again again later or contact your agent or an admin, thank you for your patience.
|
||||||
</span>
|
</span>
|
||||||
<span className="max-w-lg">Please try again again later or contact your agent or an admin, thank you for your patience.</span>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
) : (
|
) : (
|
||||||
<div />
|
<div />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {v4} from "uuid";
|
|||||||
import {OrderResponseBody} from "@paypal/paypal-js";
|
import {OrderResponseBody} from "@paypal/paypal-js";
|
||||||
import {getAccessToken} from "@/utils/paypal";
|
import {getAccessToken} from "@/utils/paypal";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
import {Group} from "@/interfaces/user";
|
||||||
|
|
||||||
const db = getFirestore(app);
|
const db = getFirestore(app);
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (request.data.status === "COMPLETED") {
|
if (request.data.status === "COMPLETED") {
|
||||||
|
const user = req.session.user;
|
||||||
const subscriptionExpirationDate = req.session.user.subscriptionExpirationDate;
|
const subscriptionExpirationDate = req.session.user.subscriptionExpirationDate;
|
||||||
const today = moment(new Date());
|
const today = moment(new Date());
|
||||||
const dateToBeAddedTo = !subscriptionExpirationDate
|
const dateToBeAddedTo = !subscriptionExpirationDate
|
||||||
@@ -51,8 +53,30 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
{merge: true},
|
{merge: true},
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).json({ok: true});
|
if (user.type === "corporate") {
|
||||||
return;
|
const snapshot = await getDocs(collection(db, "groups"));
|
||||||
|
const groups: Group[] = (
|
||||||
|
snapshot.docs.map((doc) => ({
|
||||||
|
id: doc.id,
|
||||||
|
...doc.data(),
|
||||||
|
})) as Group[]
|
||||||
|
).filter((x) => x.admin === user.id);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
groups
|
||||||
|
.flatMap((x) => x.participants)
|
||||||
|
.map(
|
||||||
|
async (x) =>
|
||||||
|
await setDoc(
|
||||||
|
doc(db, "users", x),
|
||||||
|
{subscriptionExpirationDate: updatedExpirationDate.toISOString(), status: "active"},
|
||||||
|
{merge: true},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(200).json({ok: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(404).json({ok: false, reason: "Order ID not found or purchase was not approved!"});
|
res.status(404).json({ok: false, reason: "Order ID not found or purchase was not approved!"});
|
||||||
|
|||||||
Reference in New Issue
Block a user