Search on user list with mongo search query
This commit is contained in:
@@ -17,7 +17,7 @@ import moment from "moment";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
mutateUser: KeyedMutator<User>;
|
mutateUser: (user: User) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DemographicInformationInput({user, mutateUser}: Props) {
|
export default function DemographicInformationInput({user, mutateUser}: Props) {
|
||||||
|
|||||||
@@ -31,12 +31,40 @@ interface Props {
|
|||||||
user: User;
|
user: User;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const studentHash = {
|
||||||
|
type: "student",
|
||||||
|
size: 25,
|
||||||
|
orderBy: "registrationDate",
|
||||||
|
};
|
||||||
|
|
||||||
|
const teacherHash = {
|
||||||
|
type: "teacher",
|
||||||
|
size: 25,
|
||||||
|
orderBy: "registrationDate",
|
||||||
|
};
|
||||||
|
|
||||||
|
const corporateHash = {
|
||||||
|
type: "corporate",
|
||||||
|
size: 25,
|
||||||
|
orderBy: "registrationDate",
|
||||||
|
};
|
||||||
|
|
||||||
|
const agentsHash = {
|
||||||
|
type: "agent",
|
||||||
|
size: 25,
|
||||||
|
orderBy: "registrationDate",
|
||||||
|
};
|
||||||
|
|
||||||
export default function AdminDashboard({user}: Props) {
|
export default function AdminDashboard({user}: Props) {
|
||||||
const [page, setPage] = useState("");
|
const [page, setPage] = useState("");
|
||||||
const [selectedUser, setSelectedUser] = useState<User>();
|
const [selectedUser, setSelectedUser] = useState<User>();
|
||||||
const [showModal, setShowModal] = useState(false);
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
|
||||||
const {users, reload, isLoading} = useUsers();
|
const {users: students, total: totalStudents, reload: reloadStudents, isLoading: isStudentsLoading} = useUsers(studentHash);
|
||||||
|
const {users: teachers, total: totalTeachers, reload: reloadTeachers, isLoading: isTeachersLoading} = useUsers(teacherHash);
|
||||||
|
const {users: corporates, total: totalCorporate, reload: reloadCorporates, isLoading: isCorporatesLoading} = useUsers(corporateHash);
|
||||||
|
const {users: agents, total: totalAgents, reload: reloadAgents, isLoading: isAgentsLoading} = useUsers(agentsHash);
|
||||||
|
|
||||||
const {groups} = useGroups({});
|
const {groups} = useGroups({});
|
||||||
const {pending, done} = usePaymentStatusUsers();
|
const {pending, done} = usePaymentStatusUsers();
|
||||||
|
|
||||||
@@ -47,9 +75,6 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
setShowModal(!!selectedUser && router.asPath === "/#");
|
setShowModal(!!selectedUser && router.asPath === "/#");
|
||||||
}, [selectedUser, router.asPath]);
|
}, [selectedUser, router.asPath]);
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
useEffect(reload, [page]);
|
|
||||||
|
|
||||||
const inactiveCountryManagerFilter = (x: User) => x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate);
|
const inactiveCountryManagerFilter = (x: User) => x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate);
|
||||||
|
|
||||||
const UserDisplay = (displayUser: User) => (
|
const UserDisplay = (displayUser: User) => (
|
||||||
@@ -279,50 +304,50 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<section className="w-full grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 place-items-center items-center justify-between">
|
<section className="w-full grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 place-items-center items-center justify-between">
|
||||||
<IconCard
|
<IconCard
|
||||||
Icon={BsPersonFill}
|
Icon={BsPersonFill}
|
||||||
isLoading={isLoading}
|
isLoading={isStudentsLoading}
|
||||||
label="Students"
|
label="Students"
|
||||||
value={users.filter((x) => x.type === "student").length}
|
value={totalStudents}
|
||||||
onClick={() => router.push("/#students")}
|
onClick={() => router.push("/#students")}
|
||||||
color="purple"
|
color="purple"
|
||||||
/>
|
/>
|
||||||
<IconCard
|
<IconCard
|
||||||
Icon={BsPencilSquare}
|
Icon={BsPencilSquare}
|
||||||
isLoading={isLoading}
|
isLoading={isTeachersLoading}
|
||||||
label="Teachers"
|
label="Teachers"
|
||||||
value={users.filter((x) => x.type === "teacher").length}
|
value={totalTeachers}
|
||||||
onClick={() => router.push("/#teachers")}
|
onClick={() => router.push("/#teachers")}
|
||||||
color="purple"
|
color="purple"
|
||||||
/>
|
/>
|
||||||
<IconCard
|
<IconCard
|
||||||
Icon={BsBank}
|
Icon={BsBank}
|
||||||
isLoading={isLoading}
|
isLoading={isCorporatesLoading}
|
||||||
label="Corporate"
|
label="Corporate"
|
||||||
value={users.filter((x) => x.type === "corporate").length}
|
value={totalCorporate}
|
||||||
onClick={() => router.push("/#corporate")}
|
onClick={() => router.push("/#corporate")}
|
||||||
color="purple"
|
color="purple"
|
||||||
/>
|
/>
|
||||||
<IconCard
|
<IconCard
|
||||||
Icon={BsBriefcaseFill}
|
Icon={BsBriefcaseFill}
|
||||||
isLoading={isLoading}
|
isLoading={isAgentsLoading}
|
||||||
label="Country Managers"
|
label="Country Managers"
|
||||||
value={users.filter((x) => x.type === "agent").length}
|
value={totalAgents}
|
||||||
onClick={() => router.push("/#agents")}
|
onClick={() => router.push("/#agents")}
|
||||||
color="purple"
|
color="purple"
|
||||||
/>
|
/>
|
||||||
<IconCard
|
<IconCard
|
||||||
Icon={BsGlobeCentralSouthAsia}
|
Icon={BsGlobeCentralSouthAsia}
|
||||||
isLoading={isLoading}
|
isLoading={isAgentsLoading}
|
||||||
label="Countries"
|
label="Countries"
|
||||||
value={[...new Set(users.filter((x) => x.demographicInformation).map((x) => x.demographicInformation?.country))].length}
|
value={[...new Set(agents.filter((x) => x.demographicInformation).map((x) => x.demographicInformation?.country))].length}
|
||||||
color="purple"
|
color="purple"
|
||||||
/>
|
/>
|
||||||
<IconCard
|
<IconCard
|
||||||
onClick={() => router.push("/#inactiveStudents")}
|
onClick={() => router.push("/#inactiveStudents")}
|
||||||
Icon={BsPersonFill}
|
Icon={BsPersonFill}
|
||||||
isLoading={isLoading}
|
isLoading={isStudentsLoading}
|
||||||
label="Inactive Students"
|
label="Inactive Students"
|
||||||
value={
|
value={
|
||||||
users.filter((x) => x.type === "student" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)))
|
students.filter((x) => x.type === "student" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)))
|
||||||
.length
|
.length
|
||||||
}
|
}
|
||||||
color="rose"
|
color="rose"
|
||||||
@@ -330,26 +355,26 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<IconCard
|
<IconCard
|
||||||
onClick={() => router.push("/#inactiveCountryManagers")}
|
onClick={() => router.push("/#inactiveCountryManagers")}
|
||||||
Icon={BsBriefcaseFill}
|
Icon={BsBriefcaseFill}
|
||||||
isLoading={isLoading}
|
isLoading={isAgentsLoading}
|
||||||
label="Inactive Country Managers"
|
label="Inactive Country Managers"
|
||||||
value={users.filter(inactiveCountryManagerFilter).length}
|
value={agents.filter(inactiveCountryManagerFilter).length}
|
||||||
color="rose"
|
color="rose"
|
||||||
/>
|
/>
|
||||||
<IconCard
|
<IconCard
|
||||||
onClick={() => router.push("/#inactiveCorporate")}
|
onClick={() => router.push("/#inactiveCorporate")}
|
||||||
Icon={BsBank}
|
Icon={BsBank}
|
||||||
isLoading={isLoading}
|
isLoading={isCorporatesLoading}
|
||||||
label="Inactive Corporate"
|
label="Inactive Corporate"
|
||||||
value={
|
value={
|
||||||
users.filter((x) => x.type === "corporate" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)))
|
corporates.filter(
|
||||||
.length
|
(x) => x.type === "corporate" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)),
|
||||||
|
).length
|
||||||
}
|
}
|
||||||
color="rose"
|
color="rose"
|
||||||
/>
|
/>
|
||||||
<IconCard
|
<IconCard
|
||||||
onClick={() => router.push("/#paymentdone")}
|
onClick={() => router.push("/#paymentdone")}
|
||||||
Icon={BsCurrencyDollar}
|
Icon={BsCurrencyDollar}
|
||||||
isLoading={isLoading}
|
|
||||||
label="Payment Done"
|
label="Payment Done"
|
||||||
value={done.length}
|
value={done.length}
|
||||||
color="purple"
|
color="purple"
|
||||||
@@ -357,7 +382,6 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<IconCard
|
<IconCard
|
||||||
onClick={() => router.push("/#paymentpending")}
|
onClick={() => router.push("/#paymentpending")}
|
||||||
Icon={BsCurrencyDollar}
|
Icon={BsCurrencyDollar}
|
||||||
isLoading={isLoading}
|
|
||||||
label="Pending Payment"
|
label="Pending Payment"
|
||||||
value={pending.length}
|
value={pending.length}
|
||||||
color="rose"
|
color="rose"
|
||||||
@@ -365,14 +389,13 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<IconCard
|
<IconCard
|
||||||
onClick={() => router.push("https://cms.encoach.com/admin")}
|
onClick={() => router.push("https://cms.encoach.com/admin")}
|
||||||
Icon={BsLayoutSidebar}
|
Icon={BsLayoutSidebar}
|
||||||
isLoading={isLoading}
|
|
||||||
label="Content Management System (CMS)"
|
label="Content Management System (CMS)"
|
||||||
color="green"
|
color="green"
|
||||||
/>
|
/>
|
||||||
<IconCard
|
<IconCard
|
||||||
onClick={() => router.push("/#corporatestudentslevels")}
|
onClick={() => router.push("/#corporatestudentslevels")}
|
||||||
Icon={BsPersonFill}
|
Icon={BsPersonFill}
|
||||||
isLoading={isLoading}
|
isLoading={isStudentsLoading}
|
||||||
label="Corporate Students Levels"
|
label="Corporate Students Levels"
|
||||||
color="purple"
|
color="purple"
|
||||||
/>
|
/>
|
||||||
@@ -382,8 +405,7 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Latest students</span>
|
<span className="p-4">Latest students</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{students
|
||||||
.filter((x) => x.type === "student")
|
|
||||||
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
|
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
|
||||||
.map((x) => (
|
.map((x) => (
|
||||||
<UserDisplay key={x.id} {...x} />
|
<UserDisplay key={x.id} {...x} />
|
||||||
@@ -393,8 +415,7 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Latest teachers</span>
|
<span className="p-4">Latest teachers</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{teachers
|
||||||
.filter((x) => x.type === "teacher")
|
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
return dateSorter(a, b, "desc", "registrationDate");
|
return dateSorter(a, b, "desc", "registrationDate");
|
||||||
})
|
})
|
||||||
@@ -406,8 +427,7 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Latest corporate</span>
|
<span className="p-4">Latest corporate</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{corporates
|
||||||
.filter((x) => x.type === "corporate")
|
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
return dateSorter(a, b, "desc", "registrationDate");
|
return dateSorter(a, b, "desc", "registrationDate");
|
||||||
})
|
})
|
||||||
@@ -419,8 +439,8 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Unpaid Corporate</span>
|
<span className="p-4">Unpaid Corporate</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{corporates
|
||||||
.filter((x) => x.type === "corporate" && x.status === "paymentDue")
|
.filter((x) => x.status === "paymentDue")
|
||||||
.map((x) => (
|
.map((x) => (
|
||||||
<UserDisplay key={x.id} {...x} />
|
<UserDisplay key={x.id} {...x} />
|
||||||
))}
|
))}
|
||||||
@@ -429,10 +449,9 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Students expiring in 1 month</span>
|
<span className="p-4">Students expiring in 1 month</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{students
|
||||||
.filter(
|
.filter(
|
||||||
(x) =>
|
(x) =>
|
||||||
x.type === "student" &&
|
|
||||||
x.subscriptionExpirationDate &&
|
x.subscriptionExpirationDate &&
|
||||||
moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) &&
|
moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) &&
|
||||||
moment().isBefore(moment(x.subscriptionExpirationDate)),
|
moment().isBefore(moment(x.subscriptionExpirationDate)),
|
||||||
@@ -445,10 +464,9 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Teachers expiring in 1 month</span>
|
<span className="p-4">Teachers expiring in 1 month</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{teachers
|
||||||
.filter(
|
.filter(
|
||||||
(x) =>
|
(x) =>
|
||||||
x.type === "teacher" &&
|
|
||||||
x.subscriptionExpirationDate &&
|
x.subscriptionExpirationDate &&
|
||||||
moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) &&
|
moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) &&
|
||||||
moment().isBefore(moment(x.subscriptionExpirationDate)),
|
moment().isBefore(moment(x.subscriptionExpirationDate)),
|
||||||
@@ -461,10 +479,9 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Country Manager expiring in 1 month</span>
|
<span className="p-4">Country Manager expiring in 1 month</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{agents
|
||||||
.filter(
|
.filter(
|
||||||
(x) =>
|
(x) =>
|
||||||
x.type === "agent" &&
|
|
||||||
x.subscriptionExpirationDate &&
|
x.subscriptionExpirationDate &&
|
||||||
moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) &&
|
moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) &&
|
||||||
moment().isBefore(moment(x.subscriptionExpirationDate)),
|
moment().isBefore(moment(x.subscriptionExpirationDate)),
|
||||||
@@ -477,10 +494,9 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Corporate expiring in 1 month</span>
|
<span className="p-4">Corporate expiring in 1 month</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{corporates
|
||||||
.filter(
|
.filter(
|
||||||
(x) =>
|
(x) =>
|
||||||
x.type === "corporate" &&
|
|
||||||
x.subscriptionExpirationDate &&
|
x.subscriptionExpirationDate &&
|
||||||
moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) &&
|
moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) &&
|
||||||
moment().isBefore(moment(x.subscriptionExpirationDate)),
|
moment().isBefore(moment(x.subscriptionExpirationDate)),
|
||||||
@@ -493,10 +509,8 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Expired Students</span>
|
<span className="p-4">Expired Students</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{students
|
||||||
.filter(
|
.filter((x) => x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)))
|
||||||
(x) => x.type === "student" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)),
|
|
||||||
)
|
|
||||||
.map((x) => (
|
.map((x) => (
|
||||||
<UserDisplay key={x.id} {...x} />
|
<UserDisplay key={x.id} {...x} />
|
||||||
))}
|
))}
|
||||||
@@ -505,10 +519,8 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Expired Teachers</span>
|
<span className="p-4">Expired Teachers</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{teachers
|
||||||
.filter(
|
.filter((x) => x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)))
|
||||||
(x) => x.type === "teacher" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)),
|
|
||||||
)
|
|
||||||
.map((x) => (
|
.map((x) => (
|
||||||
<UserDisplay key={x.id} {...x} />
|
<UserDisplay key={x.id} {...x} />
|
||||||
))}
|
))}
|
||||||
@@ -517,10 +529,8 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Expired Country Manager</span>
|
<span className="p-4">Expired Country Manager</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{agents
|
||||||
.filter(
|
.filter((x) => x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)))
|
||||||
(x) => x.type === "agent" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)),
|
|
||||||
)
|
|
||||||
.map((x) => (
|
.map((x) => (
|
||||||
<UserDisplay key={x.id} {...x} />
|
<UserDisplay key={x.id} {...x} />
|
||||||
))}
|
))}
|
||||||
@@ -529,11 +539,8 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Expired Corporate</span>
|
<span className="p-4">Expired Corporate</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{corporates
|
||||||
.filter(
|
.filter((x) => x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)))
|
||||||
(x) =>
|
|
||||||
x.type === "corporate" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)),
|
|
||||||
)
|
|
||||||
.map((x) => (
|
.map((x) => (
|
||||||
<UserDisplay key={x.id} {...x} />
|
<UserDisplay key={x.id} {...x} />
|
||||||
))}
|
))}
|
||||||
@@ -553,7 +560,10 @@ export default function AdminDashboard({user}: Props) {
|
|||||||
loggedInUser={user}
|
loggedInUser={user}
|
||||||
onClose={(shouldReload) => {
|
onClose={(shouldReload) => {
|
||||||
setSelectedUser(undefined);
|
setSelectedUser(undefined);
|
||||||
if (shouldReload) reload();
|
if (shouldReload && selectedUser!.type === "student") reloadStudents();
|
||||||
|
if (shouldReload && selectedUser!.type === "teacher") reloadTeachers();
|
||||||
|
if (shouldReload && selectedUser!.type === "corporate") reloadCorporates();
|
||||||
|
if (shouldReload && selectedUser!.type === "agent") reloadAgents();
|
||||||
}}
|
}}
|
||||||
onViewStudents={
|
onViewStudents={
|
||||||
selectedUser.type === "corporate" || selectedUser.type === "teacher"
|
selectedUser.type === "corporate" || selectedUser.type === "teacher"
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ const MasterStatistical = (props: Props) => {
|
|||||||
const [endDate, setEndDate] = React.useState<Date | null>(moment().endOf("year").toDate());
|
const [endDate, setEndDate] = React.useState<Date | null>(moment().endOf("year").toDate());
|
||||||
|
|
||||||
const {assignments} = useAssignmentsCorporates({
|
const {assignments} = useAssignmentsCorporates({
|
||||||
// corporates: [...corporates, "tYU0HTiJdjMsS8SB7XJsUdMMP892"],
|
|
||||||
corporates: selectedCorporates,
|
corporates: selectedCorporates,
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
@@ -69,38 +68,40 @@ const MasterStatistical = (props: Props) => {
|
|||||||
|
|
||||||
const tableResults = React.useMemo(
|
const tableResults = React.useMemo(
|
||||||
() =>
|
() =>
|
||||||
assignments.reduce((accmA: TableData[], a: AssignmentWithCorporateId) => {
|
assignments
|
||||||
const userResults = a.assignees.map((assignee) => {
|
.reduce((accmA: TableData[], a: AssignmentWithCorporateId) => {
|
||||||
const userStats = a.results.find((r) => r.user === assignee)?.stats || [];
|
const userResults = a.assignees.map((assignee) => {
|
||||||
const userData = users.find((u) => u.id === assignee);
|
const userStats = a.results.find((r) => r.user === assignee)?.stats || [];
|
||||||
const corporate = users.find((u) => u.id === a.assigner)?.name || "";
|
const userData = users.find((u) => u.id === assignee);
|
||||||
const commonData = {
|
const corporate = users.find((u) => u.id === a.assigner)?.name || "";
|
||||||
user: userData?.name || "",
|
const commonData = {
|
||||||
email: userData?.email || "",
|
user: userData?.name || "N/A",
|
||||||
userId: assignee,
|
email: userData?.email || "N/A",
|
||||||
corporateId: a.corporateId,
|
userId: assignee,
|
||||||
corporate,
|
corporateId: a.corporateId,
|
||||||
assignment: a.name,
|
corporate,
|
||||||
};
|
assignment: a.name,
|
||||||
if (userStats.length === 0) {
|
};
|
||||||
|
if (userStats.length === 0) {
|
||||||
|
return {
|
||||||
|
...commonData,
|
||||||
|
correct: 0,
|
||||||
|
submitted: false,
|
||||||
|
// date: moment(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...commonData,
|
...commonData,
|
||||||
correct: 0,
|
correct: userStats.reduce((n, e) => n + e.score.correct, 0),
|
||||||
submitted: false,
|
submitted: true,
|
||||||
// date: moment(),
|
date: moment.max(userStats.map((e) => moment(e.date))),
|
||||||
};
|
};
|
||||||
}
|
}) as TableData[];
|
||||||
|
|
||||||
return {
|
return [...accmA, ...userResults];
|
||||||
...commonData,
|
}, [])
|
||||||
correct: userStats.reduce((n, e) => n + e.score.correct, 0),
|
.filter((x) => x.user !== "N/A"),
|
||||||
submitted: true,
|
|
||||||
date: moment.max(userStats.map((e) => moment(e.date))),
|
|
||||||
};
|
|
||||||
}) as TableData[];
|
|
||||||
|
|
||||||
return [...accmA, ...userResults];
|
|
||||||
}, []),
|
|
||||||
[assignments, users],
|
[assignments, users],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import {Exam} from "@/interfaces/exam";
|
import {Exam} from "@/interfaces/exam";
|
||||||
import {ExamState} from "@/stores/examStore";
|
import {ExamState} from "@/stores/examStore";
|
||||||
import Axios from "axios";
|
import axios from "axios";
|
||||||
import {setupCache} from "axios-cache-interceptor";
|
import {setupCache} from "axios-cache-interceptor";
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
|
|
||||||
const instance = Axios.create();
|
|
||||||
const axios = setupCache(instance);
|
|
||||||
|
|
||||||
export type Session = ExamState & {user: string; id: string; date: string};
|
export type Session = ExamState & {user: string; id: string; date: string};
|
||||||
|
|
||||||
export default function useSessions(user?: string) {
|
export default function useSessions(user?: string) {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ const USER_TYPE_PERMISSIONS: {
|
|||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
perm: "createCodeAdmin",
|
perm: "createCodeAdmin",
|
||||||
list: ["student", "teacher", "agent", "corporate", "admin", "mastercorporate"],
|
list: ["student", "teacher", "agent", "corporate", "mastercorporate"],
|
||||||
},
|
},
|
||||||
developer: {
|
developer: {
|
||||||
perm: undefined,
|
perm: undefined,
|
||||||
@@ -161,7 +161,7 @@ export default function BatchCreateUser({user, users, permissions, onFinish}: Pr
|
|||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await axios.post("/api/batch_users", { users: newUsers.map(user => ({...user, type, expiryDate})) });
|
await axios.post("/api/batch_users", {users: newUsers.map((user) => ({...user, type, expiryDate}))});
|
||||||
toast.success(`Successfully added ${newUsers.length} user(s)!`);
|
toast.success(`Successfully added ${newUsers.length} user(s)!`);
|
||||||
onFinish();
|
onFinish();
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -32,7 +32,11 @@ import Input from "@/components/Low/Input";
|
|||||||
const columnHelper = createColumnHelper<User>();
|
const columnHelper = createColumnHelper<User>();
|
||||||
const searchFields = [["name"], ["email"], ["corporateInformation", "companyInformation", "name"]];
|
const searchFields = [["name"], ["email"], ["corporateInformation", "companyInformation", "name"]];
|
||||||
|
|
||||||
const CompanyNameCell = ({ users, user, groups }: { user: User; users: User[]; groups: Group[] }) => {
|
const corporatesHash = {
|
||||||
|
type: "corporate",
|
||||||
|
};
|
||||||
|
|
||||||
|
const CompanyNameCell = ({users, user, groups}: {user: User; users: User[]; groups: Group[]}) => {
|
||||||
const [companyName, setCompanyName] = useState("");
|
const [companyName, setCompanyName] = useState("");
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
@@ -64,9 +68,13 @@ export default function UserList({
|
|||||||
|
|
||||||
const { users, total, isLoading, reload } = useUsers({type: type, size: 16, page: page, searchTerm: searchTerm});
|
const { users, total, isLoading, reload } = useUsers({type: type, size: 16, page: page, searchTerm: searchTerm});
|
||||||
|
|
||||||
const { permissions } = usePermissions(user?.id || "");
|
const {users: corporates} = useUsers(corporatesHash);
|
||||||
const { balance } = useUserBalance();
|
|
||||||
const { groups } = useGroups({
|
const totalUsers = useMemo(() => [...users, ...corporates], [users, corporates]);
|
||||||
|
|
||||||
|
const {permissions} = usePermissions(user?.id || "");
|
||||||
|
const {balance} = useUserBalance();
|
||||||
|
const {groups} = useGroups({
|
||||||
admin: user && ["corporate", "teacher", "mastercorporate"].includes(user?.type) ? user.id : undefined,
|
admin: user && ["corporate", "teacher", "mastercorporate"].includes(user?.type) ? user.id : undefined,
|
||||||
userType: user?.type,
|
userType: user?.type,
|
||||||
});
|
});
|
||||||
@@ -346,7 +354,7 @@ export default function UserList({
|
|||||||
<SorterArrow name="companyName" />
|
<SorterArrow name="companyName" />
|
||||||
</button>
|
</button>
|
||||||
) as any,
|
) as any,
|
||||||
cell: (info) => <CompanyNameCell user={info.row.original} users={users} groups={groups} />,
|
cell: (info) => <CompanyNameCell user={info.row.original} users={totalUsers} groups={groups} />,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("subscriptionExpirationDate", {
|
columnHelper.accessor("subscriptionExpirationDate", {
|
||||||
header: (
|
header: (
|
||||||
|
|||||||
@@ -141,7 +141,11 @@ export default function UserCreator({user, users, permissions, onFinish}: Props)
|
|||||||
setType("student");
|
setType("student");
|
||||||
setPosition(undefined);
|
setPosition(undefined);
|
||||||
})
|
})
|
||||||
.catch(() => toast.error("Something went wrong! Please try again later!"))
|
.catch((error) => {
|
||||||
|
const data = error?.response?.data;
|
||||||
|
if (!!data?.message) return toast.error(data.message);
|
||||||
|
toast.error("Something went wrong! Please try again later!");
|
||||||
|
})
|
||||||
.finally(() => setIsLoading(false));
|
.finally(() => setIsLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -218,6 +218,8 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
return res.status(200).json({ok: true});
|
return res.status(200).json({ok: true});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
if (error.code.includes("email-already-in-use")) return res.status(403).json({error, message: "E-mail is already in the platform."});
|
||||||
|
|
||||||
console.log(`Failing - ${email}`);
|
console.log(`Failing - ${email}`);
|
||||||
console.log(error);
|
console.log(error);
|
||||||
return res.status(401).json({error});
|
return res.status(401).json({error});
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ async function get(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
const {user} = req.query as {user?: string};
|
const {user} = req.query as {user?: string};
|
||||||
|
|
||||||
const q = user ? {user: user} : {};
|
const q = user ? {user: user} : {};
|
||||||
const sessions = await db.collection("sessions").find<Session>(q).toArray();
|
const sessions = await db.collection("sessions").find<Session>(q).limit(10).toArray();
|
||||||
|
|
||||||
res.status(200).json(
|
res.status(200).json(
|
||||||
sessions.filter((x) => {
|
sessions.filter((x) => {
|
||||||
@@ -41,12 +41,8 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const session = req.body;
|
const session = req.body;
|
||||||
|
|
||||||
await db.collection("sessions").updateOne(
|
await db.collection("sessions").updateOne({id: session.id}, {$set: session}, {upsert: true});
|
||||||
{ id: session.id},
|
|
||||||
{ $set: session },
|
|
||||||
{ upsert: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
res.status(200).json({ok: true});
|
res.status(200).json({ok: true});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,18 +68,18 @@ interface Props {
|
|||||||
linkedCorporate?: CorporateUser | MasterCorporateUser;
|
linkedCorporate?: CorporateUser | MasterCorporateUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Home({linkedCorporate}: Props) {
|
export default function Home({user: propsUser, linkedCorporate}: Props) {
|
||||||
|
const [user, setUser] = useState(propsUser);
|
||||||
const [showDiagnostics, setShowDiagnostics] = useState(false);
|
const [showDiagnostics, setShowDiagnostics] = useState(false);
|
||||||
const [showDemographicInput, setShowDemographicInput] = useState(false);
|
const [showDemographicInput, setShowDemographicInput] = useState(false);
|
||||||
const [selectedScreen, setSelectedScreen] = useState<Type>("admin");
|
const [selectedScreen, setSelectedScreen] = useState<Type>("admin");
|
||||||
|
|
||||||
const {user, mutateUser} = useUser({redirectTo: "/login"});
|
const {mutateUser} = useUser({redirectTo: "/login"});
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (user) {
|
if (user) {
|
||||||
console.log(user.demographicInformation);
|
// setShowDemographicInput(!user.demographicInformation || !user.demographicInformation.country || !user.demographicInformation.phone);
|
||||||
setShowDemographicInput(!user.demographicInformation || !user.demographicInformation.country || !user.demographicInformation.phone);
|
|
||||||
setShowDiagnostics(user.isFirstLogin && user.type === "student");
|
setShowDiagnostics(user.isFirstLogin && user.type === "student");
|
||||||
}
|
}
|
||||||
}, [user]);
|
}, [user]);
|
||||||
@@ -131,7 +131,13 @@ export default function Home({linkedCorporate}: Props) {
|
|||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
<Layout user={user} navDisabled>
|
<Layout user={user} navDisabled>
|
||||||
<DemographicInformationInput mutateUser={mutateUser} user={user} />
|
<DemographicInformationInput
|
||||||
|
mutateUser={(user) => {
|
||||||
|
setUser(user);
|
||||||
|
mutateUser(user);
|
||||||
|
}}
|
||||||
|
user={user}
|
||||||
|
/>
|
||||||
</Layout>
|
</Layout>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {DeveloperUser, Stat, StudentUser, User} from "@/interfaces/user";
|
|||||||
import {Module} from "@/interfaces";
|
import {Module} from "@/interfaces";
|
||||||
import {getCorporateUser} from "@/resources/user";
|
import {getCorporateUser} from "@/resources/user";
|
||||||
import {getUserCorporate} from "./groups.be";
|
import {getUserCorporate} from "./groups.be";
|
||||||
import { Db, ObjectId } from "mongodb";
|
import {Db, ObjectId} from "mongodb";
|
||||||
|
|
||||||
export const getExams = async (
|
export const getExams = async (
|
||||||
db: Db,
|
db: Db,
|
||||||
@@ -18,18 +18,18 @@ export const getExams = async (
|
|||||||
variant?: Variant,
|
variant?: Variant,
|
||||||
instructorGender?: InstructorGender,
|
instructorGender?: InstructorGender,
|
||||||
): Promise<Exam[]> => {
|
): Promise<Exam[]> => {
|
||||||
|
const allExams = await db
|
||||||
|
.collection(module)
|
||||||
|
.find<Exam>({
|
||||||
|
isDiagnostic: false,
|
||||||
|
})
|
||||||
|
.toArray();
|
||||||
|
|
||||||
const allExams = await db.collection(module).find<Exam>({
|
const shuffledPublicExams = shuffle(
|
||||||
isDiagnostic: false
|
allExams.map((doc) => ({
|
||||||
}).toArray();
|
...doc,
|
||||||
|
module,
|
||||||
const shuffledPublicExams = (
|
})) as Exam[],
|
||||||
shuffle(
|
|
||||||
allExams.map((doc) => ({
|
|
||||||
...doc,
|
|
||||||
module,
|
|
||||||
})) as Exam[],
|
|
||||||
)
|
|
||||||
).filter((x) => !x.private);
|
).filter((x) => !x.private);
|
||||||
|
|
||||||
let exams: Exam[] = await filterByOwners(shuffledPublicExams, userId);
|
let exams: Exam[] = await filterByOwners(shuffledPublicExams, userId);
|
||||||
@@ -39,9 +39,12 @@ export const getExams = async (
|
|||||||
exams = await filterByPreference(db, exams, module, userId);
|
exams = await filterByPreference(db, exams, module, userId);
|
||||||
|
|
||||||
if (avoidRepeated === "true") {
|
if (avoidRepeated === "true") {
|
||||||
const stats = await db.collection("stats").find<Stat>({
|
const stats = await db
|
||||||
user: userId
|
.collection("stats")
|
||||||
}).toArray();
|
.find<Stat>({
|
||||||
|
user: userId,
|
||||||
|
})
|
||||||
|
.toArray();
|
||||||
|
|
||||||
const filteredExams = exams.filter((x) => !stats.map((s) => s.exam).includes(x.id));
|
const filteredExams = exams.filter((x) => !stats.map((s) => s.exam).includes(x.id));
|
||||||
|
|
||||||
@@ -78,7 +81,7 @@ const filterByOwners = async (exams: Exam[], userID?: string) => {
|
|||||||
|
|
||||||
const filterByDifficulty = async (db: Db, exams: Exam[], module: Module, userID?: string) => {
|
const filterByDifficulty = async (db: Db, exams: Exam[], module: Module, userID?: string) => {
|
||||||
if (!userID) return exams;
|
if (!userID) return exams;
|
||||||
const user = await db.collection("users").findOne<User>({ _id: new ObjectId(userID) });
|
const user = await db.collection("users").findOne<User>({id: userID});
|
||||||
if (!user) return exams;
|
if (!user) return exams;
|
||||||
|
|
||||||
const difficulty = user.levels[module] <= 3 ? "easy" : user.levels[module] <= 6 ? "medium" : "hard";
|
const difficulty = user.levels[module] <= 3 ? "easy" : user.levels[module] <= 6 ? "medium" : "hard";
|
||||||
@@ -92,7 +95,7 @@ const filterByPreference = async (db: Db, exams: Exam[], module: Module, userID?
|
|||||||
|
|
||||||
if (!userID) return exams;
|
if (!userID) return exams;
|
||||||
|
|
||||||
const user = await db.collection("users").findOne<StudentUser | DeveloperUser>({ _id: new ObjectId(userID) });
|
const user = await db.collection("users").findOne<StudentUser | DeveloperUser>({id: userID});
|
||||||
if (!user) return exams;
|
if (!user) return exams;
|
||||||
|
|
||||||
if (!["developer", "student"].includes(user.type)) return exams;
|
if (!["developer", "student"].includes(user.type)) return exams;
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export async function getLinkedUsers(
|
|||||||
|
|
||||||
const participants = uniq([
|
const participants = uniq([
|
||||||
...adminGroups.flatMap((x) => x.participants),
|
...adminGroups.flatMap((x) => x.participants),
|
||||||
...groups.flat().flatMap((x) => x.participants),
|
...(userType === "mastercorporate" ? groups.flat().flatMap((x) => x.participants) : []),
|
||||||
...(userType === "teacher" ? belongingGroups.flatMap((x) => x.participants) : []),
|
...(userType === "teacher" ? belongingGroups.flatMap((x) => x.participants) : []),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user