235 lines
9.4 KiB
TypeScript
235 lines
9.4 KiB
TypeScript
/* eslint-disable @next/next/no-img-element */
|
|
import Layout from "@/components/High/Layout";
|
|
import useGroups from "@/hooks/useGroups";
|
|
import usePackages from "@/hooks/usePackages";
|
|
import useUsers from "@/hooks/useUsers";
|
|
import {User} from "@/interfaces/user";
|
|
import clsx from "clsx";
|
|
import {capitalize} from "lodash";
|
|
import {useEffect, useState} from "react";
|
|
import useInvites from "@/hooks/useInvites";
|
|
import {BsArrowRepeat} from "react-icons/bs";
|
|
import InviteCard from "@/components/Medium/InviteCard";
|
|
import {useRouter} from "next/router";
|
|
import {ToastContainer} from "react-toastify";
|
|
import useDiscounts from "@/hooks/useDiscounts";
|
|
import PaymobPayment from "@/components/PaymobPayment";
|
|
import moment from "moment";
|
|
|
|
interface Props {
|
|
user: User;
|
|
hasExpired?: boolean;
|
|
reload: () => void;
|
|
}
|
|
|
|
export default function PaymentDue({user, hasExpired = false, reload}: Props) {
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [appliedDiscount, setAppliedDiscount] = useState(0);
|
|
|
|
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});
|
|
|
|
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 || (biggestDiscount.validUntil && moment(biggestDiscount.validUntil).isBefore(moment()))) return;
|
|
|
|
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));
|
|
|
|
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");
|
|
};
|
|
|
|
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 flex-col items-center gap-8 text-white">
|
|
<span className={clsx("loading loading-infinity w-48 animate-pulse")} />
|
|
<span className={clsx("text-2xl font-bold animate-pulse")}>Completing your payment...</span>
|
|
<span>If you canceled your payment or it failed, please click the button below to restart</span>
|
|
<button
|
|
onClick={() => setIsLoading(false)}
|
|
className="border border-white rounded-full px-4 py-2 hover:bg-white/80 hover:text-black cursor-pointer transition ease-in-out duration-300">
|
|
Cancel Payment
|
|
</button>
|
|
</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">
|
|
{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 === 0 && (
|
|
<span className="text-2xl">
|
|
{p.price} {p.currency}
|
|
</span>
|
|
)}
|
|
{appliedDiscount > 0 && (
|
|
<div className="flex items-center gap-2">
|
|
<span className="text-2xl line-through">
|
|
{p.price} {p.currency}
|
|
</span>
|
|
<span className="text-2xl text-mti-red-light">
|
|
{(p.price - p.price * (appliedDiscount / 100)).toFixed(2)} {p.currency}
|
|
</span>
|
|
</div>
|
|
)}
|
|
<PaymobPayment
|
|
user={user}
|
|
setIsPaymentLoading={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>
|
|
))}
|
|
</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} {user.corporateInformation.payment.currency}
|
|
</span>
|
|
<PaymobPayment
|
|
user={user}
|
|
setIsPaymentLoading={setIsLoading}
|
|
currency={user.corporateInformation.payment.currency}
|
|
price={user.corporateInformation.payment.value}
|
|
duration={user.corporateInformation.monthlyDuration}
|
|
duration_unit="months"
|
|
onSuccess={() => {
|
|
setIsLoading(false);
|
|
setTimeout(reload, 500);
|
|
}}
|
|
/>
|
|
</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' 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'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 />
|
|
)}
|
|
</>
|
|
);
|
|
}
|