| @@ -8,7 +8,7 @@ export const metadata: Metadata = { | |||
| title: "Edit User Group", | |||
| }; | |||
| const Positions: React.FC = async () => { | |||
| const Group: React.FC = async () => { | |||
| const { t } = await getServerI18n("group"); | |||
| // Preload necessary dependencies | |||
| @@ -23,4 +23,4 @@ const Positions: React.FC = async () => { | |||
| ); | |||
| }; | |||
| export default Positions; | |||
| export default Group; | |||
| @@ -22,7 +22,7 @@ import { CreateProjectInputs, saveProject } from "@/app/api/projects/actions"; | |||
| import { Error } from "@mui/icons-material"; | |||
| import { ProjectCategory } from "@/app/api/projects"; | |||
| import { Grid, Typography } from "@mui/material"; | |||
| import CreateStaffForm from "@/components/CreateStaff/CreateStaff"; | |||
| import CreateStaff from "@/components/CreateStaff"; | |||
| interface CreateCustomInputs { | |||
| projectCode: string; | |||
| @@ -31,23 +31,17 @@ interface CreateCustomInputs { | |||
| // const Title = ["title1", "title2"]; | |||
| const CreateStaff: React.FC = async () => { | |||
| const CreateStaffPage: React.FC = async () => { | |||
| const { t } = await getServerI18n("staff"); | |||
| const title = ['', t('Additional Info')] | |||
| // const regex = new RegExp("^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$") | |||
| // console.log(regex) | |||
| return ( | |||
| <> | |||
| <Typography variant="h4">{t("Create Staff")}</Typography> | |||
| <I18nProvider namespaces={["staff"]}> | |||
| <CreateStaffForm | |||
| Title={title} | |||
| /> | |||
| <CreateStaff/> | |||
| </I18nProvider> | |||
| </> | |||
| ); | |||
| }; | |||
| export default CreateStaff; | |||
| export default CreateStaffPage; | |||
| @@ -15,6 +15,8 @@ export interface combo { | |||
| } | |||
| export interface CreatePositionInputs { | |||
| positionCode: string; | |||
| positionName: string; | |||
| code: string; | |||
| name: string; | |||
| description: string; | |||
| @@ -11,6 +11,12 @@ export interface UserInputs { | |||
| email: string; | |||
| } | |||
| export interface PasswordInputs { | |||
| password: string; | |||
| newPassword: string; | |||
| newPasswordCheck: string; | |||
| } | |||
| export const fetchUserDetails = cache(async (id: number) => { | |||
| return serverFetchJson<UserDetail>(`${BASE_API_URL}/user/${id}`, { | |||
| @@ -31,4 +37,12 @@ export const deleteUser = async (id: number) => { | |||
| method: "DELETE", | |||
| headers: { "Content-Type": "application/json" }, | |||
| }); | |||
| }; | |||
| export const changePassword = async (data: any) => { | |||
| return serverFetchJson(`${BASE_API_URL}/user/change-password`, { | |||
| method: "PATCH", | |||
| body: JSON.stringify(data), | |||
| headers: { "Content-Type": "application/json" }, | |||
| }); | |||
| }; | |||
| @@ -10,6 +10,7 @@ import Divider from "@mui/material/Divider"; | |||
| import Typography from "@mui/material/Typography"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { signOut } from "next-auth/react"; | |||
| import { useRouter } from "next/navigation"; | |||
| type Props = Pick<AppBarProps, "avatarImageSrc" | "profileName">; | |||
| @@ -26,6 +27,7 @@ const Profile: React.FC<Props> = ({ avatarImageSrc, profileName }) => { | |||
| }; | |||
| const { t } = useTranslation("login"); | |||
| const router = useRouter(); | |||
| return ( | |||
| <> | |||
| @@ -52,6 +54,7 @@ const Profile: React.FC<Props> = ({ avatarImageSrc, profileName }) => { | |||
| {profileName} | |||
| </Typography> | |||
| <Divider /> | |||
| <MenuItem onClick={() => {router.replace("/settings/changepassword")}}>{t("Change Password")}</MenuItem> | |||
| <MenuItem onClick={() => signOut()}>{t("Sign out")}</MenuItem> | |||
| </Menu> | |||
| </> | |||
| @@ -22,7 +22,6 @@ import { fetchSkillCombo } from "@/app/api/skill/actions"; | |||
| import { fetchSalaryCombo } from "@/app/api/salarys/actions"; | |||
| interface Field { | |||
| // subtitle: string; | |||
| id: string; | |||
| label: string; | |||
| type: string; | |||
| @@ -33,12 +32,6 @@ interface Field { | |||
| options?: any[]; | |||
| readOnly?: boolean; | |||
| } | |||
| interface formProps { | |||
| Title?: string[]; | |||
| // fieldLists: Field[][]; | |||
| } | |||
| export interface comboItem { | |||
| company: comboProp[]; | |||
| team: comboProp[]; | |||
| @@ -49,101 +42,14 @@ export interface comboItem { | |||
| salary: comboProp[]; | |||
| } | |||
| const CreateStaff: React.FC<formProps> = ({ Title }) => { | |||
| // const router = useRouter(); | |||
| const { t } = useTranslation(); | |||
| const [companyCombo, setCompanyCombo] = useState<comboProp[]>(); | |||
| const [teamCombo, setTeamCombo] = useState<comboProp[]>(); | |||
| const [departmentCombo, setDepartmentCombo] = useState<comboProp[]>(); | |||
| const [positionCombo, setPositionCombo] = useState<comboProp[]>(); | |||
| const [gradeCombo, setGradeCombo] = useState<comboProp[]>(); | |||
| const [skillCombo, setSkillCombo] = useState<comboProp[]>(); | |||
| const [salaryCombo, setSalaryCombo] = useState<comboProp[]>(); | |||
| // const [serverError, setServerError] = useState(""); | |||
| let comboItem: comboItem = { | |||
| company: [], | |||
| team: [], | |||
| department: [], | |||
| position: [], | |||
| grade: [], | |||
| skill: [], | |||
| salary: [], | |||
| }; | |||
| const fetchCompany = async () => { | |||
| await fetchCompanyCombo().then((data) => { | |||
| if (data) setCompanyCombo(data.records); | |||
| }); | |||
| } | |||
| const fetchTeam = async () => { | |||
| await fetchTeamCombo().then((data) => { | |||
| if (data) setTeamCombo(data.records); | |||
| }); | |||
| } | |||
| const fetchDepartment = async () => { | |||
| await fetchDepartmentCombo().then((data) => { | |||
| if (data) setDepartmentCombo(data.records); | |||
| }); | |||
| } | |||
| const fetchPosition = async () => { | |||
| await fetchPositionCombo().then((data) => { | |||
| if (data) setPositionCombo(data.records); | |||
| }); | |||
| } | |||
| const fetchGrade = async () => { | |||
| await fetchGradeCombo().then((data) => { | |||
| if (data) setGradeCombo(data.records); | |||
| }); | |||
| } | |||
| const fetchSkill = async () => { | |||
| await fetchSkillCombo().then((data) => { | |||
| if (data) setSkillCombo(data.records); | |||
| }); | |||
| } | |||
| const fetchSalary = async () => { | |||
| await fetchSalaryCombo().then((data) => { | |||
| if (data) setSalaryCombo(data.records); | |||
| }); | |||
| } | |||
| useEffect(() => { | |||
| fetchCompany() | |||
| fetchTeam() | |||
| fetchDepartment() | |||
| fetchPosition() | |||
| fetchGrade() | |||
| fetchSkill() | |||
| fetchSalary() | |||
| }, []); | |||
| useEffect(() => { | |||
| if(!companyCombo) | |||
| fetchCompany() | |||
| if(!teamCombo) | |||
| fetchTeam() | |||
| if(!departmentCombo) | |||
| fetchDepartment() | |||
| if(!positionCombo) | |||
| fetchPosition() | |||
| if(!gradeCombo) | |||
| fetchGrade() | |||
| if(!skillCombo) | |||
| fetchSkill() | |||
| if(!salaryCombo) | |||
| fetchSalary() | |||
| interface formProps { | |||
| Title?: string[]; | |||
| combos: comboItem; | |||
| } | |||
| }, [companyCombo, teamCombo, departmentCombo, positionCombo, gradeCombo, skillCombo, salaryCombo]); | |||
| // useEffect(() => { | |||
| // console.log(companyCombo) | |||
| // }, [companyCombo]); | |||
| const CreateStaff: React.FC<formProps> = ({ Title, combos }) => { | |||
| const { t } = useTranslation(); | |||
| const fieldLists: Field[][] = [ | |||
| [ | |||
| @@ -163,49 +69,49 @@ const CreateStaff: React.FC<formProps> = ({ Title }) => { | |||
| id: "companyId", | |||
| label: t("Company"), | |||
| type: "combo-Obj", | |||
| options: companyCombo || [], | |||
| options: combos.company || [], | |||
| required: true, | |||
| }, | |||
| { | |||
| id: "teamId", | |||
| label: t("Team"), | |||
| type: "combo-Obj", | |||
| options: teamCombo || [], | |||
| options: combos.team || [], | |||
| required: false, | |||
| }, | |||
| { | |||
| id: "departmentId", | |||
| label: t("Department"), | |||
| type: "combo-Obj", | |||
| options: departmentCombo || [], | |||
| options: combos.department || [], | |||
| required: true, | |||
| }, | |||
| { | |||
| id: "gradeId", | |||
| label: t("Grade"), | |||
| type: "combo-Obj", | |||
| options: gradeCombo || [], | |||
| options: combos.grade || [], | |||
| required: false, | |||
| }, | |||
| { | |||
| id: "skillSetId", | |||
| label: t("Skillset"), | |||
| type: "multiSelect-Obj", | |||
| options: skillCombo || [], | |||
| options: combos.skill || [], | |||
| required: false, | |||
| }, | |||
| { | |||
| id: "currentPositionId", | |||
| label: t("Current Position"), | |||
| type: "combo-Obj", | |||
| options: positionCombo || [], | |||
| options: combos.position || [], | |||
| required: true, | |||
| }, | |||
| { | |||
| id: "salaryId", | |||
| label: t("Salary Point"), | |||
| type: "combo-Obj", | |||
| options: salaryCombo || [], | |||
| options: combos.salary || [], | |||
| required: true, | |||
| }, | |||
| // { | |||
| @@ -279,7 +185,7 @@ const CreateStaff: React.FC<formProps> = ({ Title }) => { | |||
| id: "joinPositionId", | |||
| label: t("Join Position"), | |||
| type: "combo-Obj", | |||
| options: positionCombo || [], | |||
| options: combos.position || [], | |||
| required: true, | |||
| }, | |||
| { | |||
| @@ -1,17 +1,48 @@ | |||
| import React from "react"; | |||
| import CreateStaff from "./CreateStaff"; | |||
| import CreateStaff, { comboItem } from "./CreateStaff"; | |||
| import CreateStaffLoading from "./CreateStaffLoading"; | |||
| import { fetchStaff, fetchTeamLeads } from "@/app/api/staff"; | |||
| import { useSearchParams } from "next/navigation"; | |||
| import { fetchTeamCombo } from "@/app/api/team/actions"; | |||
| import { fetchDepartmentCombo } from "@/app/api/departments/actions"; | |||
| import { fetchPositionCombo } from "@/app/api/positions/actions"; | |||
| import { fetchGradeCombo } from "@/app/api/grades/actions"; | |||
| import { fetchSkillCombo } from "@/app/api/skill/actions"; | |||
| import { fetchSalaryCombo } from "@/app/api/salarys/actions"; | |||
| import { fetchCompanyCombo } from "@/app/api/companys/actions"; | |||
| interface SubComponents { | |||
| Loading: typeof CreateStaffLoading; | |||
| } | |||
| const CreateStaffWrapper: React.FC & SubComponents = async () => { | |||
| const [ | |||
| CompanyCombo, | |||
| TeamCombo, | |||
| DepartmentCombo, | |||
| PositionCombo, | |||
| GradeCombo, | |||
| SkillCombo, | |||
| SalaryCombo, | |||
| ] = await Promise.all([ | |||
| fetchCompanyCombo(), | |||
| fetchTeamCombo(), | |||
| fetchDepartmentCombo(), | |||
| fetchPositionCombo(), | |||
| fetchGradeCombo(), | |||
| fetchSkillCombo(), | |||
| fetchSalaryCombo(), | |||
| ]); | |||
| const combos: comboItem = { | |||
| company: CompanyCombo.records, | |||
| team: TeamCombo.records, | |||
| department: DepartmentCombo.records, | |||
| position: PositionCombo.records, | |||
| grade: GradeCombo.records, | |||
| skill: SkillCombo.records, | |||
| salary: SalaryCombo.records, | |||
| } | |||
| return <CreateStaff/>; | |||
| return <CreateStaff combos={combos}/>; | |||
| }; | |||
| CreateStaffWrapper.Loading = CreateStaffLoading; | |||
| @@ -83,7 +83,7 @@ const EditStaffForm: React.FC<formProps> = ({ Title, fieldLists }) => { | |||
| }; | |||
| return ( | |||
| <> | |||
| {serverError && ( | |||
| {serverError && ( | |||
| <Typography variant="body2" color="error" alignSelf="flex-end"> | |||
| {serverError} | |||
| </Typography> | |||
| @@ -0,0 +1,164 @@ | |||
| "use client"; | |||
| import { useRouter, useSearchParams } from "next/navigation"; | |||
| import { useCallback, useEffect, useMemo, useState } from "react"; | |||
| import SearchResults, { Column } from "../SearchResults"; | |||
| // import { TeamResult } from "@/app/api/team"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { | |||
| Button, | |||
| Card, | |||
| CardContent, | |||
| Grid, | |||
| Stack, | |||
| Tab, | |||
| Tabs, | |||
| TabsProps, | |||
| TextField, | |||
| Typography, | |||
| } from "@mui/material"; | |||
| import { | |||
| FieldErrors, | |||
| FormProvider, | |||
| SubmitErrorHandler, | |||
| SubmitHandler, | |||
| useForm, | |||
| useFormContext, | |||
| } from "react-hook-form"; | |||
| import { Check, Close, Error, RestartAlt } from "@mui/icons-material"; | |||
| import { StaffResult } from "@/app/api/staff"; | |||
| import { editUser, fetchUserDetails } from "@/app/api/user/actions"; | |||
| import UserDetail from "./UserDetail"; | |||
| import { UserResult } from "@/app/api/user"; | |||
| interface Props { | |||
| // users: UserResult[] | |||
| } | |||
| const EditUser: React.FC<Props> = async ({ }) => { | |||
| const { t } = useTranslation(); | |||
| const formProps = useForm<UserResult>(); | |||
| const searchParams = useSearchParams(); | |||
| const id = parseInt(searchParams.get("id") || "0"); | |||
| const [tabIndex, setTabIndex] = useState(0); | |||
| const router = useRouter(); | |||
| const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>( | |||
| (_e, newValue) => { | |||
| setTabIndex(newValue); | |||
| }, | |||
| [] | |||
| ); | |||
| const [serverError, setServerError] = useState(""); | |||
| const [data, setData] = useState<UserResult>(); | |||
| const fetchUserDetail = async () => { | |||
| console.log(id); | |||
| try { | |||
| const userDetail = await fetchUserDetails(id); | |||
| console.log(userDetail); | |||
| const _data = userDetail.data as UserResult; | |||
| console.log(_data); | |||
| setData(_data); | |||
| formProps.reset({ | |||
| username: _data.username, | |||
| firstname: _data.firstname, | |||
| lastname: _data.lastname, | |||
| title: _data.title, | |||
| department: _data.department, | |||
| email: _data.email, | |||
| phone1: _data.phone1, | |||
| phone2: _data.phone2, | |||
| remarks: _data.remarks, | |||
| }); | |||
| } catch (error) { | |||
| console.log(error); | |||
| setServerError(t("An error has occurred. Please try again later.")); | |||
| } | |||
| }; | |||
| useEffect(() => { | |||
| fetchUserDetail(); | |||
| }, []); | |||
| const hasErrorsInTab = ( | |||
| tabIndex: number, | |||
| errors: FieldErrors<UserResult> | |||
| ) => { | |||
| switch (tabIndex) { | |||
| case 0: | |||
| return Object.keys(errors).length > 0; | |||
| default: | |||
| false; | |||
| } | |||
| }; | |||
| const handleCancel = () => { | |||
| router.back(); | |||
| }; | |||
| const onSubmit = useCallback<SubmitHandler<UserResult>>( | |||
| async (data) => { | |||
| try { | |||
| console.log(data); | |||
| const tempData = { | |||
| username: data.username, | |||
| email: data.email, | |||
| locked: false | |||
| } | |||
| console.log(tempData); | |||
| await editUser(id, tempData); | |||
| router.replace("/settings/staff"); | |||
| } catch (e) { | |||
| console.log(e); | |||
| setServerError(t("An error has occurred. Please try again later.")); | |||
| } | |||
| }, | |||
| [router] | |||
| ); | |||
| const onSubmitError = useCallback<SubmitErrorHandler<UserResult>>( | |||
| (errors) => { | |||
| console.log(errors); | |||
| }, | |||
| [] | |||
| ); | |||
| return ( | |||
| <> | |||
| {serverError && ( | |||
| <Typography variant="body2" color="error" alignSelf="flex-end"> | |||
| {serverError} | |||
| </Typography> | |||
| )} | |||
| <FormProvider {...formProps}> | |||
| <Stack | |||
| spacing={2} | |||
| component="form" | |||
| onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)} | |||
| > | |||
| <UserDetail data={data!!} /> | |||
| <Stack direction="row" justifyContent="flex-end" gap={1}> | |||
| <Button | |||
| variant="text" | |||
| startIcon={<RestartAlt />} | |||
| // onClick={() => console.log("asdasd")} | |||
| > | |||
| {t("Reset")} | |||
| </Button> | |||
| <Button | |||
| variant="outlined" | |||
| startIcon={<Close />} | |||
| onClick={handleCancel} | |||
| > | |||
| {t("Cancel")} | |||
| </Button> | |||
| <Button variant="contained" startIcon={<Check />} type="submit"> | |||
| {t("Confirm")} | |||
| </Button> | |||
| </Stack> | |||
| </Stack> | |||
| </FormProvider> | |||
| </> | |||
| ); | |||
| }; | |||
| export default EditUser; | |||
| @@ -0,0 +1,40 @@ | |||
| import Card from "@mui/material/Card"; | |||
| import CardContent from "@mui/material/CardContent"; | |||
| import Skeleton from "@mui/material/Skeleton"; | |||
| import Stack from "@mui/material/Stack"; | |||
| import React from "react"; | |||
| // Can make this nicer | |||
| export const EditUserLoading: React.FC = () => { | |||
| return ( | |||
| <> | |||
| <Card> | |||
| <CardContent> | |||
| <Stack spacing={2}> | |||
| <Skeleton variant="rounded" height={60} /> | |||
| <Skeleton variant="rounded" height={60} /> | |||
| <Skeleton variant="rounded" height={60} /> | |||
| <Skeleton | |||
| variant="rounded" | |||
| height={50} | |||
| width={100} | |||
| sx={{ alignSelf: "flex-end" }} | |||
| /> | |||
| </Stack> | |||
| </CardContent> | |||
| </Card> | |||
| <Card>EditUser | |||
| <CardContent> | |||
| <Stack spacing={2}> | |||
| <Skeleton variant="rounded" height={40} /> | |||
| <Skeleton variant="rounded" height={40} /> | |||
| <Skeleton variant="rounded" height={40} /> | |||
| <Skeleton variant="rounded" height={40} /> | |||
| </Stack> | |||
| </CardContent> | |||
| </Card> | |||
| </> | |||
| ); | |||
| }; | |||
| export default EditUserLoading; | |||
| @@ -0,0 +1,23 @@ | |||
| import React from "react"; | |||
| import EditUser from "./EditUser"; | |||
| import EditUserLoading from "./EditUserLoading"; | |||
| // import { fetchTeam, fetchTeamLeads } from "@/app/api/Team"; | |||
| import { useSearchParams } from "next/navigation"; | |||
| import { fetchTeam, fetchTeamDetail } from "@/app/api/team"; | |||
| import { fetchStaff } from "@/app/api/staff"; | |||
| import { fetchUser } from "@/app/api/user"; | |||
| interface SubComponents { | |||
| Loading: typeof EditUserLoading; | |||
| } | |||
| const EditUserWrapper: React.FC & SubComponents = async () => { | |||
| // const users = await fetchUser() | |||
| // console.log(users) | |||
| return <EditUser />; | |||
| }; | |||
| EditUserWrapper.Loading = EditUserLoading; | |||
| export default EditUserWrapper; | |||
| @@ -0,0 +1,136 @@ | |||
| "use client"; | |||
| import { UserResult } from "@/app/api/user"; | |||
| import { | |||
| Card, | |||
| CardContent, | |||
| Grid, | |||
| Stack, | |||
| TextField, | |||
| Typography, | |||
| } from "@mui/material"; | |||
| import { useFormContext } from "react-hook-form"; | |||
| import { useTranslation } from "react-i18next"; | |||
| interface Props { | |||
| data: UserResult | |||
| } | |||
| const UserDetail: React.FC<Props> = ({ | |||
| data | |||
| }) => { | |||
| const { t } = useTranslation(); | |||
| const { | |||
| register, | |||
| formState: { errors }, | |||
| control, | |||
| } = useFormContext<UserResult>(); | |||
| return ( | |||
| <Card> | |||
| <CardContent component={Stack} spacing={4}> | |||
| <Typography variant="overline" display="block" marginBlockEnd={1}> | |||
| {t("User Detail")} | |||
| </Typography> | |||
| <Grid container spacing={2} columns={{ xs: 6, sm: 12 }}> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("username")} | |||
| fullWidth | |||
| {...register("username", { | |||
| required: "username required!", | |||
| })} | |||
| error={Boolean(errors.name)} | |||
| /> | |||
| </Grid> | |||
| {/* <Grid item xs={6}> | |||
| <TextField | |||
| label={t("First Name")} | |||
| fullWidth | |||
| {...register("firstname", { | |||
| required: "Name required!", | |||
| })} | |||
| error={Boolean(errors.firstname)} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("Last Name")} | |||
| fullWidth | |||
| {...register("lastname", { | |||
| required: "Name required!", | |||
| })} | |||
| error={Boolean(errors.lastname)} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("title")} | |||
| fullWidth | |||
| {...register("title", { | |||
| required: "title required!", | |||
| })} | |||
| error={Boolean(errors.title)} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("department")} | |||
| fullWidth | |||
| {...register("department", { | |||
| required: "department required!", | |||
| })} | |||
| error={Boolean(errors.department)} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("email")} | |||
| fullWidth | |||
| {...register("email", { | |||
| required: "email required!", | |||
| })} | |||
| error={Boolean(errors.email)} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("phone1")} | |||
| fullWidth | |||
| {...register("phone1", { | |||
| required: "phone1 required!", | |||
| })} | |||
| error={Boolean(errors.phone1)} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("phone2")} | |||
| fullWidth | |||
| {...register("phone2", { | |||
| required: "phone2 required!", | |||
| })} | |||
| error={Boolean(errors.phone2)} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={12}> | |||
| <TextField | |||
| label={t("remarks")} | |||
| fullWidth | |||
| multiline | |||
| rows={4} | |||
| variant="filled" | |||
| {...register("remarks", { | |||
| required: "remarks required!", | |||
| })} | |||
| error={Boolean(errors.remarks)} | |||
| /> | |||
| </Grid> */} | |||
| </Grid> | |||
| </CardContent> | |||
| </Card> | |||
| ); | |||
| }; | |||
| export default UserDetail; | |||
| @@ -0,0 +1 @@ | |||
| export { default } from "./EditUserWrapper"; | |||
| @@ -14,14 +14,11 @@ const EditUserGroupWrapper: React.FC & SubComponents = async () => { | |||
| const [ | |||
| groups, | |||
| // auths, | |||
| users, | |||
| ] = await Promise.all([ | |||
| fetchGroup(), | |||
| // fetchAuth(), | |||
| fetchUser(), | |||
| ]); | |||
| console.log(users) | |||
| return <EditUserGroup groups={groups.records} users={users}/>; | |||
| }; | |||
| @@ -9,6 +9,7 @@ import DeleteIcon from "@mui/icons-material/Delete"; | |||
| import { deleteStaff } from "@/app/api/staff/actions"; | |||
| import { useRouter } from "next/navigation"; | |||
| import { deleteDialog, successDialog } from "../Swal/CustomAlerts"; | |||
| import Person from '@mui/icons-material/Person'; | |||
| interface Props { | |||
| staff: StaffResult[]; | |||
| @@ -65,6 +66,14 @@ const StaffSearch: React.FC<Props> = ({ staff }) => { | |||
| [router, t] | |||
| ); | |||
| const onUserClick = useCallback( | |||
| (staff: StaffResult) => { | |||
| console.log(staff); | |||
| router.push(`/settings/staff/user?id=${staff.id}`); | |||
| }, | |||
| [router, t] | |||
| ); | |||
| const deleteClick = useCallback((staff: StaffResult) => { | |||
| deleteDialog(async () => { | |||
| await deleteStaff(staff.id); | |||
| @@ -81,6 +90,12 @@ const StaffSearch: React.FC<Props> = ({ staff }) => { | |||
| onClick: onStaffClick, | |||
| buttonIcon: <EditNote />, | |||
| }, | |||
| { | |||
| name: "id", | |||
| label: t("Actions"), | |||
| onClick: onUserClick, | |||
| buttonIcon: <Person />, | |||
| }, | |||
| { name: "team", label: t("Team") }, | |||
| { name: "name", label: t("Staff Name") }, | |||
| { name: "staffId", label: t("Staff ID") }, | |||
| @@ -71,9 +71,6 @@ export default async function middleware( | |||
| return response; | |||
| } | |||
| // const session = await getServerSession(authOptions); | |||
| // console.log(session); | |||
| let abilities: string[] = [] | |||
| if (token) { | |||
| abilities = (token.abilities as ability[]).map((item: ability) => item.actionSubjectCombo); | |||
| @@ -93,6 +90,9 @@ export default async function middleware( | |||
| if (req.nextUrl.pathname.startsWith('/settings/user')) { | |||
| isAuth = [MAINTAIN_USER, VIEW_USER].some((ability) => abilities.includes(ability)); | |||
| } | |||
| if (req.nextUrl.pathname.startsWith('/settings/staff/user')) { | |||
| isAuth = [MAINTAIN_USER, VIEW_USER].some((ability) => abilities.includes(ability)); | |||
| } | |||
| if (req.nextUrl.pathname.startsWith('/analytics')) { | |||
| isAuth = [GENERATE_REPORTS].some((ability) => abilities.includes(ability)); | |||
| } | |||
| @@ -104,40 +104,6 @@ export default async function middleware( | |||
| } | |||
| }); | |||
| // for (const obj of abilities) { | |||
| // switch (obj.actionSubjectCombo.toLowerCase()) { | |||
| // case "maintain_user": | |||
| // // appendRoutes(settings) | |||
| // break; | |||
| // case "maintain_group": | |||
| // // appendRoutes("/testing-maintain_user") | |||
| // break; | |||
| // case "view_user": | |||
| // // appendRoutes("/testing-maintain_user") | |||
| // break; | |||
| // case "view_group": | |||
| // // appendRoutes("/testing-maintain_user") | |||
| // break; | |||
| // } | |||
| // } | |||
| // console.log("TESTING_ROUTES: ") | |||
| // console.log(TESTING_ROUTES) | |||
| // TESTING_ROUTES.some((route) => { | |||
| // if (req.nextUrl.pathname.startsWith(route)) { | |||
| // console.log("////////////////start//////////////// ") | |||
| // console.log("TESTING_ROUTES:") | |||
| // console.log("route:") | |||
| // console.log(route) | |||
| // console.log("pathname:") | |||
| // console.log(req.nextUrl.pathname) | |||
| // console.log("////////////////end////////////////") | |||
| // } | |||
| // return (req.nextUrl.pathname.startsWith(route)) | |||
| // }) | |||
| // Matcher for using the auth middleware | |||
| return PRIVATE_ROUTES.some((route) => req.nextUrl.pathname.startsWith(route)) | |||
| ? await authMiddleware(req, event) // Let auth middleware handle response | |||