Merge branch 'develop' into faeture/payment-history
This commit is contained in:
@@ -35,9 +35,10 @@ interface Props {
|
|||||||
onClose: (reload?: boolean) => void;
|
onClose: (reload?: boolean) => void;
|
||||||
onViewStudents?: () => void;
|
onViewStudents?: () => void;
|
||||||
onViewTeachers?: () => void;
|
onViewTeachers?: () => void;
|
||||||
|
onViewCorporate?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers}: Props) => {
|
const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers, onViewCorporate}: Props) => {
|
||||||
const [expiryDate, setExpiryDate] = useState<Date | null | undefined>(user.subscriptionExpirationDate);
|
const [expiryDate, setExpiryDate] = useState<Date | null | undefined>(user.subscriptionExpirationDate);
|
||||||
const [type, setType] = useState(user.type);
|
const [type, setType] = useState(user.type);
|
||||||
const [status, setStatus] = useState(user.status);
|
const [status, setStatus] = useState(user.status);
|
||||||
@@ -456,6 +457,11 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers}:
|
|||||||
|
|
||||||
<div className="flex gap-4 justify-between mt-4 w-full">
|
<div className="flex gap-4 justify-between mt-4 w-full">
|
||||||
<div className="self-start flex gap-4 justify-start items-center w-full">
|
<div className="self-start flex gap-4 justify-start items-center w-full">
|
||||||
|
{onViewCorporate && (
|
||||||
|
<Button className="w-full max-w-[200px]" variant="outline" color="rose" onClick={onViewCorporate}>
|
||||||
|
View Corporate
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
{onViewStudents && (
|
{onViewStudents && (
|
||||||
<Button className="w-full max-w-[200px]" variant="outline" color="rose" onClick={onViewStudents}>
|
<Button className="w-full max-w-[200px]" variant="outline" color="rose" onClick={onViewStudents}>
|
||||||
View Students
|
View Students
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import {
|
|||||||
import UserCard from "@/components/UserCard";
|
import UserCard from "@/components/UserCard";
|
||||||
import useGroups from "@/hooks/useGroups";
|
import useGroups from "@/hooks/useGroups";
|
||||||
import IconCard from "./IconCard";
|
import IconCard from "./IconCard";
|
||||||
|
import useFilterStore from "@/stores/listFilterStore";
|
||||||
|
import {useRouter} from "next/router";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
@@ -34,6 +36,9 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
const {users, reload} = useUsers();
|
const {users, reload} = useUsers();
|
||||||
const {groups} = useGroups();
|
const {groups} = useGroups();
|
||||||
|
|
||||||
|
const appendUserFilters = useFilterStore((state) => state.appendUserFilter);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setShowModal(!!selectedUser && page === "");
|
setShowModal(!!selectedUser && page === "");
|
||||||
}, [selectedUser, page]);
|
}, [selectedUser, page]);
|
||||||
@@ -61,7 +66,7 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
? groups
|
? groups
|
||||||
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
|
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
|
||||||
.flatMap((g) => g.participants)
|
.flatMap((g) => g.participants)
|
||||||
.includes(x.id) || false
|
.includes(x.id)
|
||||||
: true);
|
: true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -76,7 +81,7 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<h2 className="text-2xl font-semibold">Students ({users.filter(filter).length})</h2>
|
<h2 className="text-2xl font-semibold">Students ({users.filter(filter).length})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UserList user={user} filter={filter} />
|
<UserList user={user} filters={[filter]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -103,7 +108,7 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<h2 className="text-2xl font-semibold">Teachers ({users.filter(filter).length})</h2>
|
<h2 className="text-2xl font-semibold">Teachers ({users.filter(filter).length})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UserList user={user} filter={filter} />
|
<UserList user={user} filters={[filter]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -123,7 +128,7 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<h2 className="text-2xl font-semibold">Country Managers ({users.filter(filter).length})</h2>
|
<h2 className="text-2xl font-semibold">Country Managers ({users.filter(filter).length})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UserList user={user} filter={filter} />
|
<UserList user={user} filters={[filter]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -140,7 +145,7 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<h2 className="text-2xl font-semibold">Corporate ({users.filter((x) => x.type === "corporate").length})</h2>
|
<h2 className="text-2xl font-semibold">Corporate ({users.filter((x) => x.type === "corporate").length})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UserList user={user} filter={(x) => x.type === "corporate"} />
|
<UserList user={user} filters={[(x) => x.type === "corporate"]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -159,7 +164,7 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<h2 className="text-2xl font-semibold">Inactive Students ({users.filter(filter).length})</h2>
|
<h2 className="text-2xl font-semibold">Inactive Students ({users.filter(filter).length})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UserList user={user} filter={filter} />
|
<UserList user={user} filters={[filter]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -179,7 +184,7 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<h2 className="text-2xl font-semibold">Inactive Corporate ({users.filter(filter).length})</h2>
|
<h2 className="text-2xl font-semibold">Inactive Corporate ({users.filter(filter).length})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UserList user={user} filter={filter} />
|
<UserList user={user} filters={[filter]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -378,9 +383,65 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
if (shouldReload) reload();
|
if (shouldReload) reload();
|
||||||
}}
|
}}
|
||||||
onViewStudents={
|
onViewStudents={
|
||||||
selectedUser.type === "corporate" || selectedUser.type === "teacher" ? () => setPage("students") : undefined
|
selectedUser.type === "corporate" || selectedUser.type === "teacher"
|
||||||
|
? () => {
|
||||||
|
appendUserFilters({
|
||||||
|
id: "view-students",
|
||||||
|
filter: (x: User) => x.type === "student",
|
||||||
|
});
|
||||||
|
appendUserFilters({
|
||||||
|
id: "belongs-to-admin",
|
||||||
|
filter: (x: User) =>
|
||||||
|
groups
|
||||||
|
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
|
||||||
|
.flatMap((g) => g.participants)
|
||||||
|
.includes(x.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push("/list/users");
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onViewTeachers={
|
||||||
|
selectedUser.type === "corporate" || selectedUser.type === "student"
|
||||||
|
? () => {
|
||||||
|
appendUserFilters({
|
||||||
|
id: "view-teachers",
|
||||||
|
filter: (x: User) => x.type === "teacher",
|
||||||
|
});
|
||||||
|
appendUserFilters({
|
||||||
|
id: "belongs-to-admin",
|
||||||
|
filter: (x: User) =>
|
||||||
|
groups
|
||||||
|
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
|
||||||
|
.flatMap((g) => g.participants)
|
||||||
|
.includes(x.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push("/list/users");
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onViewCorporate={
|
||||||
|
selectedUser.type === "teacher" || selectedUser.type === "student"
|
||||||
|
? () => {
|
||||||
|
appendUserFilters({
|
||||||
|
id: "view-corporate",
|
||||||
|
filter: (x: User) => x.type === "corporate",
|
||||||
|
});
|
||||||
|
appendUserFilters({
|
||||||
|
id: "belongs-to-admin",
|
||||||
|
filter: (x: User) =>
|
||||||
|
groups
|
||||||
|
.filter((g) => g.participants.includes(selectedUser.id))
|
||||||
|
.flatMap((g) => [g.admin, ...g.participants])
|
||||||
|
.includes(x.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push("/list/users");
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
onViewTeachers={selectedUser.type === "corporate" ? () => setPage("teachers") : undefined}
|
|
||||||
user={selectedUser}
|
user={selectedUser}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export default function AgentDashboard({user}: Props) {
|
|||||||
<h2 className="text-2xl font-semibold">Referred Corporate ({users.filter(filter).length})</h2>
|
<h2 className="text-2xl font-semibold">Referred Corporate ({users.filter(filter).length})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UserList user={user} filter={filter} />
|
<UserList user={user} filters={[filter]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -102,7 +102,7 @@ export default function AgentDashboard({user}: Props) {
|
|||||||
<h2 className="text-2xl font-semibold">Referred Corporate ({users.filter(filter).length})</h2>
|
<h2 className="text-2xl font-semibold">Referred Corporate ({users.filter(filter).length})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UserList user={user} filter={filter} />
|
<UserList user={user} filters={[filter]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import {Module} from "@/interfaces";
|
|||||||
import {groupByExam} from "@/utils/stats";
|
import {groupByExam} from "@/utils/stats";
|
||||||
import IconCard from "./IconCard";
|
import IconCard from "./IconCard";
|
||||||
import GroupList from "@/pages/(admin)/Lists/GroupList";
|
import GroupList from "@/pages/(admin)/Lists/GroupList";
|
||||||
|
import useFilterStore from "@/stores/listFilterStore";
|
||||||
|
import {useRouter} from "next/router";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
@@ -43,6 +45,9 @@ export default function CorporateDashboard({user}: Props) {
|
|||||||
const {users, reload} = useUsers();
|
const {users, reload} = useUsers();
|
||||||
const {groups} = useGroups(user.id);
|
const {groups} = useGroups(user.id);
|
||||||
|
|
||||||
|
const appendUserFilters = useFilterStore((state) => state.appendUserFilter);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setShowModal(!!selectedUser && page === "");
|
setShowModal(!!selectedUser && page === "");
|
||||||
}, [selectedUser, page]);
|
}, [selectedUser, page]);
|
||||||
@@ -86,7 +91,7 @@ export default function CorporateDashboard({user}: Props) {
|
|||||||
<h2 className="text-2xl font-semibold">Students ({users.filter(filter).length})</h2>
|
<h2 className="text-2xl font-semibold">Students ({users.filter(filter).length})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UserList user={user} filter={filter} />
|
<UserList user={user} filters={[filter]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -113,7 +118,7 @@ export default function CorporateDashboard({user}: Props) {
|
|||||||
<h2 className="text-2xl font-semibold">Teachers ({users.filter(filter).length})</h2>
|
<h2 className="text-2xl font-semibold">Teachers ({users.filter(filter).length})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UserList user={user} filter={filter} />
|
<UserList user={user} filters={[filter]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -256,9 +261,45 @@ export default function CorporateDashboard({user}: Props) {
|
|||||||
if (shouldReload) reload();
|
if (shouldReload) reload();
|
||||||
}}
|
}}
|
||||||
onViewStudents={
|
onViewStudents={
|
||||||
selectedUser.type === "corporate" || selectedUser.type === "teacher" ? () => setPage("students") : undefined
|
selectedUser.type === "corporate" || selectedUser.type === "teacher"
|
||||||
|
? () => {
|
||||||
|
appendUserFilters({
|
||||||
|
id: "view-students",
|
||||||
|
filter: (x: User) => x.type === "student",
|
||||||
|
});
|
||||||
|
appendUserFilters({
|
||||||
|
id: "belongs-to-admin",
|
||||||
|
filter: (x: User) =>
|
||||||
|
groups
|
||||||
|
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
|
||||||
|
.flatMap((g) => g.participants)
|
||||||
|
.includes(x.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push("/list/users");
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onViewTeachers={
|
||||||
|
selectedUser.type === "corporate" || selectedUser.type === "student"
|
||||||
|
? () => {
|
||||||
|
appendUserFilters({
|
||||||
|
id: "view-teachers",
|
||||||
|
filter: (x: User) => x.type === "teacher",
|
||||||
|
});
|
||||||
|
appendUserFilters({
|
||||||
|
id: "belongs-to-admin",
|
||||||
|
filter: (x: User) =>
|
||||||
|
groups
|
||||||
|
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
|
||||||
|
.flatMap((g) => g.participants)
|
||||||
|
.includes(x.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push("/list/users");
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
onViewTeachers={selectedUser.type === "corporate" ? () => setPage("teachers") : undefined}
|
|
||||||
user={selectedUser}
|
user={selectedUser}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export default function TeacherDashboard({user}: Props) {
|
|||||||
<h2 className="text-2xl font-semibold">Students ({users.filter(filter).length})</h2>
|
<h2 className="text-2xl font-semibold">Students ({users.filter(filter).length})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UserList user={user} filter={filter} />
|
<UserList user={user} filters={[filter]} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,17 +17,22 @@ import countryCodes from "country-codes-list";
|
|||||||
import Modal from "@/components/Modal";
|
import Modal from "@/components/Modal";
|
||||||
import UserCard from "@/components/UserCard";
|
import UserCard from "@/components/UserCard";
|
||||||
import {USER_TYPE_LABELS} from "@/resources/user";
|
import {USER_TYPE_LABELS} from "@/resources/user";
|
||||||
|
import useFilterStore from "@/stores/listFilterStore";
|
||||||
|
import {useRouter} from "next/router";
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<User>();
|
const columnHelper = createColumnHelper<User>();
|
||||||
|
|
||||||
export default function UserList({user, filter}: {user: User; filter?: (user: User) => boolean}) {
|
export default function UserList({user, filters = []}: {user: User; filters?: ((user: User) => boolean)[]}) {
|
||||||
const [showDemographicInformation, setShowDemographicInformation] = useState(false);
|
const [showDemographicInformation, setShowDemographicInformation] = useState(false);
|
||||||
const [sorter, setSorter] = useState<string>();
|
const [sorter, setSorter] = useState<string>();
|
||||||
const [displayUsers, setDisplayUsers] = useState<User[]>([]);
|
const [displayUsers, setDisplayUsers] = useState<User[]>([]);
|
||||||
const [selectedUser, setSelectedUser] = useState<User>();
|
const [selectedUser, setSelectedUser] = useState<User>();
|
||||||
|
|
||||||
const {users, reload} = useUsers();
|
const {users, reload} = useUsers();
|
||||||
const {groups} = useGroups(user ? user.id : undefined);
|
const {groups} = useGroups(user && (user?.type === "corporate" || user?.type === "teacher") ? user.id : undefined);
|
||||||
|
|
||||||
|
const appendUserFilters = useFilterStore((state) => state.appendUserFilter);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
const expirationDateColor = (date: Date) => {
|
const expirationDateColor = (date: Date) => {
|
||||||
const momentDate = moment(date);
|
const momentDate = moment(date);
|
||||||
@@ -42,11 +47,11 @@ export default function UserList({user, filter}: {user: User; filter?: (user: Us
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (user && users) {
|
if (user && users) {
|
||||||
const filterUsers =
|
const filterUsers =
|
||||||
user.type === "corporate" || user.type === "student"
|
user.type === "corporate" || user.type === "teacher"
|
||||||
? users.filter((u) => groups.flatMap((g) => g.participants).includes(u.id))
|
? users.filter((u) => groups.flatMap((g) => g.participants).includes(u.id))
|
||||||
: users;
|
: users;
|
||||||
|
|
||||||
const filteredUsers = filter ? filterUsers.filter(filter) : filterUsers;
|
const filteredUsers = filters.reduce((d, f) => d.filter(f), filterUsers);
|
||||||
|
|
||||||
setDisplayUsers([...filteredUsers.sort(sortFunction)]);
|
setDisplayUsers([...filteredUsers.sort(sortFunction)]);
|
||||||
}
|
}
|
||||||
@@ -457,6 +462,66 @@ export default function UserList({user, filter}: {user: User; filter?: (user: Us
|
|||||||
<div className="w-full flex flex-col gap-8">
|
<div className="w-full flex flex-col gap-8">
|
||||||
<UserCard
|
<UserCard
|
||||||
loggedInUser={user}
|
loggedInUser={user}
|
||||||
|
onViewStudents={
|
||||||
|
selectedUser.type === "corporate" || selectedUser.type === "teacher"
|
||||||
|
? () => {
|
||||||
|
appendUserFilters({
|
||||||
|
id: "view-students",
|
||||||
|
filter: (x: User) => x.type === "student",
|
||||||
|
});
|
||||||
|
appendUserFilters({
|
||||||
|
id: "belongs-to-admin",
|
||||||
|
filter: (x: User) =>
|
||||||
|
groups
|
||||||
|
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
|
||||||
|
.flatMap((g) => g.participants)
|
||||||
|
.includes(x.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push("/list/users");
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onViewTeachers={
|
||||||
|
selectedUser.type === "corporate" || selectedUser.type === "student"
|
||||||
|
? () => {
|
||||||
|
appendUserFilters({
|
||||||
|
id: "view-teachers",
|
||||||
|
filter: (x: User) => x.type === "teacher",
|
||||||
|
});
|
||||||
|
appendUserFilters({
|
||||||
|
id: "belongs-to-admin",
|
||||||
|
filter: (x: User) =>
|
||||||
|
groups
|
||||||
|
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
|
||||||
|
.flatMap((g) => g.participants)
|
||||||
|
.includes(x.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push("/list/users");
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onViewCorporate={
|
||||||
|
selectedUser.type === "teacher" || selectedUser.type === "student"
|
||||||
|
? () => {
|
||||||
|
appendUserFilters({
|
||||||
|
id: "view-corporate",
|
||||||
|
filter: (x: User) => x.type === "corporate",
|
||||||
|
});
|
||||||
|
appendUserFilters({
|
||||||
|
id: "belongs-to-admin",
|
||||||
|
filter: (x: User) =>
|
||||||
|
groups
|
||||||
|
.filter((g) => g.participants.includes(selectedUser.id))
|
||||||
|
.flatMap((g) => [g.admin, ...g.participants])
|
||||||
|
.includes(x.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push("/list/users");
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
onClose={(shouldReload) => {
|
onClose={(shouldReload) => {
|
||||||
setSelectedUser(undefined);
|
setSelectedUser(undefined);
|
||||||
if (shouldReload) reload();
|
if (shouldReload) reload();
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ const ListeningGeneration = () => {
|
|||||||
setPart1(undefined);
|
setPart1(undefined);
|
||||||
setPart2(undefined);
|
setPart2(undefined);
|
||||||
setPart3(undefined);
|
setPart3(undefined);
|
||||||
|
setPart4(undefined);
|
||||||
setTypes([]);
|
setTypes([]);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
|||||||
80
src/pages/list/users.tsx
Normal file
80
src/pages/list/users.tsx
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import Layout from "@/components/High/Layout";
|
||||||
|
import useUser from "@/hooks/useUser";
|
||||||
|
import useUsers from "@/hooks/useUsers";
|
||||||
|
import {sessionOptions} from "@/lib/session";
|
||||||
|
import useFilterStore from "@/stores/listFilterStore";
|
||||||
|
import {withIronSessionSsr} from "iron-session/next";
|
||||||
|
import Head from "next/head";
|
||||||
|
import {useRouter} from "next/router";
|
||||||
|
import {useEffect} from "react";
|
||||||
|
import {BsArrowLeft} from "react-icons/bs";
|
||||||
|
import {ToastContainer} from "react-toastify";
|
||||||
|
import UserList from "../(admin)/Lists/UserList";
|
||||||
|
|
||||||
|
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
||||||
|
const user = req.session.user;
|
||||||
|
|
||||||
|
const envVariables: {[key: string]: string} = {};
|
||||||
|
Object.keys(process.env)
|
||||||
|
.filter((x) => x.startsWith("NEXT_PUBLIC"))
|
||||||
|
.forEach((x: string) => {
|
||||||
|
envVariables[x] = process.env[x]!;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user || !user.isVerified) {
|
||||||
|
res.setHeader("location", "/login");
|
||||||
|
res.statusCode = 302;
|
||||||
|
res.end();
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
user: null,
|
||||||
|
envVariables,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {user: req.session.user, envVariables},
|
||||||
|
};
|
||||||
|
}, sessionOptions);
|
||||||
|
|
||||||
|
export default function UsersListPage() {
|
||||||
|
const {user} = useUser();
|
||||||
|
const {users} = useUsers();
|
||||||
|
const [filters, clearFilters] = useFilterStore((state) => [state.userFilters, state.clearUserFilters]);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title>EnCoach</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
|
||||||
|
/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
</Head>
|
||||||
|
<ToastContainer />
|
||||||
|
|
||||||
|
{user && (
|
||||||
|
<Layout user={user}>
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
clearFilters();
|
||||||
|
router.back();
|
||||||
|
}}
|
||||||
|
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
|
||||||
|
<BsArrowLeft className="text-xl" />
|
||||||
|
<span>Back</span>
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-semibold">Users ({filters.map((f) => f.filter).reduce((d, f) => d.filter(f), users).length})</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<UserList user={user} filters={filters.map((f) => f.filter)} />
|
||||||
|
</Layout>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
34
src/stores/listFilterStore.ts
Normal file
34
src/stores/listFilterStore.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import {Group, User} from "@/interfaces/user";
|
||||||
|
import {create} from "zustand";
|
||||||
|
|
||||||
|
export type Filter<T> = {id: string; filter: (x: T) => boolean};
|
||||||
|
|
||||||
|
export interface ListFilterState {
|
||||||
|
userFilters: Filter<User>[];
|
||||||
|
groupFilters: Filter<Group>[];
|
||||||
|
appendUserFilter: (filter: Filter<User>) => void;
|
||||||
|
removeUserFilter: (id: string) => void;
|
||||||
|
clearUserFilters: () => void;
|
||||||
|
appendGroupFilter: (filter: Filter<Group>) => void;
|
||||||
|
removeGroupFilter: (id: string) => void;
|
||||||
|
clearGroupFilters: () => void;
|
||||||
|
reset: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialState = {
|
||||||
|
userFilters: [],
|
||||||
|
groupFilters: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const useFilterStore = create<ListFilterState>((set) => ({
|
||||||
|
...initialState,
|
||||||
|
appendUserFilter: (filter: Filter<User>) => set((state) => ({userFilters: [...state.userFilters.filter((f) => f.id !== filter.id), filter]})),
|
||||||
|
appendGroupFilter: (filter: Filter<Group>) => set((state) => ({groupFilters: [...state.groupFilters.filter((f) => f.id !== filter.id), filter]})),
|
||||||
|
removeUserFilter: (id: string) => set((state) => ({userFilters: state.userFilters.filter((x) => x.id !== id)})),
|
||||||
|
removeGroupFilter: (id: string) => set((state) => ({groupFilters: state.groupFilters.filter((x) => x.id !== id)})),
|
||||||
|
clearUserFilters: () => set({userFilters: []}),
|
||||||
|
clearGroupFilters: () => set({groupFilters: []}),
|
||||||
|
reset: () => set(() => initialState),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default useFilterStore;
|
||||||
Reference in New Issue
Block a user