Enabled payment for Corporate along with increasing every single one of their students/teachers expiry date as well

This commit is contained in:
Tiago Ribeiro
2023-11-26 11:01:27 +00:00
parent 7e91a989b3
commit fa544bf4e8
3 changed files with 127 additions and 84 deletions

View File

@@ -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 (

View File

@@ -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,31 +37,86 @@ 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 (
<Layout user={user} navDisabled> <>
<div className="flex flex-col items-center justify-center text-center w-full gap-4"> {isLoading && (
<span className="font-bold text-lg">You do not have time credits for your account type!</span> <div className="w-screen h-screen absolute top-0 left-0 overflow-hidden z-[999] bg-black/60">
{isIndividual() && ( <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">
<div className="flex flex-col items-center w-full overflow-x-scroll scrollbar-hide gap-12"> <span className={clsx("loading loading-infinity w-48")} />
<span className="max-w-lg">To add to your use of EnCoach, please purchase one of the time packages available below:</span> <span className={clsx("font-bold text-2xl")}>Completing your payment...</span>
<div className="w-full flex flex-wrap justify-center gap-8"> </div>
{packages.map((p) => ( </div>
<div key={p.id} className={clsx("p-4 bg-white rounded-xl flex flex-col gap-6 items-start")}> )}
{user ? (
<Layout user={user} navDisabled>
<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>
{isIndividual() && (
<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>
<div className="w-full flex flex-wrap justify-center gap-8">
{packages.map((p) => (
<div key={p.id} className={clsx("p-4 bg-white rounded-xl flex flex-col gap-6 items-start")}>
<div className="flex flex-col items-start mb-2">
<img src="/logo_title.png" alt="EnCoach's Logo" className="w-32" />
<span className="font-semibold text-xl">
EnCoach - {p.duration}{" "}
{capitalize(
p.duration === 1 ? p.duration_unit.slice(0, p.duration_unit.length - 1) : p.duration_unit,
)}
</span>
</div>
<div className="flex flex-col gap-2 items-start w-full">
<span className="text-2xl">
{p.price}
{getSymbolFromCurrency(p.currency)}
</span>
<PayPalPayment
{...p}
setIsLoading={setIsLoading}
onSuccess={(duration, duration_unit) => {
setTimeout(reload, 500);
}}
/>
</div>
<div className="flex flex-col gap-1 items-start">
<span>This includes:</span>
<ul className="flex flex-col items-start text-sm">
<li>- Train your abilities for the IELTS exam</li>
<li>- Gain insights into your weaknesses and strengths</li>
<li>- Allow yourself to correctly prepare for the exam</li>
</ul>
</div>
</div>
))}
</div>
</div>
)}
{!isIndividual() && user?.corporateInformation && user?.corporateInformation.payment && (
<div className="flex flex-col items-center">
<span className="max-w-lg">
To add to your use of EnCoach and that of your students and teachers, please pay your designated package below:
</span>
<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"> <span className="font-semibold text-xl">EnCoach - {user.corporateInformation?.monthlyDuration} Months</span>
EnCoach - {p.duration}{" "}
{capitalize(p.duration === 1 ? p.duration_unit.slice(0, p.duration_unit.length - 1) : p.duration_unit)}
</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">
{p.price} {user.corporateInformation.payment.value}
{getSymbolFromCurrency(p.currency)} {getSymbolFromCurrency(user.corporateInformation.payment.currency)}
</span> </span>
<PayPalPayment <PayPalPayment
{...p} setIsLoading={setIsLoading}
currency={user.corporateInformation.payment.currency}
price={user.corporateInformation.payment.value}
duration={user.corporateInformation.monthlyDuration}
duration_unit="months"
onSuccess={(duration, duration_unit) => { onSuccess={(duration, duration_unit) => {
setIsLoading(false);
setTimeout(reload, 500); setTimeout(reload, 500);
}} }}
/> />
@@ -70,68 +124,34 @@ export default function PaymentDue({user, reload}: {user: User; reload: () => vo
<div className="flex flex-col gap-1 items-start"> <div className="flex flex-col gap-1 items-start">
<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>- Train your abilities for the IELTS exam</li> <li>
<li>- Gain insights into your weaknesses and strengths</li> - Allow a total of {user.corporateInformation.companyInformation.userAmount} students and teachers to
<li>- Allow yourself to correctly prepare for the exam</li> use EnCoach
</li>
<li>- Train their abilities for the IELTS exam</li>
<li>- Gain insights into your students&apos; weaknesses and strengths</li>
<li>- Allow them to correctly prepare for the exam</li>
</ul> </ul>
</div> </div>
</div> </div>
))}
</div>
</div>
)}
{!isIndividual() && user?.corporateInformation && user?.corporateInformation.payment && (
<div className="flex flex-col items-center">
<span className="max-w-lg">
To add to your use of EnCoach and that of your students and teachers, please pay your designated package below:
</span>
<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">
<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>
</div> </div>
<div className="flex flex-col gap-2 items-start w-full"> )}
<span className="text-2xl"> {!isIndividual() && (!user?.corporateInformation || !user?.corporateInformation?.payment) && (
{user.corporateInformation.payment.value} <div className="flex flex-col items-center">
{getSymbolFromCurrency(user.corporateInformation.payment.currency)} <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 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>
<PayPalPayment
currency={user.corporateInformation.payment.currency}
price={user.corporateInformation.payment.value}
duration={user.corporateInformation.monthlyDuration}
duration_unit="months"
onSuccess={(duration, duration_unit) => {
setTimeout(reload, 500);
}}
/>
</div> </div>
<div className="flex flex-col gap-1 items-start"> )}
<span>This includes:</span>
<ul className="flex flex-col items-start text-sm">
<li>
- Allow a total of {user.corporateInformation.companyInformation.userAmount} students and teachers to use
EnCoach
</li>
<li>- Train their abilities for the IELTS exam</li>
<li>- Gain insights into your students&apos; weaknesses and strengths</li>
<li>- Allow them to correctly prepare for the exam</li>
</ul>
</div>
</div>
</div> </div>
)} </Layout>
{!isIndividual() && (!user?.corporateInformation || !user?.corporateInformation?.payment) && ( ) : (
<div className="flex flex-col items-center"> <div />
<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 </>
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>
</div>
)}
</div>
</Layout>
) : (
<div />
); );
} }

View File

@@ -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!"});