diff --git a/src/interfaces/user.ts b/src/interfaces/user.ts
index ddda1ccb..c704e4b7 100644
--- a/src/interfaces/user.ts
+++ b/src/interfaces/user.ts
@@ -1,189 +1,161 @@
-import { Module } from ".";
-import { InstructorGender } from "./exam";
-import { PermissionType } from "./permissions";
+import {Module} from ".";
+import {InstructorGender} from "./exam";
+import {PermissionType} from "./permissions";
-export type User =
- | StudentUser
- | TeacherUser
- | CorporateUser
- | AgentUser
- | AdminUser
- | DeveloperUser
- | MasterCorporateUser;
+export type User = StudentUser | TeacherUser | CorporateUser | AgentUser | AdminUser | DeveloperUser | MasterCorporateUser;
export type UserStatus = "active" | "disabled" | "paymentDue";
export interface BasicUser {
- email: string;
- name: string;
- profilePicture: string;
- id: string;
- isFirstLogin: boolean;
- focus: "academic" | "general";
- levels: { [key in Module]: number };
- desiredLevels: { [key in Module]: number };
- type: Type;
- bio: string;
- isVerified: boolean;
- subscriptionExpirationDate?: null | Date;
- registrationDate?: Date;
- status: UserStatus;
- permissions: PermissionType[],
+ email: string;
+ name: string;
+ profilePicture: string;
+ id: string;
+ isFirstLogin: boolean;
+ focus: "academic" | "general";
+ levels: {[key in Module]: number};
+ desiredLevels: {[key in Module]: number};
+ type: Type;
+ bio: string;
+ isVerified: boolean;
+ subscriptionExpirationDate?: null | Date;
+ registrationDate?: Date;
+ status: UserStatus;
+ permissions: PermissionType[];
+ lastLogin?: Date;
}
export interface StudentUser extends BasicUser {
- type: "student";
- preferredGender?: InstructorGender;
- demographicInformation?: DemographicInformation;
- preferredTopics?: string[];
+ type: "student";
+ preferredGender?: InstructorGender;
+ demographicInformation?: DemographicInformation;
+ preferredTopics?: string[];
}
export interface TeacherUser extends BasicUser {
- type: "teacher";
- demographicInformation?: DemographicInformation;
+ type: "teacher";
+ demographicInformation?: DemographicInformation;
}
export interface CorporateUser extends BasicUser {
- type: "corporate";
- corporateInformation: CorporateInformation;
- demographicInformation?: DemographicCorporateInformation;
+ type: "corporate";
+ corporateInformation: CorporateInformation;
+ demographicInformation?: DemographicCorporateInformation;
}
export interface MasterCorporateUser extends BasicUser {
- type: "mastercorporate";
- corporateInformation: CorporateInformation;
- demographicInformation?: DemographicCorporateInformation;
+ type: "mastercorporate";
+ corporateInformation: CorporateInformation;
+ demographicInformation?: DemographicCorporateInformation;
}
export interface AgentUser extends BasicUser {
- type: "agent";
- agentInformation: AgentInformation;
- demographicInformation?: DemographicInformation;
+ type: "agent";
+ agentInformation: AgentInformation;
+ demographicInformation?: DemographicInformation;
}
export interface AdminUser extends BasicUser {
- type: "admin";
- demographicInformation?: DemographicInformation;
+ type: "admin";
+ demographicInformation?: DemographicInformation;
}
export interface DeveloperUser extends BasicUser {
- type: "developer";
- preferredGender?: InstructorGender;
- demographicInformation?: DemographicInformation;
- preferredTopics?: string[];
+ type: "developer";
+ preferredGender?: InstructorGender;
+ demographicInformation?: DemographicInformation;
+ preferredTopics?: string[];
}
export interface CorporateInformation {
- companyInformation: CompanyInformation;
- monthlyDuration: number;
- payment?: {
- value: number;
- currency: string;
- commission: number;
- };
- referralAgent?: string;
+ companyInformation: CompanyInformation;
+ monthlyDuration: number;
+ payment?: {
+ value: number;
+ currency: string;
+ commission: number;
+ };
+ referralAgent?: string;
}
export interface AgentInformation {
- companyName: string;
- commercialRegistration: string;
- companyArabName?: string;
+ companyName: string;
+ commercialRegistration: string;
+ companyArabName?: string;
}
export interface CompanyInformation {
- name: string;
- userAmount: number;
+ name: string;
+ userAmount: number;
}
export interface DemographicInformation {
- country: string;
- phone: string;
- gender: Gender;
- employment: EmploymentStatus;
- passport_id?: string;
- timezone?: string;
+ country: string;
+ phone: string;
+ gender: Gender;
+ employment: EmploymentStatus;
+ passport_id?: string;
+ timezone?: string;
}
export interface DemographicCorporateInformation {
- country: string;
- phone: string;
- gender: Gender;
- position: string;
- timezone?: string;
+ country: string;
+ phone: string;
+ gender: Gender;
+ position: string;
+ timezone?: string;
}
export type Gender = "male" | "female" | "other";
-export type EmploymentStatus =
- | "employed"
- | "student"
- | "self-employed"
- | "unemployed"
- | "retired"
- | "other";
-export const EMPLOYMENT_STATUS: { status: EmploymentStatus; label: string }[] =
- [
- { 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 type EmploymentStatus = "employed" | "student" | "self-employed" | "unemployed" | "retired" | "other";
+export const EMPLOYMENT_STATUS: {status: EmploymentStatus; label: string}[] = [
+ {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 {
- id: string;
- user: string;
- exam: string;
- exercise: string;
- session: string;
- date: number;
- module: Module;
- solutions: any[];
- type: string;
- timeSpent?: number;
- inactivity?: number;
- assignment?: string;
- score: {
- correct: number;
- total: number;
- missing: number;
- };
- isDisabled?: boolean;
+ id: string;
+ user: string;
+ exam: string;
+ exercise: string;
+ session: string;
+ date: number;
+ module: Module;
+ solutions: any[];
+ type: string;
+ timeSpent?: number;
+ inactivity?: number;
+ assignment?: string;
+ score: {
+ correct: number;
+ total: number;
+ missing: number;
+ };
+ isDisabled?: boolean;
}
export interface Group {
- admin: string;
- name: string;
- participants: string[];
- id: string;
- disableEditing?: boolean;
+ admin: string;
+ name: string;
+ participants: string[];
+ id: string;
+ disableEditing?: boolean;
}
export interface Code {
- code: string;
- creator: string;
- expiryDate: Date;
- type: Type;
- creationDate?: string;
- userId?: string;
- email?: string;
- name?: string;
- passport_id?: string;
+ code: string;
+ creator: string;
+ expiryDate: Date;
+ type: Type;
+ creationDate?: string;
+ userId?: string;
+ email?: string;
+ name?: string;
+ passport_id?: string;
}
-export type Type =
- | "student"
- | "teacher"
- | "corporate"
- | "admin"
- | "developer"
- | "agent"
- | "mastercorporate";
-export const userTypes: Type[] = [
- "student",
- "teacher",
- "corporate",
- "admin",
- "developer",
- "agent",
- "mastercorporate",
-];
+export type Type = "student" | "teacher" | "corporate" | "admin" | "developer" | "agent" | "mastercorporate";
+export const userTypes: Type[] = ["student", "teacher", "corporate", "admin", "developer", "agent", "mastercorporate"];
diff --git a/src/pages/(admin)/Lists/UserList.tsx b/src/pages/(admin)/Lists/UserList.tsx
index cd939522..fb66d7ae 100644
--- a/src/pages/(admin)/Lists/UserList.tsx
+++ b/src/pages/(admin)/Lists/UserList.tsx
@@ -279,10 +279,10 @@ export default function UserList({
) as any,
cell: (info) =>
info.getValue()
- ? `${countryCodes.findOne("countryCode" as any, info.getValue()).flag} ${
- countries[info.getValue() as unknown as keyof TCountries].name
- } (+${countryCodes.findOne("countryCode" as any, info.getValue()).countryCallingCode})`
- : "Not available",
+ ? `${countryCodes.findOne("countryCode" as any, info.getValue())?.flag} ${
+ countries[info.getValue() as unknown as keyof TCountries]?.name
+ } (+${countryCodes.findOne("countryCode" as any, info.getValue())?.countryCallingCode})`
+ : "N/A",
}),
columnHelper.accessor("demographicInformation.phone", {
header: (
@@ -291,7 +291,7 @@ export default function UserList({
) as any,
- cell: (info) => info.getValue() || "Not available",
+ cell: (info) => info.getValue() || "N/A",
enableSorting: true,
}),
columnHelper.accessor(
@@ -301,14 +301,23 @@ export default function UserList({
id: "employment",
header: (
) 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,
},
),
+ columnHelper.accessor("lastLogin", {
+ header: (
+
+ ) as any,
+ cell: (info) => (!!info.getValue() ? moment(info.getValue()).format("YYYY-MM-DD HH:mm") : "N/A"),
+ }),
columnHelper.accessor("demographicInformation.gender", {
header: (
) as any,
- cell: (info) => capitalize(info.getValue()) || "Not available",
+ cell: (info) => capitalize(info.getValue()) || "N/A",
enableSorting: true,
}),
{
@@ -379,7 +388,7 @@ export default function UserList({
columnHelper.accessor("corporateInformation.companyInformation.name", {
header: (
) as any,
@@ -388,7 +397,7 @@ export default function UserList({
columnHelper.accessor("subscriptionExpirationDate", {
header: (
) as any,
@@ -401,7 +410,7 @@ export default function UserList({
columnHelper.accessor("isVerified", {
header: (
) as any,
@@ -464,6 +473,15 @@ export default function UserList({
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 (!a.demographicInformation?.country && b.demographicInformation?.country) return sorter === "country" ? -1 : 1;
if (a.demographicInformation?.country && !b.demographicInformation?.country) return sorter === "country" ? 1 : -1;
diff --git a/src/pages/api/user.ts b/src/pages/api/user.ts
index 6d9c176b..6240aa18 100644
--- a/src/pages/api/user.ts
+++ b/src/pages/api/user.ts
@@ -107,10 +107,12 @@ async function get(req: NextApiRequest, res: NextApiResponse) {
}
const user = docUser.data() as User;
+ await setDoc(docUser.ref, {lastLogin: new Date().toISOString()}, {merge: true});
req.session.user = {
...user,
id: req.session.user.id,
+ lastLogin: new Date(),
};
await req.session.save();