Added the ability for Corporate accounts to register without codes

This commit is contained in:
Tiago Ribeiro
2023-10-29 14:38:46 +00:00
parent 6e31a05f21
commit a20b980adb
9 changed files with 98 additions and 23 deletions

View File

@@ -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} />
))}

View File

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

View File

@@ -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" />

View File

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

View File

@@ -43,6 +43,7 @@ export default function RegisterIndividual({queryCode, isLoading, setIsLoading,
name,
email,
password,
type: "individual",
code,
profilePicture: "/defaultAvatar.png",
})

View File

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

View File

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

View File

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

View File

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