Added the ability for Corporate accounts to register without codes
This commit is contained in:
@@ -111,7 +111,7 @@ export default function OwnerDashboard({user}: Props) {
|
||||
);
|
||||
|
||||
const InactiveStudentsList = () => {
|
||||
const filter = (x: User) => x.type === "student" && (x.isDisabled || moment().isAfter(x.subscriptionExpirationDate));
|
||||
const filter = (x: User) => x.type === "student" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate));
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -131,7 +131,7 @@ export default function OwnerDashboard({user}: Props) {
|
||||
};
|
||||
|
||||
const InactiveCorporateList = () => {
|
||||
const filter = (x: User) => x.type === "corporate" && (x.isDisabled || moment().isAfter(x.subscriptionExpirationDate));
|
||||
const filter = (x: User) => x.type === "corporate" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate));
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -196,7 +196,11 @@ export default function OwnerDashboard({user}: Props) {
|
||||
<span className="flex flex-col gap-1 items-center text-xl">
|
||||
<span className="text-lg">Inactive Students</span>
|
||||
<span className="font-semibold text-mti-rose">
|
||||
{users.filter((x) => x.type === "student" && (x.isDisabled || moment().isAfter(x.subscriptionExpirationDate))).length}
|
||||
{
|
||||
users.filter(
|
||||
(x) => x.type === "student" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)),
|
||||
).length
|
||||
}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -207,7 +211,11 @@ export default function OwnerDashboard({user}: Props) {
|
||||
<span className="flex flex-col gap-1 items-center text-xl">
|
||||
<span className="text-lg text-center">Inactive Corporate</span>
|
||||
<span className="font-semibold text-mti-rose">
|
||||
{users.filter((x) => x.type === "corporate" && (x.isDisabled || moment().isAfter(x.subscriptionExpirationDate))).length}
|
||||
{
|
||||
users.filter(
|
||||
(x) => x.type === "corporate" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)),
|
||||
).length
|
||||
}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -219,7 +227,7 @@ export default function OwnerDashboard({user}: Props) {
|
||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||
{users
|
||||
.filter((x) => x.type === "student")
|
||||
.sort((a, b) => dateSorter(a, b, "asc", "registrationDate"))
|
||||
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
|
||||
.map((x) => (
|
||||
<UserDisplay key={x.id} {...x} />
|
||||
))}
|
||||
@@ -230,17 +238,17 @@ export default function OwnerDashboard({user}: Props) {
|
||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||
{users
|
||||
.filter((x) => x.type === "corporate")
|
||||
.sort((a, b) => dateSorter(a, b, "asc", "registrationDate"))
|
||||
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
|
||||
.map((x) => (
|
||||
<UserDisplay key={x.id} {...x} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||
<span className="p-4">Disabled Corporate</span>
|
||||
<span className="p-4">Unpaid Corporate</span>
|
||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||
{users
|
||||
.filter((x) => x.type === "corporate" && x.isDisabled)
|
||||
.filter((x) => x.type === "corporate" && x.status === "paymentDue")
|
||||
.map((x) => (
|
||||
<UserDisplay key={x.id} {...x} />
|
||||
))}
|
||||
|
||||
@@ -16,8 +16,8 @@ export interface User {
|
||||
demographicInformation?: DemographicInformation;
|
||||
corporateInformation?: CorporateInformation;
|
||||
subscriptionExpirationDate?: null | Date;
|
||||
isDisabled?: boolean;
|
||||
registrationDate?: Date;
|
||||
status: "active" | "disabled" | "paymentDue";
|
||||
}
|
||||
|
||||
export interface CorporateInformation {
|
||||
|
||||
@@ -85,7 +85,7 @@ export default function UserList({user, filter}: {user: User; filter?: (user: Us
|
||||
const toggleDisableAccount = (user: User) => {
|
||||
if (
|
||||
!confirm(
|
||||
`Are you sure you want to ${user.isDisabled ? "enable" : "disable"} ${
|
||||
`Are you sure you want to ${user.status === "disabled" ? "enable" : "disable"} ${
|
||||
user.name
|
||||
}'s account? This change is usually related to their payment state.`,
|
||||
)
|
||||
@@ -93,9 +93,12 @@ export default function UserList({user, filter}: {user: User; filter?: (user: Us
|
||||
return;
|
||||
|
||||
axios
|
||||
.post<{user?: User; ok?: boolean}>(`/api/users/update?id=${user.id}`, {...user, isDisabled: !user.isDisabled})
|
||||
.post<{user?: User; ok?: boolean}>(`/api/users/update?id=${user.id}`, {
|
||||
...user,
|
||||
status: user.status === "disabled" ? "active" : "disabled",
|
||||
})
|
||||
.then(() => {
|
||||
toast.success(`User ${user.isDisabled ? "enabled" : "disabled"} successfully!`);
|
||||
toast.success(`User ${user.status === "disabled" ? "enabled" : "disabled"} successfully!`);
|
||||
reload();
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -166,10 +169,10 @@ export default function UserList({user, filter}: {user: User; filter?: (user: Us
|
||||
)}
|
||||
{PERMISSIONS.updateUser[row.original.type].includes(user.type) && (
|
||||
<div
|
||||
data-tip={row.original.isDisabled ? "Enable User" : "Disable User"}
|
||||
data-tip={row.original.status === "disabled" ? "Enable User" : "Disable User"}
|
||||
className="cursor-pointer tooltip"
|
||||
onClick={() => toggleDisableAccount(row.original)}>
|
||||
{row.original.isDisabled ? (
|
||||
{row.original.status === "disabled" ? (
|
||||
<BsCheckCircle className="hover:text-mti-purple-light transition ease-in-out duration-300" />
|
||||
) : (
|
||||
<BsFillExclamationOctagonFill className="hover:text-mti-purple-light transition ease-in-out duration-300" />
|
||||
|
||||
@@ -47,6 +47,13 @@ export default function RegisterCorporate({isLoading, setIsLoading, mutateUser,
|
||||
password,
|
||||
type: "corporate",
|
||||
profilePicture: "/defaultAvatar.png",
|
||||
corporateInformation: {
|
||||
companyInformation: {
|
||||
name: companyName,
|
||||
userAmount: companyUsers,
|
||||
},
|
||||
allowedUserAmount: companyUsers,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
mutateUser(response.data.user).then(() => sendEmailVerification(setIsLoading, onSuccess, onError));
|
||||
@@ -114,7 +121,9 @@ export default function RegisterCorporate({isLoading, setIsLoading, mutateUser,
|
||||
<Button
|
||||
className="lg:mt-8 w-full"
|
||||
color="purple"
|
||||
disabled={isLoading || !email || !name || !password || !confirmPassword || password !== confirmPassword}>
|
||||
disabled={
|
||||
isLoading || !email || !name || !password || !confirmPassword || password !== confirmPassword || !companyName || companyUsers <= 0
|
||||
}>
|
||||
Create account
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
@@ -43,6 +43,7 @@ export default function RegisterIndividual({queryCode, isLoading, setIsLoading,
|
||||
name,
|
||||
email,
|
||||
password,
|
||||
type: "individual",
|
||||
code,
|
||||
profilePicture: "/defaultAvatar.png",
|
||||
})
|
||||
|
||||
@@ -4,13 +4,13 @@ import {app} from "@/firebase";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {getFirestore, doc, setDoc, query, collection, where, getDocs} from "firebase/firestore";
|
||||
import {DemographicInformation, Type} from "@/interfaces/user";
|
||||
import {CorporateInformation, DemographicInformation, Type} from "@/interfaces/user";
|
||||
import {addUserToGroupOnCreation} from "@/utils/registration";
|
||||
|
||||
const auth = getAuth(app);
|
||||
const db = getFirestore(app);
|
||||
|
||||
export default withIronSessionApiRoute(login, sessionOptions);
|
||||
export default withIronSessionApiRoute(register, sessionOptions);
|
||||
|
||||
const DEFAULT_DESIRED_LEVELS = {
|
||||
reading: 9,
|
||||
@@ -26,8 +26,21 @@ const DEFAULT_LEVELS = {
|
||||
speaking: 0,
|
||||
};
|
||||
|
||||
async function login(req: NextApiRequest, res: NextApiResponse) {
|
||||
const {email, password, code} = req.body as {email: string; password: string; code: string; demographicInformation: DemographicInformation};
|
||||
async function register(req: NextApiRequest, res: NextApiResponse) {
|
||||
const {type} = req.body as {
|
||||
type: "individual" | "corporate";
|
||||
};
|
||||
|
||||
if (type === "individual") return registerIndividual(req, res);
|
||||
if (type === "corporate") return registerCorporate(req, res);
|
||||
}
|
||||
|
||||
async function registerIndividual(req: NextApiRequest, res: NextApiResponse) {
|
||||
const {email, password, code} = req.body as {
|
||||
email: string;
|
||||
password: string;
|
||||
code?: string;
|
||||
};
|
||||
|
||||
const codeQuery = query(collection(db, "codes"), where("code", "==", code));
|
||||
const codeDocs = (await getDocs(codeQuery)).docs.filter((x) => !Object.keys(x.data()).includes("userId"));
|
||||
@@ -70,3 +83,41 @@ async function login(req: NextApiRequest, res: NextApiResponse) {
|
||||
res.status(401).json({error});
|
||||
});
|
||||
}
|
||||
|
||||
async function registerCorporate(req: NextApiRequest, res: NextApiResponse) {
|
||||
const {email, password} = req.body as {
|
||||
email: string;
|
||||
password: string;
|
||||
corporateInformation: CorporateInformation;
|
||||
};
|
||||
|
||||
createUserWithEmailAndPassword(auth, email, password)
|
||||
.then(async (userCredentials) => {
|
||||
const userId = userCredentials.user.uid;
|
||||
delete req.body.password;
|
||||
|
||||
const user = {
|
||||
...req.body,
|
||||
desiredLevels: DEFAULT_DESIRED_LEVELS,
|
||||
levels: DEFAULT_LEVELS,
|
||||
bio: "",
|
||||
isFirstLogin: false,
|
||||
focus: "academic",
|
||||
type: "corporate",
|
||||
subscriptionExpirationDate: null,
|
||||
status: "paymentDue",
|
||||
registrationDate: new Date().toISOString(),
|
||||
};
|
||||
|
||||
await setDoc(doc(db, "users", userId), user);
|
||||
|
||||
req.session.user = {...user, id: userId};
|
||||
await req.session.save();
|
||||
|
||||
res.status(200).json({user: {...user, id: userId}});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
res.status(401).json({error});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ async function sendVerification(req: NextApiRequest, res: NextApiResponse) {
|
||||
const short = new ShortUniqueId();
|
||||
|
||||
if (req.session.user) {
|
||||
console.log("ME HERE");
|
||||
|
||||
const transport = prepareMailer("verification");
|
||||
const mailOptions = prepareMailOptions(
|
||||
{
|
||||
@@ -25,7 +27,8 @@ async function sendVerification(req: NextApiRequest, res: NextApiResponse) {
|
||||
"verification",
|
||||
);
|
||||
|
||||
await transport.sendMail(mailOptions);
|
||||
const result = await transport.sendMail(mailOptions);
|
||||
console.log(result);
|
||||
|
||||
res.status(200).json({ok: true});
|
||||
return;
|
||||
|
||||
@@ -65,7 +65,7 @@ export default function Home() {
|
||||
return true;
|
||||
};
|
||||
|
||||
if (user && (user.isDisabled || checkIfUserExpired())) {
|
||||
if (user && (user.status === "disabled" || checkIfUserExpired())) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
@@ -79,7 +79,7 @@ export default function Home() {
|
||||
</Head>
|
||||
<Layout user={user} navDisabled>
|
||||
<div className="flex flex-col items-center justify-center text-center w-full gap-4">
|
||||
{user.isDisabled ? (
|
||||
{user.status === "disabled" ? (
|
||||
<>
|
||||
<span className="font-bold text-lg">Your account has been disabled!</span>
|
||||
<span>Please contact an administrator if you believe this to be a mistake.</span>
|
||||
|
||||
@@ -8,7 +8,7 @@ export const preventNavigation = (navDisabled: boolean, focusMode: boolean): boo
|
||||
};
|
||||
|
||||
export const shouldRedirectHome = (user: User) => {
|
||||
if (user.isDisabled) return true;
|
||||
if (user.status === "disabled") return true;
|
||||
if (user.isFirstLogin) return true;
|
||||
if (!user.demographicInformation) return true;
|
||||
if (user.subscriptionExpirationDate && moment(new Date()).isAfter(user.subscriptionExpirationDate)) return true;
|
||||
|
||||
Reference in New Issue
Block a user