Started implementing the Paymob integration

This commit is contained in:
Tiago Ribeiro
2024-05-13 10:38:05 +01:00
parent 8b2459c304
commit f967282f71
5 changed files with 407 additions and 293 deletions

View File

@@ -4,194 +4,147 @@ import PayPalPayment from "@/components/PayPalPayment";
import useGroups from "@/hooks/useGroups";
import usePackages from "@/hooks/usePackages";
import useUsers from "@/hooks/useUsers";
import { User } from "@/interfaces/user";
import {User} from "@/interfaces/user";
import clsx from "clsx";
import { capitalize } from "lodash";
import { useEffect, useState } from "react";
import {capitalize} from "lodash";
import {useEffect, useState} from "react";
import getSymbolFromCurrency from "currency-symbol-map";
import useInvites from "@/hooks/useInvites";
import { BsArrowRepeat } from "react-icons/bs";
import {BsArrowRepeat} from "react-icons/bs";
import InviteCard from "@/components/Medium/InviteCard";
import { useRouter } from "next/router";
import { PayPalScriptProvider } from "@paypal/react-paypal-js";
import { usePaypalTracking } from "@/hooks/usePaypalTracking";
import { ToastContainer } from "react-toastify";
import {useRouter} from "next/router";
import {PayPalScriptProvider} from "@paypal/react-paypal-js";
import {usePaypalTracking} from "@/hooks/usePaypalTracking";
import {ToastContainer} from "react-toastify";
import useDiscounts from "@/hooks/useDiscounts";
import PaymobPayment from "@/components/PaymobPayment";
interface Props {
user: User;
hasExpired?: boolean;
clientID: string;
reload: () => void;
user: User;
hasExpired?: boolean;
clientID: string;
reload: () => void;
}
export default function PaymentDue({
user,
hasExpired = false,
clientID,
reload,
}: Props) {
const [isLoading, setIsLoading] = useState(false);
const [appliedDiscount, setAppliedDiscount] = useState(0);
export default function PaymentDue({user, hasExpired = false, clientID, reload}: Props) {
const [isLoading, setIsLoading] = useState(false);
const [appliedDiscount, setAppliedDiscount] = useState(0);
const router = useRouter();
const router = useRouter();
const { packages } = usePackages();
const { discounts } = useDiscounts();
const { users } = useUsers();
const { groups } = useGroups();
const {
invites,
isLoading: isInvitesLoading,
reload: reloadInvites,
} = useInvites({ to: user?.id });
const trackingId = usePaypalTracking();
const {packages} = usePackages();
const {discounts} = useDiscounts();
const {users} = useUsers();
const {groups} = useGroups();
const {invites, isLoading: isInvitesLoading, reload: reloadInvites} = useInvites({to: user?.id});
const trackingId = usePaypalTracking();
useEffect(() => {
const userDiscounts = discounts.filter((x) =>
user.email.endsWith(`@${x.domain}`),
);
if (userDiscounts.length === 0) return;
useEffect(() => {
const userDiscounts = discounts.filter((x) => user.email.endsWith(`@${x.domain}`));
if (userDiscounts.length === 0) return;
const biggestDiscount = [...userDiscounts]
.sort((a, b) => b.percentage - a.percentage)
.shift();
if (!biggestDiscount) return;
const biggestDiscount = [...userDiscounts].sort((a, b) => b.percentage - a.percentage).shift();
if (!biggestDiscount) return;
setAppliedDiscount(biggestDiscount.percentage);
}, [discounts, user]);
setAppliedDiscount(biggestDiscount.percentage);
}, [discounts, user]);
const isIndividual = () => {
if (user?.type === "developer") return true;
if (user?.type !== "student") return false;
const userGroups = groups.filter((g) => g.participants.includes(user?.id));
const isIndividual = () => {
if (user?.type === "developer") return true;
if (user?.type !== "student") return false;
const userGroups = groups.filter((g) => g.participants.includes(user?.id));
if (userGroups.length === 0) return true;
if (userGroups.length === 0) return true;
const userGroupsAdminTypes = userGroups
.map((g) => users?.find((u) => u.id === g.admin)?.type)
.filter((t) => !!t);
return userGroupsAdminTypes.every((t) => t !== "corporate");
};
const userGroupsAdminTypes = userGroups.map((g) => users?.find((u) => u.id === g.admin)?.type).filter((t) => !!t);
return userGroupsAdminTypes.every((t) => t !== "corporate");
};
return (
<>
<ToastContainer />
{isLoading && (
<div className="absolute left-0 top-0 z-[999] h-screen w-screen overflow-hidden bg-black/60">
<div className="absolute left-1/2 top-1/2 flex h-fit w-fit -translate-x-1/2 -translate-y-1/2 animate-pulse flex-col items-center gap-8 text-white">
<span className={clsx("loading loading-infinity w-48")} />
<span className={clsx("text-2xl font-bold")}>
Completing your payment...
</span>
</div>
</div>
)}
{user ? (
<Layout user={user} navDisabled={hasExpired}>
{invites.length > 0 && (
<section className="flex flex-col gap-1 md:gap-3">
<div className="flex items-center gap-4">
<div
onClick={reloadInvites}
className="text-mti-purple-light hover:text-mti-purple-dark flex cursor-pointer items-center gap-2 transition duration-300 ease-in-out"
>
<span className="text-mti-black text-lg font-bold">
Invites
</span>
<BsArrowRepeat
className={clsx(
"text-xl",
isInvitesLoading && "animate-spin",
)}
/>
</div>
</div>
<span className="text-mti-gray-taupe scrollbar-hide flex gap-8 overflow-x-scroll">
{invites.map((invite) => (
<InviteCard
key={invite.id}
invite={invite}
users={users}
reload={() => {
reloadInvites();
router.reload();
}}
/>
))}
</span>
</section>
)}
return (
<>
<ToastContainer />
{isLoading && (
<div className="absolute left-0 top-0 z-[999] h-screen w-screen overflow-hidden bg-black/60">
<div className="absolute left-1/2 top-1/2 flex h-fit w-fit -translate-x-1/2 -translate-y-1/2 animate-pulse flex-col items-center gap-8 text-white">
<span className={clsx("loading loading-infinity w-48")} />
<span className={clsx("text-2xl font-bold")}>Completing your payment...</span>
</div>
</div>
)}
{user ? (
<Layout user={user} navDisabled={hasExpired}>
{invites.length > 0 && (
<section className="flex flex-col gap-1 md:gap-3">
<div className="flex items-center gap-4">
<div
onClick={reloadInvites}
className="text-mti-purple-light hover:text-mti-purple-dark flex cursor-pointer items-center gap-2 transition duration-300 ease-in-out">
<span className="text-mti-black text-lg font-bold">Invites</span>
<BsArrowRepeat className={clsx("text-xl", isInvitesLoading && "animate-spin")} />
</div>
</div>
<span className="text-mti-gray-taupe scrollbar-hide flex gap-8 overflow-x-scroll">
{invites.map((invite) => (
<InviteCard
key={invite.id}
invite={invite}
users={users}
reload={() => {
reloadInvites();
router.reload();
}}
/>
))}
</span>
</section>
)}
<div className="flex w-full flex-col items-center justify-center gap-4 text-center">
{hasExpired && (
<span className="text-lg font-bold">
You do not have time credits for your account type!
</span>
)}
{isIndividual() && (
<div className="scrollbar-hide flex w-full flex-col items-center gap-12 overflow-x-scroll">
<span className="max-w-lg">
To add to your use of EnCoach, please purchase one of the time
packages available below:
</span>
<div className="flex w-full flex-wrap justify-center gap-8">
<PayPalScriptProvider
options={{
clientId: clientID,
currency: "USD",
intent: "capture",
commit: true,
}}
>
{packages.map((p) => (
<div
key={p.id}
className={clsx(
"flex flex-col items-start gap-6 rounded-xl bg-white p-4",
)}
>
<div className="mb-2 flex flex-col items-start">
<img
src="/logo_title.png"
alt="EnCoach's Logo"
className="w-32"
/>
<span className="text-xl font-semibold">
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 w-full flex-col items-start gap-2">
{!appliedDiscount && (
<span className="text-2xl">
{p.price}
{getSymbolFromCurrency(p.currency)}
</span>
)}
{appliedDiscount && (
<div className="flex items-center gap-2">
<span className="text-2xl line-through">
{p.price}
{getSymbolFromCurrency(p.currency)}
</span>
<span className="text-2xl text-mti-red-light">
{(
p.price -
p.price * (appliedDiscount / 100)
).toFixed(2)}
{getSymbolFromCurrency(p.currency)}
</span>
</div>
)}
<PayPalPayment
<div className="flex w-full flex-col items-center justify-center gap-4 text-center">
{hasExpired && <span className="text-lg font-bold">You do not have time credits for your account type!</span>}
{isIndividual() && (
<div className="scrollbar-hide flex w-full flex-col items-center gap-12 overflow-x-scroll">
<span className="max-w-lg">
To add to your use of EnCoach, please purchase one of the time packages available below:
</span>
<div className="flex w-full flex-wrap justify-center gap-8">
<PayPalScriptProvider
options={{
clientId: clientID,
currency: "USD",
intent: "capture",
commit: true,
}}>
{packages.map((p) => (
<div key={p.id} className={clsx("flex flex-col items-start gap-6 rounded-xl bg-white p-4")}>
<div className="mb-2 flex flex-col items-start">
<img src="/logo_title.png" alt="EnCoach's Logo" className="w-32" />
<span className="text-xl font-semibold">
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 w-full flex-col items-start gap-2">
{!appliedDiscount && (
<span className="text-2xl">
{p.price}
{getSymbolFromCurrency(p.currency)}
</span>
)}
{appliedDiscount && (
<div className="flex items-center gap-2">
<span className="text-2xl line-through">
{p.price}
{getSymbolFromCurrency(p.currency)}
</span>
<span className="text-2xl text-mti-red-light">
{(p.price - p.price * (appliedDiscount / 100)).toFixed(2)}
{getSymbolFromCurrency(p.currency)}
</span>
</div>
)}
{/* <PayPalPayment
key={clientID}
clientID={clientID}
setIsLoading={setIsLoading}
@@ -208,127 +161,110 @@ export default function PaymentDue({
p.price * (appliedDiscount / 100)
).toFixed(2)
}
/>
</div>
<div className="flex flex-col items-start gap-1">
<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>
))}
</PayPalScriptProvider>
</div>
</div>
)}
{!isIndividual() &&
user.type === "corporate" &&
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(
"flex flex-col items-start gap-6 rounded-xl bg-white p-4",
)}
>
<div className="mb-2 flex flex-col items-start">
<img
src="/logo_title.png"
alt="EnCoach's Logo"
className="w-32"
/>
<span className="text-xl font-semibold">
EnCoach - {user.corporateInformation?.monthlyDuration}{" "}
Months
</span>
</div>
<div className="flex w-full flex-col items-start gap-2">
<span className="text-2xl">
{user.corporateInformation.payment.value}
{getSymbolFromCurrency(
user.corporateInformation.payment.currency,
)}
</span>
<PayPalPayment
key={clientID}
clientID={clientID}
setIsLoading={setIsLoading}
currency={user.corporateInformation.payment.currency}
price={user.corporateInformation.payment.value}
duration={user.corporateInformation.monthlyDuration}
duration_unit="months"
onSuccess={() => {
setIsLoading(false);
setTimeout(reload, 500);
}}
loadScript
trackingId={trackingId}
/>
</div>
<div className="flex flex-col items-start gap-1">
<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>
)}
{!isIndividual() && user.type !== "corporate" && (
<div className="flex flex-col items-center">
<span className="max-w-lg">
You are not the person in charge of your time credits, please
contact your administrator about this situation.
</span>
<span className="max-w-lg">
If you believe this to be a mistake, please contact the
platform&apos;s administration, thank you for your patience.
</span>
</div>
)}
{!isIndividual() &&
user.type === "corporate" &&
!user.corporateInformation.payment && (
<div className="flex flex-col items-center">
<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 later or contact your agent or an admin,
thank you for your patience.
</span>
</div>
)}
</div>
</Layout>
) : (
<div />
)}
</>
);
/> */}
<PaymobPayment
key={clientID}
user={user}
description="Description"
paymentID="123"
title="Title"
setIsLoading={setIsLoading}
onSuccess={() => {
setTimeout(reload, 500);
}}
currency={p.currency}
duration={p.duration}
duration_unit={p.duration_unit}
price={+(p.price - p.price * (appliedDiscount / 100)).toFixed(2)}
/>
</div>
<div className="flex flex-col items-start gap-1">
<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>
))}
</PayPalScriptProvider>
</div>
</div>
)}
{!isIndividual() && user.type === "corporate" && 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("flex flex-col items-start gap-6 rounded-xl bg-white p-4")}>
<div className="mb-2 flex flex-col items-start">
<img src="/logo_title.png" alt="EnCoach's Logo" className="w-32" />
<span className="text-xl font-semibold">EnCoach - {user.corporateInformation?.monthlyDuration} Months</span>
</div>
<div className="flex w-full flex-col items-start gap-2">
<span className="text-2xl">
{user.corporateInformation.payment.value}
{getSymbolFromCurrency(user.corporateInformation.payment.currency)}
</span>
<PayPalPayment
key={clientID}
clientID={clientID}
setIsLoading={setIsLoading}
currency={user.corporateInformation.payment.currency}
price={user.corporateInformation.payment.value}
duration={user.corporateInformation.monthlyDuration}
duration_unit="months"
onSuccess={() => {
setIsLoading(false);
setTimeout(reload, 500);
}}
loadScript
trackingId={trackingId}
/>
</div>
<div className="flex flex-col items-start gap-1">
<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>
)}
{!isIndividual() && user.type !== "corporate" && (
<div className="flex flex-col items-center">
<span className="max-w-lg">
You are not the person in charge of your time credits, please contact your administrator about this situation.
</span>
<span className="max-w-lg">
If you believe this to be a mistake, please contact the platform&apos;s administration, thank you for your
patience.
</span>
</div>
)}
{!isIndividual() && user.type === "corporate" && !user.corporateInformation.payment && (
<div className="flex flex-col items-center">
<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 later or contact your agent or an admin, thank you for your patience.
</span>
</div>
)}
</div>
</Layout>
) : (
<div />
)}
</>
);
}