Added a "last login" to the users

This commit is contained in:
Tiago Ribeiro
2024-08-15 23:55:08 +01:00
parent 38e48c90bb
commit 0a28c2bd41
3 changed files with 139 additions and 147 deletions

View File

@@ -1,189 +1,161 @@
import { Module } from "."; import {Module} from ".";
import { InstructorGender } from "./exam"; import {InstructorGender} from "./exam";
import { PermissionType } from "./permissions"; import {PermissionType} from "./permissions";
export type User = export type User = StudentUser | TeacherUser | CorporateUser | AgentUser | AdminUser | DeveloperUser | MasterCorporateUser;
| StudentUser
| TeacherUser
| CorporateUser
| AgentUser
| AdminUser
| DeveloperUser
| MasterCorporateUser;
export type UserStatus = "active" | "disabled" | "paymentDue"; export type UserStatus = "active" | "disabled" | "paymentDue";
export interface BasicUser { export interface BasicUser {
email: string; email: string;
name: string; name: string;
profilePicture: string; profilePicture: string;
id: string; id: string;
isFirstLogin: boolean; isFirstLogin: boolean;
focus: "academic" | "general"; focus: "academic" | "general";
levels: { [key in Module]: number }; levels: {[key in Module]: number};
desiredLevels: { [key in Module]: number }; desiredLevels: {[key in Module]: number};
type: Type; type: Type;
bio: string; bio: string;
isVerified: boolean; isVerified: boolean;
subscriptionExpirationDate?: null | Date; subscriptionExpirationDate?: null | Date;
registrationDate?: Date; registrationDate?: Date;
status: UserStatus; status: UserStatus;
permissions: PermissionType[], permissions: PermissionType[];
lastLogin?: Date;
} }
export interface StudentUser extends BasicUser { export interface StudentUser extends BasicUser {
type: "student"; type: "student";
preferredGender?: InstructorGender; preferredGender?: InstructorGender;
demographicInformation?: DemographicInformation; demographicInformation?: DemographicInformation;
preferredTopics?: string[]; preferredTopics?: string[];
} }
export interface TeacherUser extends BasicUser { export interface TeacherUser extends BasicUser {
type: "teacher"; type: "teacher";
demographicInformation?: DemographicInformation; demographicInformation?: DemographicInformation;
} }
export interface CorporateUser extends BasicUser { export interface CorporateUser extends BasicUser {
type: "corporate"; type: "corporate";
corporateInformation: CorporateInformation; corporateInformation: CorporateInformation;
demographicInformation?: DemographicCorporateInformation; demographicInformation?: DemographicCorporateInformation;
} }
export interface MasterCorporateUser extends BasicUser { export interface MasterCorporateUser extends BasicUser {
type: "mastercorporate"; type: "mastercorporate";
corporateInformation: CorporateInformation; corporateInformation: CorporateInformation;
demographicInformation?: DemographicCorporateInformation; demographicInformation?: DemographicCorporateInformation;
} }
export interface AgentUser extends BasicUser { export interface AgentUser extends BasicUser {
type: "agent"; type: "agent";
agentInformation: AgentInformation; agentInformation: AgentInformation;
demographicInformation?: DemographicInformation; demographicInformation?: DemographicInformation;
} }
export interface AdminUser extends BasicUser { export interface AdminUser extends BasicUser {
type: "admin"; type: "admin";
demographicInformation?: DemographicInformation; demographicInformation?: DemographicInformation;
} }
export interface DeveloperUser extends BasicUser { export interface DeveloperUser extends BasicUser {
type: "developer"; type: "developer";
preferredGender?: InstructorGender; preferredGender?: InstructorGender;
demographicInformation?: DemographicInformation; demographicInformation?: DemographicInformation;
preferredTopics?: string[]; preferredTopics?: string[];
} }
export interface CorporateInformation { export interface CorporateInformation {
companyInformation: CompanyInformation; companyInformation: CompanyInformation;
monthlyDuration: number; monthlyDuration: number;
payment?: { payment?: {
value: number; value: number;
currency: string; currency: string;
commission: number; commission: number;
}; };
referralAgent?: string; referralAgent?: string;
} }
export interface AgentInformation { export interface AgentInformation {
companyName: string; companyName: string;
commercialRegistration: string; commercialRegistration: string;
companyArabName?: string; companyArabName?: string;
} }
export interface CompanyInformation { export interface CompanyInformation {
name: string; name: string;
userAmount: number; userAmount: number;
} }
export interface DemographicInformation { export interface DemographicInformation {
country: string; country: string;
phone: string; phone: string;
gender: Gender; gender: Gender;
employment: EmploymentStatus; employment: EmploymentStatus;
passport_id?: string; passport_id?: string;
timezone?: string; timezone?: string;
} }
export interface DemographicCorporateInformation { export interface DemographicCorporateInformation {
country: string; country: string;
phone: string; phone: string;
gender: Gender; gender: Gender;
position: string; position: string;
timezone?: string; timezone?: string;
} }
export type Gender = "male" | "female" | "other"; export type Gender = "male" | "female" | "other";
export type EmploymentStatus = export type EmploymentStatus = "employed" | "student" | "self-employed" | "unemployed" | "retired" | "other";
| "employed" export const EMPLOYMENT_STATUS: {status: EmploymentStatus; label: string}[] = [
| "student" {status: "student", label: "Student"},
| "self-employed" {status: "employed", label: "Employed"},
| "unemployed" {status: "unemployed", label: "Unemployed"},
| "retired" {status: "self-employed", label: "Self-employed"},
| "other"; {status: "retired", label: "Retired"},
export const EMPLOYMENT_STATUS: { status: EmploymentStatus; label: string }[] = {status: "other", label: "Other"},
[ ];
{ status: "student", label: "Student" },
{ status: "employed", label: "Employed" },
{ status: "unemployed", label: "Unemployed" },
{ status: "self-employed", label: "Self-employed" },
{ status: "retired", label: "Retired" },
{ status: "other", label: "Other" },
];
export interface Stat { export interface Stat {
id: string; id: string;
user: string; user: string;
exam: string; exam: string;
exercise: string; exercise: string;
session: string; session: string;
date: number; date: number;
module: Module; module: Module;
solutions: any[]; solutions: any[];
type: string; type: string;
timeSpent?: number; timeSpent?: number;
inactivity?: number; inactivity?: number;
assignment?: string; assignment?: string;
score: { score: {
correct: number; correct: number;
total: number; total: number;
missing: number; missing: number;
}; };
isDisabled?: boolean; isDisabled?: boolean;
} }
export interface Group { export interface Group {
admin: string; admin: string;
name: string; name: string;
participants: string[]; participants: string[];
id: string; id: string;
disableEditing?: boolean; disableEditing?: boolean;
} }
export interface Code { export interface Code {
code: string; code: string;
creator: string; creator: string;
expiryDate: Date; expiryDate: Date;
type: Type; type: Type;
creationDate?: string; creationDate?: string;
userId?: string; userId?: string;
email?: string; email?: string;
name?: string; name?: string;
passport_id?: string; passport_id?: string;
} }
export type Type = export type Type = "student" | "teacher" | "corporate" | "admin" | "developer" | "agent" | "mastercorporate";
| "student" export const userTypes: Type[] = ["student", "teacher", "corporate", "admin", "developer", "agent", "mastercorporate"];
| "teacher"
| "corporate"
| "admin"
| "developer"
| "agent"
| "mastercorporate";
export const userTypes: Type[] = [
"student",
"teacher",
"corporate",
"admin",
"developer",
"agent",
"mastercorporate",
];

