New feature on the account creation:
It automatically stores who created the code and adds the registered user to a group administrated by that creator
This commit is contained in:
@@ -6,11 +6,12 @@ interface Props {
|
|||||||
label?: string;
|
label?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
|
disabled?: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Input({type, label, placeholder, name, required = false, defaultValue, onChange}: Props) {
|
export default function Input({type, label, placeholder, name, required = false, defaultValue, disabled = false, onChange}: Props) {
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
|
||||||
if (type === "password") {
|
if (type === "password") {
|
||||||
@@ -53,9 +54,10 @@ export default function Input({type, label, placeholder, name, required = false,
|
|||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
name={name}
|
name={name}
|
||||||
|
disabled={disabled}
|
||||||
onChange={(e) => onChange(e.target.value)}
|
onChange={(e) => onChange(e.target.value)}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
className="px-8 py-6 text-sm font-normal placeholder:text-mti-gray-cool bg-white rounded-full border border-mti-gray-platinum focus:outline-none"
|
className="px-8 py-6 text-sm font-normal placeholder:text-mti-gray-cool disabled:bg-mti-gray-platinum/40 disabled:text-mti-gray-dim disabled:cursor-not-allowed bg-white rounded-full border border-mti-gray-platinum focus:outline-none"
|
||||||
required={required}
|
required={required}
|
||||||
defaultValue={defaultValue}
|
defaultValue={defaultValue}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export interface Group {
|
|||||||
name: string;
|
name: string;
|
||||||
participants: string[];
|
participants: string[];
|
||||||
id: string;
|
id: string;
|
||||||
|
disableEditing?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Type = "student" | "teacher" | "admin" | "owner" | "developer";
|
export type Type = "student" | "teacher" | "admin" | "owner" | "developer";
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ const CreatePanel = ({user, users, group, onCreate}: CreateDialogProps) => {
|
|||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-12 mt-4 w-full px-4 py-2">
|
<div className="flex flex-col gap-12 mt-4 w-full px-4 py-2">
|
||||||
<div className="flex flex-col gap-8">
|
<div className="flex flex-col gap-8">
|
||||||
<Input name="name" type="text" label="Name" defaultValue={name} onChange={setName} required />
|
<Input name="name" type="text" label="Name" defaultValue={name} onChange={setName} required disabled={group?.disableEditing} />
|
||||||
<div className="flex flex-col gap-3 w-full">
|
<div className="flex flex-col gap-3 w-full">
|
||||||
<label className="font-normal text-base text-mti-gray-dim">Participants</label>
|
<label className="font-normal text-base text-mti-gray-dim">Participants</label>
|
||||||
<div className="flex gap-8 w-full">
|
<div className="flex gap-8 w-full">
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {sessionOptions} from "@/lib/session";
|
|||||||
import {withIronSessionApiRoute} from "iron-session/next";
|
import {withIronSessionApiRoute} from "iron-session/next";
|
||||||
import {getFirestore, doc, setDoc, query, collection, where, getDocs} from "firebase/firestore";
|
import {getFirestore, doc, setDoc, query, collection, where, getDocs} from "firebase/firestore";
|
||||||
import {DemographicInformation, Type} from "@/interfaces/user";
|
import {DemographicInformation, Type} from "@/interfaces/user";
|
||||||
|
import {addUserToGroupOnCreation} from "@/utils/registration";
|
||||||
|
|
||||||
const auth = getAuth(app);
|
const auth = getAuth(app);
|
||||||
const db = getFirestore(app);
|
const db = getFirestore(app);
|
||||||
@@ -36,7 +37,7 @@ async function login(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const codeData = codeDocs[0].data() as {code: string; type: Type};
|
const codeData = codeDocs[0].data() as {code: string; type: Type; creator: string};
|
||||||
|
|
||||||
createUserWithEmailAndPassword(auth, email, password)
|
createUserWithEmailAndPassword(auth, email, password)
|
||||||
.then(async (userCredentials) => {
|
.then(async (userCredentials) => {
|
||||||
@@ -55,6 +56,7 @@ async function login(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
|
|
||||||
await setDoc(doc(db, "users", userId), user);
|
await setDoc(doc(db, "users", userId), user);
|
||||||
await setDoc(codeDocs[0].ref, {userId: userId}, {merge: true});
|
await setDoc(codeDocs[0].ref, {userId: userId}, {merge: true});
|
||||||
|
await addUserToGroupOnCreation(userId, codeData.type, codeData.creator);
|
||||||
|
|
||||||
req.session.user = {...user, id: userId};
|
req.session.user = {...user, id: userId};
|
||||||
await req.session.save();
|
await req.session.save();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {PERMISSIONS} from "@/constants/userPermissions";
|
|||||||
import {app, adminApp} from "@/firebase";
|
import {app, adminApp} from "@/firebase";
|
||||||
import {User} from "@/interfaces/user";
|
import {User} from "@/interfaces/user";
|
||||||
import {sessionOptions} from "@/lib/session";
|
import {sessionOptions} from "@/lib/session";
|
||||||
import {collection, deleteDoc, doc, getDoc, getDocs, getFirestore, query, where} from "firebase/firestore";
|
import {collection, deleteDoc, doc, getDoc, getDocs, getFirestore, query, setDoc, where} from "firebase/firestore";
|
||||||
import {getAuth} from "firebase-admin/auth";
|
import {getAuth} from "firebase-admin/auth";
|
||||||
import {withIronSessionApiRoute} from "iron-session/next";
|
import {withIronSessionApiRoute} from "iron-session/next";
|
||||||
import {NextApiRequest, NextApiResponse} from "next";
|
import {NextApiRequest, NextApiResponse} from "next";
|
||||||
@@ -49,18 +49,24 @@ async function del(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const userCodeDocs = await getDocs(query(collection(db, "codes"), where("userId", "==", id)));
|
||||||
|
const userParticipantGroup = await getDocs(query(collection(db, "groups"), where("participants", "array-contains", id)));
|
||||||
|
const userGroupAdminDocs = await getDocs(query(collection(db, "groups"), where("admin", "==", id)));
|
||||||
|
const userStatsDocs = await getDocs(query(collection(db, "stats"), where("user", "==", id)));
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
...userCodeDocs.docs.map(async (x) => await deleteDoc(x.ref)),
|
||||||
|
...userGroupAdminDocs.docs.map(async (x) => await deleteDoc(x.ref)),
|
||||||
|
...userStatsDocs.docs.map(async (x) => await deleteDoc(x.ref)),
|
||||||
|
...userParticipantGroup.docs.map(
|
||||||
|
async (x) => await setDoc(x.ref, {participants: x.data().participants.filter((y: string) => y !== id)}, {merge: true}),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
await auth.deleteUser(id);
|
await auth.deleteUser(id);
|
||||||
await deleteDoc(doc(db, "users", id));
|
await deleteDoc(doc(db, "users", id));
|
||||||
|
|
||||||
res.json({ok: true});
|
res.json({ok: true});
|
||||||
|
|
||||||
const statsQuery = query(collection(db, "stats"), where("user", "==", targetUser.id));
|
|
||||||
const statsSnapshot = await getDocs(statsQuery);
|
|
||||||
await Promise.all(
|
|
||||||
statsSnapshot.docs.map(async (doc) => {
|
|
||||||
return await deleteDoc(doc.ref);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function get(req: NextApiRequest, res: NextApiResponse) {
|
async function get(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
|||||||
31
src/utils/registration.ts
Normal file
31
src/utils/registration.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import {collection, doc, getDoc, getDocs, getFirestore, query, setDoc, where} from "firebase/firestore";
|
||||||
|
import {app} from "@/firebase";
|
||||||
|
import {Group, Type, User} from "@/interfaces/user";
|
||||||
|
import {uuidv4} from "@firebase/util";
|
||||||
|
|
||||||
|
const db = getFirestore(app);
|
||||||
|
|
||||||
|
export const addUserToGroupOnCreation = async (userId: string, type: Type, creatorId: string) => {
|
||||||
|
const creatorDoc = await getDoc(doc(db, "users", creatorId));
|
||||||
|
if (!creatorDoc.exists()) return false;
|
||||||
|
|
||||||
|
const creator = {...creatorDoc.data(), id: creatorDoc.id} as User;
|
||||||
|
|
||||||
|
const creatorGroupsDocs = await getDocs(query(collection(db, "groups"), where("admin", "==", creator.id)));
|
||||||
|
const typeGroup = creatorGroupsDocs.docs.find((x) => (x.data() as Group).name === (type === "student" ? "Students" : "Teachers"));
|
||||||
|
|
||||||
|
if (typeGroup && typeGroup.exists()) {
|
||||||
|
await setDoc(typeGroup.ref, {participants: [...typeGroup.data().participants, userId]}, {merge: true});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupId = uuidv4();
|
||||||
|
await setDoc(doc(db, "groups", groupId), {
|
||||||
|
admin: creatorId,
|
||||||
|
name: type === "student" ? "Students" : "Teachers",
|
||||||
|
id: groupId,
|
||||||
|
participants: [userId],
|
||||||
|
disableEditing: true,
|
||||||
|
} as Group);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user