Merge branch 'develop' into feature/exam-generation

This commit is contained in:
Tiago Ribeiro
2023-11-21 19:45:30 +00:00
16 changed files with 314 additions and 115 deletions

View File

@@ -105,12 +105,12 @@ export default function MobileMenu({isOpen, onClose, path, user}: Props) {
</Link>
{user.type !== "student" && (
<Link
href="/manage"
href="/settings"
className={clsx(
"transition ease-in-out duration-300 w-fit",
path === "/manage" && "text-mti-purple-light font-semibold border-b-2 border-b-mti-purple-light ",
path === "/settings" && "text-mti-purple-light font-semibold border-b-2 border-b-mti-purple-light ",
)}>
Management
Settings
</Link>
)}
<Link

View File

@@ -1,5 +1,6 @@
/* eslint-disable @next/next/no-img-element */
import {User} from "@/interfaces/user";
import {USER_TYPE_LABELS} from "@/resources/user";
import {calculateAverageLevel} from "@/utils/score";
import {capitalize} from "lodash";
import {ReactElement} from "react";
@@ -28,7 +29,7 @@ export default function ProfileSummary({user, items}: Props) {
<div className="flex -md:flex-col justify-between w-full gap-8">
<div className="flex flex-col gap-2 py-2">
<h1 className="font-bold text-2xl md:text-4xl">{user.name}</h1>
<h6 className="font-normal text-base text-mti-gray-taupe">{capitalize(user.type)}</h6>
<h6 className="font-normal text-base text-mti-gray-taupe">{USER_TYPE_LABELS[user.type]}</h6>
</div>
<ProgressBar
label={`Level ${calculateAverageLevel(user.levels).toFixed(1)}`}

View File

@@ -93,9 +93,9 @@ export default function Sidebar({path, navDisabled = false, focusMode = false, u
<Nav
disabled={disableNavigation}
Icon={BsShieldFill}
label="Management"
label="Settings"
path={path}
keyPath="/manage"
keyPath="/settings"
isMinimized={isMinimized}
/>
)}
@@ -117,7 +117,7 @@ export default function Sidebar({path, navDisabled = false, focusMode = false, u
<Nav disabled={disableNavigation} Icon={BsGraphUp} label="Stats" path={path} keyPath="/stats" isMinimized={true} />
<Nav disabled={disableNavigation} Icon={BsClockHistory} label="Record" path={path} keyPath="/record" isMinimized={true} />
{userType !== "student" && (
<Nav disabled={disableNavigation} Icon={BsShieldFill} label="Management" path={path} keyPath="/manage" isMinimized={true} />
<Nav disabled={disableNavigation} Icon={BsShieldFill} label="Settings" path={path} keyPath="/settings" isMinimized={true} />
)}
{userType === "developer" && (
<Nav disabled={disableNavigation} Icon={BsCloudFill} label="Generation" path={path} keyPath="/generation" isMinimized={true} />

View File

@@ -6,7 +6,7 @@ import axios from "axios";
import clsx from "clsx";
import moment from "moment";
import {Divider} from "primereact/divider";
import {useState} from "react";
import {useEffect, useState} from "react";
import ReactDatePicker from "react-datepicker";
import {BsFileEarmarkText, BsPencil, BsStar} from "react-icons/bs";
import {toast} from "react-toastify";
@@ -17,6 +17,7 @@ import Input from "./Low/Input";
import ProfileSummary from "./ProfileSummary";
import Select from "react-select";
import useUsers from "@/hooks/useUsers";
import {USER_TYPE_LABELS} from "@/resources/user";
const expirationDateColor = (date: Date) => {
const momentDate = moment(date);
@@ -40,15 +41,46 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers}:
const [referralAgent, setReferralAgent] = useState(user.corporateInformation?.referralAgent);
const [type, setType] = useState(user.type);
const [status, setStatus] = useState(user.status);
const [companyName, setCompanyName] = useState(user.corporateInformation?.companyInformation.name);
const [userAmount, setUserAmount] = useState(user.corporateInformation?.companyInformation.userAmount);
const [referralAgentLabel, setReferralAgentLabel] = useState<string>();
const {stats} = useStats(user.id);
const {users} = useUsers();
useEffect(() => {
if (users && users.length > 0) {
if (!referralAgent) {
setReferralAgentLabel("No manager");
return;
}
const agent = users.find((x) => x.id === referralAgent);
setReferralAgentLabel(`${agent?.name} - ${agent?.email}`);
}
}, [users, referralAgent]);
const updateUser = () => {
if (!confirm(`Are you sure you want to update ${user.name}'s account?`)) return;
// TODO: Add the corporate information when it is changed as well
axios
.post<{user?: User; ok?: boolean}>(`/api/users/update?id=${user.id}`, {...user, subscriptionExpirationDate: expiryDate, type, status})
.post<{user?: User; ok?: boolean}>(`/api/users/update?id=${user.id}`, {
...user,
subscriptionExpirationDate: expiryDate,
type,
status,
corporateInformation:
type === "corporate"
? {
referralAgent,
companyInformation: {
companyName,
userAmount,
},
}
: undefined,
})
.then(() => {
toast.success("User updated successfully!");
onClose(true);
@@ -255,12 +287,11 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers}:
defaultValue={user.type}
onChange={(e) => setType(e.target.value as typeof user.type)}
className="p-6 w-full min-h-[70px] flex justify-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer bg-white">
<option value="student">Student</option>
<option value="teacher">Teacher</option>
<option value="corporate">Corporate</option>
<option value="agent">Country Agent</option>
<option value="admin">Admin</option>
<option value="developer">Developer</option>
{Object.keys(USER_TYPE_LABELS).map((type) => (
<option key={type} value={type}>
{USER_TYPE_LABELS[type as keyof typeof USER_TYPE_LABELS]}
</option>
))}
</select>
</div>
</div>
@@ -269,54 +300,60 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers}:
{user.type === "corporate" && (
<>
<Divider className="w-full" />
<div className="flex flex-col md:flex-row gap-8 w-full">
<div className="grid grid-cols-2 gap-8 w-full">
<Input
label="Company Name"
type="text"
name="companyName"
onChange={() => null}
onChange={setCompanyName}
placeholder="Enter company name"
defaultValue={user.corporateInformation?.companyInformation.name}
defaultValue={companyName}
/>
<Input
label="Amount of Users"
type="number"
name="userAmount"
onChange={() => null}
onChange={(e) => setUserAmount(e ? parseInt(e) : undefined)}
placeholder="Enter amount of users"
defaultValue={user.corporateInformation?.companyInformation.userAmount}
defaultValue={userAmount}
/>
<div className="flex flex-col gap-3 w-full">
<label className="font-normal text-base text-mti-gray-dim">Country Agent</label>
<Select
className="px-4 py-4 w-full 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"
options={[
{value: "", label: "No referral"},
...users.filter((u) => u.type === "agent").map((x) => ({value: x.id, label: `${x.name} - ${x.email}`})),
]}
defaultValue={{
value: referralAgent,
label: referralAgent ? users.find((u) => u.id === referralAgent)?.name || "" : "No agent",
}}
onChange={(value) => setReferralAgent(value?.value)}
styles={{
control: (styles) => ({
...styles,
paddingLeft: "4px",
border: "none",
outline: "none",
":focus": {
<label className="font-normal text-base text-mti-gray-dim">Country Manager</label>
{referralAgentLabel && (
<Select
className="px-4 py-4 w-full 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"
options={[
{value: "", label: "No referral"},
...users.filter((u) => u.type === "agent").map((x) => ({value: x.id, label: `${x.name} - ${x.email}`})),
]}
defaultValue={{
value: referralAgent,
label: referralAgentLabel,
}}
onChange={(value) => setReferralAgent(value?.value)}
styles={{
control: (styles) => ({
...styles,
paddingLeft: "4px",
border: "none",
outline: "none",
},
}),
option: (styles, state) => ({
...styles,
backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white",
color: state.isFocused ? "black" : styles.color,
}),
}}
/>
":focus": {
outline: "none",
},
}),
option: (styles, state) => ({
...styles,
backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white",
color: state.isFocused ? "black" : styles.color,
}),
}}
/>
)}
</div>
<div className="flex flex-col gap-3 w-full">
<label className="font-normal text-base text-mti-gray-dim">Pricing</label>
</div>
</div>
</>