Added an Invite list to the payment due page as well
This commit is contained in:
77
src/components/Medium/InviteCard.tsx
Normal file
77
src/components/Medium/InviteCard.tsx
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { Invite } from "@/interfaces/invite";
|
||||||
|
import { User } from "@/interfaces/user";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { BsArrowRepeat } from "react-icons/bs";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
invite: Invite;
|
||||||
|
users: User[];
|
||||||
|
reload: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function InviteCard({ invite, users, reload }: Props) {
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
const inviter = users.find((u) => u.id === invite.from);
|
||||||
|
const name = !inviter
|
||||||
|
? null
|
||||||
|
: inviter.type === "corporate"
|
||||||
|
? inviter.corporateInformation?.companyInformation?.name || inviter.name
|
||||||
|
: inviter.name;
|
||||||
|
|
||||||
|
const decide = (decision: "accept" | "decline") => {
|
||||||
|
if (!confirm(`Are you sure you want to ${decision} this invite?`)) return;
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
|
axios
|
||||||
|
.get(`/api/invites/${decision}/${invite.id}`)
|
||||||
|
.then(() => {
|
||||||
|
toast.success(
|
||||||
|
`Successfully ${decision === "accept" ? "accepted" : "declined"} the invite!`,
|
||||||
|
{ toastId: "success" },
|
||||||
|
);
|
||||||
|
reload();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
toast.success(`Something went wrong, please try again later!`, {
|
||||||
|
toastId: "error",
|
||||||
|
});
|
||||||
|
reload();
|
||||||
|
})
|
||||||
|
.finally(() => setIsLoading(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="border-mti-gray-anti-flash flex min-w-[200px] flex-col gap-6 rounded-xl border p-4 text-black">
|
||||||
|
<span>Invited by {name}</span>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<button
|
||||||
|
onClick={() => decide("accept")}
|
||||||
|
disabled={isLoading}
|
||||||
|
className="bg-mti-green-ultralight hover:bg-mti-green-light w-24 rounded-lg p-2 px-4 transition duration-300 ease-in-out hover:text-white disabled:cursor-not-allowed"
|
||||||
|
>
|
||||||
|
{!isLoading && "Accept"}
|
||||||
|
{isLoading && (
|
||||||
|
<div className="flex items-center justify-center">
|
||||||
|
<BsArrowRepeat className="animate-spin text-white" size={25} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => decide("decline")}
|
||||||
|
disabled={isLoading}
|
||||||
|
className="bg-mti-red-ultralight hover:bg-mti-red-light w-24 rounded-lg p-2 px-4 transition duration-300 ease-in-out hover:text-white disabled:cursor-not-allowed"
|
||||||
|
>
|
||||||
|
{!isLoading && "Decline"}
|
||||||
|
{isLoading && (
|
||||||
|
<div className="flex items-center justify-center">
|
||||||
|
<BsArrowRepeat className="animate-spin text-white" size={25} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import Button from "@/components/Low/Button";
|
import Button from "@/components/Low/Button";
|
||||||
import ProgressBar from "@/components/Low/ProgressBar";
|
import ProgressBar from "@/components/Low/ProgressBar";
|
||||||
|
import InviteCard from "@/components/Medium/InviteCard";
|
||||||
import PayPalPayment from "@/components/PayPalPayment";
|
import PayPalPayment from "@/components/PayPalPayment";
|
||||||
import ProfileSummary from "@/components/ProfileSummary";
|
import ProfileSummary from "@/components/ProfileSummary";
|
||||||
import useAssignments from "@/hooks/useAssignments";
|
import useAssignments from "@/hooks/useAssignments";
|
||||||
@@ -102,71 +103,6 @@ export default function StudentDashboard({ user }: Props) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const InviteCard = (invite: Invite) => {
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
|
|
||||||
const inviter = users.find((u) => u.id === invite.from);
|
|
||||||
const name = !inviter
|
|
||||||
? null
|
|
||||||
: inviter.type === "corporate"
|
|
||||||
? inviter.corporateInformation?.companyInformation?.name || inviter.name
|
|
||||||
: inviter.name;
|
|
||||||
|
|
||||||
const decide = (decision: "accept" | "decline") => {
|
|
||||||
if (!confirm(`Are you sure you want to ${decision} this invite?`)) return;
|
|
||||||
|
|
||||||
setIsLoading(true);
|
|
||||||
axios
|
|
||||||
.get(`/api/invites/${decision}/${invite.id}`)
|
|
||||||
.then(() => {
|
|
||||||
toast.success(
|
|
||||||
`Successfully ${decision === "accept" ? "accepted" : "declined"} the invite!`,
|
|
||||||
{ toastId: "success" },
|
|
||||||
);
|
|
||||||
reloadInvites();
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
toast.success(`Something went wrong, please try again later!`, {
|
|
||||||
toastId: "error",
|
|
||||||
});
|
|
||||||
reloadInvites();
|
|
||||||
})
|
|
||||||
.finally(() => setIsLoading(false));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="border-mti-gray-anti-flash flex min-w-[200px] flex-col gap-6 rounded-xl border p-4 text-black">
|
|
||||||
<span>Invited by {name}</span>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<button
|
|
||||||
onClick={() => decide("accept")}
|
|
||||||
disabled={isLoading}
|
|
||||||
className="bg-mti-green-ultralight hover:bg-mti-green-light w-24 rounded-lg p-2 px-4 transition duration-300 ease-in-out hover:text-white disabled:cursor-not-allowed"
|
|
||||||
>
|
|
||||||
{!isLoading && "Accept"}
|
|
||||||
{isLoading && (
|
|
||||||
<div className="flex items-center justify-center">
|
|
||||||
<BsArrowRepeat className="animate-spin text-white" size={25} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => decide("decline")}
|
|
||||||
disabled={isLoading}
|
|
||||||
className="bg-mti-red-ultralight hover:bg-mti-red-light w-24 rounded-lg p-2 px-4 transition duration-300 ease-in-out hover:text-white disabled:cursor-not-allowed"
|
|
||||||
>
|
|
||||||
{!isLoading && "Decline"}
|
|
||||||
{isLoading && (
|
|
||||||
<div className="flex items-center justify-center">
|
|
||||||
<BsArrowRepeat className="animate-spin text-white" size={25} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{corporateUserToShow && (
|
{corporateUserToShow && (
|
||||||
@@ -356,7 +292,12 @@ export default function StudentDashboard({ user }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
<span className="text-mti-gray-taupe scrollbar-hide flex gap-8 overflow-x-scroll">
|
<span className="text-mti-gray-taupe scrollbar-hide flex gap-8 overflow-x-scroll">
|
||||||
{invites.map((invite) => (
|
{invites.map((invite) => (
|
||||||
<InviteCard key={invite.id} {...invite} />
|
<InviteCard
|
||||||
|
key={invite.id}
|
||||||
|
invite={invite}
|
||||||
|
users={users}
|
||||||
|
reload={reloadInvites}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ import clsx from "clsx";
|
|||||||
import { capitalize } from "lodash";
|
import { capitalize } from "lodash";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import getSymbolFromCurrency from "currency-symbol-map";
|
import getSymbolFromCurrency from "currency-symbol-map";
|
||||||
|
import useInvites from "@/hooks/useInvites";
|
||||||
|
import { BsArrowRepeat } from "react-icons/bs";
|
||||||
|
import InviteCard from "@/components/Medium/InviteCard";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
@@ -17,12 +21,24 @@ interface Props {
|
|||||||
reload: () => void;
|
reload: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PaymentDue({user, hasExpired = false, clientID, reload}: Props) {
|
export default function PaymentDue({
|
||||||
|
user,
|
||||||
|
hasExpired = false,
|
||||||
|
clientID,
|
||||||
|
reload,
|
||||||
|
}: Props) {
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
const { packages } = usePackages();
|
const { packages } = usePackages();
|
||||||
const { users } = useUsers();
|
const { users } = useUsers();
|
||||||
const { groups } = useGroups();
|
const { groups } = useGroups();
|
||||||
|
const {
|
||||||
|
invites,
|
||||||
|
isLoading: isInvitesLoading,
|
||||||
|
reload: reloadInvites,
|
||||||
|
} = useInvites({ to: user.id });
|
||||||
|
|
||||||
const isIndividual = () => {
|
const isIndividual = () => {
|
||||||
if (user?.type === "developer") return true;
|
if (user?.type === "developer") return true;
|
||||||
@@ -31,42 +47,99 @@ export default function PaymentDue({user, hasExpired = false, clientID, reload}:
|
|||||||
|
|
||||||
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);
|
const userGroupsAdminTypes = userGroups
|
||||||
|
.map((g) => users?.find((u) => u.id === g.admin)?.type)
|
||||||
|
.filter((t) => !!t);
|
||||||
return userGroupsAdminTypes.every((t) => t !== "corporate");
|
return userGroupsAdminTypes.every((t) => t !== "corporate");
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="w-screen h-screen absolute top-0 left-0 overflow-hidden z-[999] bg-black/60">
|
<div className="absolute left-0 top-0 z-[999] h-screen w-screen overflow-hidden 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">
|
<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("loading loading-infinity w-48")} />
|
||||||
<span className={clsx("font-bold text-2xl")}>Completing your payment...</span>
|
<span className={clsx("text-2xl font-bold")}>
|
||||||
|
Completing your payment...
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{user ? (
|
{user ? (
|
||||||
<Layout user={user} navDisabled={hasExpired}>
|
<Layout user={user} navDisabled={hasExpired}>
|
||||||
<div className="flex flex-col items-center justify-center text-center w-full gap-4">
|
{invites.length > 0 && (
|
||||||
{hasExpired && <span className="font-bold text-lg">You do not have time credits for your account type!</span>}
|
<section className="flex flex-col gap-1 md:gap-3">
|
||||||
{isIndividual() && (
|
<div className="flex items-center gap-4">
|
||||||
<div className="flex flex-col items-center w-full overflow-x-scroll scrollbar-hide gap-12">
|
<div
|
||||||
<span className="max-w-lg">
|
onClick={reloadInvites}
|
||||||
To add to your use of EnCoach, please purchase one of the time packages available below:
|
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>
|
</span>
|
||||||
<div className="w-full flex flex-wrap justify-center gap-8">
|
<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) => (
|
{packages.map((p) => (
|
||||||
<div key={p.id} className={clsx("p-4 bg-white rounded-xl flex flex-col gap-6 items-start")}>
|
<div
|
||||||
<div className="flex flex-col items-start mb-2">
|
key={p.id}
|
||||||
<img src="/logo_title.png" alt="EnCoach's Logo" className="w-32" />
|
className={clsx(
|
||||||
<span className="font-semibold text-xl">
|
"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}{" "}
|
EnCoach - {p.duration}{" "}
|
||||||
{capitalize(
|
{capitalize(
|
||||||
p.duration === 1 ? p.duration_unit.slice(0, p.duration_unit.length - 1) : p.duration_unit,
|
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 w-full flex-col items-start gap-2">
|
||||||
<span className="text-2xl">
|
<span className="text-2xl">
|
||||||
{p.price}
|
{p.price}
|
||||||
{getSymbolFromCurrency(p.currency)}
|
{getSymbolFromCurrency(p.currency)}
|
||||||
@@ -81,12 +154,16 @@ export default function PaymentDue({user, hasExpired = false, clientID, reload}:
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-1 items-start">
|
<div className="flex flex-col items-start gap-1">
|
||||||
<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>- Train your abilities for the IELTS exam</li>
|
||||||
<li>- Gain insights into your weaknesses and strengths</li>
|
<li>
|
||||||
<li>- Allow yourself to correctly prepare for the exam</li>
|
- Gain insights into your weaknesses and strengths
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
- Allow yourself to correctly prepare for the exam
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -94,20 +171,36 @@ export default function PaymentDue({user, hasExpired = false, clientID, reload}:
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!isIndividual() && user.type === "corporate" && user?.corporateInformation.payment && (
|
{!isIndividual() &&
|
||||||
|
user.type === "corporate" &&
|
||||||
|
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">
|
||||||
To add to your use of EnCoach and that of your students and teachers, please pay your designated package below:
|
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>
|
</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} Months</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-2 items-start w-full">
|
<div className="flex w-full flex-col items-start gap-2">
|
||||||
<span className="text-2xl">
|
<span className="text-2xl">
|
||||||
{user.corporateInformation.payment.value}
|
{user.corporateInformation.payment.value}
|
||||||
{getSymbolFromCurrency(user.corporateInformation.payment.currency)}
|
{getSymbolFromCurrency(
|
||||||
|
user.corporateInformation.payment.currency,
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
<PayPalPayment
|
<PayPalPayment
|
||||||
key={clientID}
|
key={clientID}
|
||||||
@@ -123,15 +216,22 @@ export default function PaymentDue({user, hasExpired = false, clientID, reload}:
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-1 items-start">
|
<div className="flex flex-col items-start gap-1">
|
||||||
<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
|
- Allow a total of{" "}
|
||||||
use EnCoach
|
{
|
||||||
|
user.corporateInformation.companyInformation
|
||||||
|
.userAmount
|
||||||
|
}{" "}
|
||||||
|
students and teachers to 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>
|
||||||
<li>- Allow them to correctly prepare for the exam</li>
|
<li>- Allow them to correctly prepare for the exam</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -141,22 +241,27 @@ export default function PaymentDue({user, hasExpired = false, clientID, reload}:
|
|||||||
{!isIndividual() && user.type !== "corporate" && (
|
{!isIndividual() && user.type !== "corporate" && (
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<span className="max-w-lg">
|
<span className="max-w-lg">
|
||||||
You are not the person in charge of your time credits, please contact your administrator about this situation.
|
You are not the person in charge of your time credits, please
|
||||||
|
contact your administrator about this situation.
|
||||||
</span>
|
</span>
|
||||||
<span className="max-w-lg">
|
<span className="max-w-lg">
|
||||||
If you believe this to be a mistake, please contact the platform's administration, thank you for your
|
If you believe this to be a mistake, please contact the
|
||||||
patience.
|
platform's administration, thank you for your patience.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!isIndividual() && user.type === "corporate" && !user.corporateInformation.payment && (
|
{!isIndividual() &&
|
||||||
|
user.type === "corporate" &&
|
||||||
|
!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
|
An admin nor your agent have yet set the price intended to
|
||||||
desire and your expected monthly duration.
|
your requirements in terms of the amount of users you desire
|
||||||
|
and your expected monthly duration.
|
||||||
</span>
|
</span>
|
||||||
<span className="max-w-lg">
|
<span className="max-w-lg">
|
||||||
Please try again later or contact your agent or an admin, thank you for your patience.
|
Please try again later or contact your agent or an admin,
|
||||||
|
thank you for your patience.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { Invite } from "@/interfaces/invite";
|
|||||||
import { Group, User } from "@/interfaces/user";
|
import { Group, User } from "@/interfaces/user";
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
import { sendEmail } from "@/email";
|
import { sendEmail } from "@/email";
|
||||||
|
import { updateExpiryDateOnGroup } from "@/utils/groups.be";
|
||||||
|
|
||||||
const db = getFirestore(app);
|
const db = getFirestore(app);
|
||||||
|
|
||||||
@@ -48,6 +49,8 @@ async function get(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
const invitedByRef = await getDoc(doc(db, "users", invite.from));
|
const invitedByRef = await getDoc(doc(db, "users", invite.from));
|
||||||
if (!invitedByRef.exists()) return res.status(404).json({ ok: false });
|
if (!invitedByRef.exists()) return res.status(404).json({ ok: false });
|
||||||
|
|
||||||
|
await updateExpiryDateOnGroup(invite.to, invite.from);
|
||||||
|
|
||||||
const invitedBy = { ...invitedByRef.data(), id: invitedByRef.id } as User;
|
const invitedBy = { ...invitedByRef.data(), id: invitedByRef.id } as User;
|
||||||
const invitedByGroupsRef = await getDocs(
|
const invitedByGroupsRef = await getDocs(
|
||||||
query(collection(db, "groups"), where("admin", "==", invitedBy.id)),
|
query(collection(db, "groups"), where("admin", "==", invitedBy.id)),
|
||||||
|
|||||||
@@ -33,8 +33,12 @@ export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
|||||||
};
|
};
|
||||||
}, sessionOptions);
|
}, sessionOptions);
|
||||||
|
|
||||||
export default function Home({envVariables}: {envVariables: {[key: string]: string}}) {
|
export default function Home({
|
||||||
const {user, mutateUser} = useUser({redirectTo: "/login"});
|
envVariables,
|
||||||
|
}: {
|
||||||
|
envVariables: { [key: string]: string };
|
||||||
|
}) {
|
||||||
|
const { user } = useUser({ redirectTo: "/login" });
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user