View File

@@ -279,10 +279,10 @@ export default function UserList({
) as any, ) as any,
cell: (info) => cell: (info) =>
info.getValue() info.getValue()
? `${countryCodes.findOne("countryCode" as any, info.getValue()).flag} ${ ? `${countryCodes.findOne("countryCode" as any, info.getValue())?.flag} ${
countries[info.getValue() as unknown as keyof TCountries].name countries[info.getValue() as unknown as keyof TCountries]?.name
} (+${countryCodes.findOne("countryCode" as any, info.getValue()).countryCallingCode})` } (+${countryCodes.findOne("countryCode" as any, info.getValue())?.countryCallingCode})`
: "Not available", : "N/A",
}), }),
columnHelper.accessor("demographicInformation.phone", { columnHelper.accessor("demographicInformation.phone", {
header: ( header: (
@@ -291,7 +291,7 @@ export default function UserList({
<SorterArrow name="phone" /> <SorterArrow name="phone" />
</button> </button>
) as any, ) as any,
cell: (info) => info.getValue() || "Not available", cell: (info) => info.getValue() || "N/A",
enableSorting: true, enableSorting: true,
}), }),
columnHelper.accessor( columnHelper.accessor(
@@ -301,14 +301,23 @@ export default function UserList({
id: "employment", id: "employment",
header: ( header: (
<button className="flex gap-2 items-center" onClick={() => setSorter((prev) => selectSorter(prev, "employment"))}> <button className="flex gap-2 items-center" onClick={() => setSorter((prev) => selectSorter(prev, "employment"))}>
<span>Employment/Position</span> <span>Employment</span>
<SorterArrow name="employment" /> <SorterArrow name="employment" />
</button> </button>
) as any, ) as any,
cell: (info) => (info.row.original.type === "corporate" ? info.getValue() : capitalize(info.getValue())) || "Not available", cell: (info) => (info.row.original.type === "corporate" ? info.getValue() : capitalize(info.getValue())) || "N/A",
enableSorting: true, enableSorting: true,
}, },
), ),
columnHelper.accessor("lastLogin", {
header: (
<button className="flex gap-2 items-center" onClick={() => setSorter((prev) => selectSorter(prev, "lastLogin"))}>
<span>Last Login</span>
<SorterArrow name="lastLogin" />
</button>
) as any,
cell: (info) => (!!info.getValue() ? moment(info.getValue()).format("YYYY-MM-DD HH:mm") : "N/A"),
}),
columnHelper.accessor("demographicInformation.gender", { columnHelper.accessor("demographicInformation.gender", {
header: ( header: (
<button className="flex gap-2 items-center" onClick={() => setSorter((prev) => selectSorter(prev, "gender"))}> <button className="flex gap-2 items-center" onClick={() => setSorter((prev) => selectSorter(prev, "gender"))}>
@@ -316,7 +325,7 @@ export default function UserList({
<SorterArrow name="gender" /> <SorterArrow name="gender" />
</button> </button>
) as any, ) as any,
cell: (info) => capitalize(info.getValue()) || "Not available", cell: (info) => capitalize(info.getValue()) || "N/A",
enableSorting: true, enableSorting: true,
}), }),
{ {
@@ -379,7 +388,7 @@ export default function UserList({
columnHelper.accessor("corporateInformation.companyInformation.name", { columnHelper.accessor("corporateInformation.companyInformation.name", {
header: ( header: (
<button className="flex gap-2 items-center" onClick={() => setSorter((prev) => selectSorter(prev, "companyName"))}> <button className="flex gap-2 items-center" onClick={() => setSorter((prev) => selectSorter(prev, "companyName"))}>
<span>Company Name</span> <span>Company</span>
<SorterArrow name="companyName" /> <SorterArrow name="companyName" />
</button> </button>
) as any, ) as any,
@@ -388,7 +397,7 @@ export default function UserList({
columnHelper.accessor("subscriptionExpirationDate", { columnHelper.accessor("subscriptionExpirationDate", {
header: ( header: (
<button className="flex gap-2 items-center" onClick={() => setSorter((prev) => selectSorter(prev, "expiryDate"))}> <button className="flex gap-2 items-center" onClick={() => setSorter((prev) => selectSorter(prev, "expiryDate"))}>
<span>Expiry Date</span> <span>Expiration</span>
<SorterArrow name="expiryDate" /> <SorterArrow name="expiryDate" />
</button> </button>
) as any, ) as any,
@@ -401,7 +410,7 @@ export default function UserList({
columnHelper.accessor("isVerified", { columnHelper.accessor("isVerified", {
header: ( header: (
<button className="flex gap-2 items-center" onClick={() => setSorter((prev) => selectSorter(prev, "verification"))}> <button className="flex gap-2 items-center" onClick={() => setSorter((prev) => selectSorter(prev, "verification"))}>
<span>Verification</span> <span>Verified</span>
<SorterArrow name="verification" /> <SorterArrow name="verification" />
</button> </button>
) as any, ) as any,
@@ -464,6 +473,15 @@ export default function UserList({
return 0; return 0;
} }
if (sorter === "lastLogin" || sorter === reverseString("lastLogin")) {
if (!a.lastLogin && b.lastLogin) return sorter === "lastLogin" ? -1 : 1;
if (a.lastLogin && !b.lastLogin) return sorter === "lastLogin" ? 1 : -1;
if (!a.lastLogin && !b.lastLogin) return 0;
if (moment(a.lastLogin).isAfter(b.lastLogin)) return sorter === "lastLogin" ? -1 : 1;
if (moment(b.lastLogin).isAfter(a.lastLogin)) return sorter === "lastLogin" ? 1 : -1;
return 0;
}
if (sorter === "country" || sorter === reverseString("country")) { if (sorter === "country" || sorter === reverseString("country")) {
if (!a.demographicInformation?.country && b.demographicInformation?.country) return sorter === "country" ? -1 : 1; if (!a.demographicInformation?.country && b.demographicInformation?.country) return sorter === "country" ? -1 : 1;
if (a.demographicInformation?.country && !b.demographicInformation?.country) return sorter === "country" ? 1 : -1; if (a.demographicInformation?.country && !b.demographicInformation?.country) return sorter === "country" ? 1 : -1;

View File

@@ -107,10 +107,12 @@ async function get(req: NextApiRequest, res: NextApiResponse) {
} }
const user = docUser.data() as User; const user = docUser.data() as User;
await setDoc(docUser.ref, {lastLogin: new Date().toISOString()}, {merge: true});
req.session.user = { req.session.user = {
...user, ...user,
id: req.session.user.id, id: req.session.user.id,
lastLogin: new Date(),
}; };
await req.session.save(); await req.session.save();