@@ -8,7 +8,7 @@ export const metadata: Metadata = { | |||||
title: "Edit User Group", | title: "Edit User Group", | ||||
}; | }; | ||||
const Positions: React.FC = async () => { | |||||
const Group: React.FC = async () => { | |||||
const { t } = await getServerI18n("group"); | const { t } = await getServerI18n("group"); | ||||
// Preload necessary dependencies | // 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 { Error } from "@mui/icons-material"; | ||||
import { ProjectCategory } from "@/app/api/projects"; | import { ProjectCategory } from "@/app/api/projects"; | ||||
import { Grid, Typography } from "@mui/material"; | import { Grid, Typography } from "@mui/material"; | ||||
import CreateStaffForm from "@/components/CreateStaff/CreateStaff"; | |||||
import CreateStaff from "@/components/CreateStaff"; | |||||
interface CreateCustomInputs { | interface CreateCustomInputs { | ||||
projectCode: string; | projectCode: string; | ||||
@@ -31,23 +31,17 @@ interface CreateCustomInputs { | |||||
// const Title = ["title1", "title2"]; | // const Title = ["title1", "title2"]; | ||||
const CreateStaff: React.FC = async () => { | |||||
const CreateStaffPage: React.FC = async () => { | |||||
const { t } = await getServerI18n("staff"); | 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 ( | return ( | ||||
<> | <> | ||||
<Typography variant="h4">{t("Create Staff")}</Typography> | <Typography variant="h4">{t("Create Staff")}</Typography> | ||||
<I18nProvider namespaces={["staff"]}> | <I18nProvider namespaces={["staff"]}> | ||||
<CreateStaffForm | |||||
Title={title} | |||||
/> | |||||
<CreateStaff/> | |||||
</I18nProvider> | </I18nProvider> | ||||
</> | </> | ||||
); | ); | ||||
}; | }; | ||||
export default CreateStaff; | |||||
export default CreateStaffPage; |
@@ -15,6 +15,8 @@ export interface combo { | |||||
} | } | ||||
export interface CreatePositionInputs { | export interface CreatePositionInputs { | ||||
positionCode: string; | |||||
positionName: string; | |||||
code: string; | code: string; | ||||
name: string; | name: string; | ||||
description: string; | description: string; | ||||
@@ -11,6 +11,12 @@ export interface UserInputs { | |||||
email: string; | email: string; | ||||
} | } | ||||
export interface PasswordInputs { | |||||
password: string; | |||||
newPassword: string; | |||||
newPasswordCheck: string; | |||||
} | |||||
export const fetchUserDetails = cache(async (id: number) => { | export const fetchUserDetails = cache(async (id: number) => { | ||||
return serverFetchJson<UserDetail>(`${BASE_API_URL}/user/${id}`, { | return serverFetchJson<UserDetail>(`${BASE_API_URL}/user/${id}`, { | ||||
@@ -31,4 +37,12 @@ export const deleteUser = async (id: number) => { | |||||
method: "DELETE", | method: "DELETE", | ||||
headers: { "Content-Type": "application/json" }, | 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 Typography from "@mui/material/Typography"; | ||||
import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
import { signOut } from "next-auth/react"; | import { signOut } from "next-auth/react"; | ||||
import { useRouter } from "next/navigation"; | |||||
type Props = Pick<AppBarProps, "avatarImageSrc" | "profileName">; | type Props = Pick<AppBarProps, "avatarImageSrc" | "profileName">; | ||||
@@ -26,6 +27,7 @@ const Profile: React.FC<Props> = ({ avatarImageSrc, profileName }) => { | |||||
}; | }; | ||||
const { t } = useTranslation("login"); | const { t } = useTranslation("login"); | ||||
const router = useRouter(); | |||||
return ( | return ( | ||||
<> | <> | ||||
@@ -52,6 +54,7 @@ const Profile: React.FC<Props> = ({ avatarImageSrc, profileName }) => { | |||||
{profileName} | {profileName} | ||||
</Typography> | </Typography> | ||||
<Divider /> | <Divider /> | ||||
<MenuItem onClick={() => {router.replace("/settings/changepassword")}}>{t("Change Password")}</MenuItem> | |||||
<MenuItem onClick={() => signOut()}>{t("Sign out")}</MenuItem> | <MenuItem onClick={() => signOut()}>{t("Sign out")}</MenuItem> | ||||
</Menu> | </Menu> | ||||
</> | </> | ||||
@@ -22,7 +22,6 @@ import { fetchSkillCombo } from "@/app/api/skill/actions"; | |||||
import { fetchSalaryCombo } from "@/app/api/salarys/actions"; | import { fetchSalaryCombo } from "@/app/api/salarys/actions"; | ||||
interface Field { | interface Field { | ||||
// subtitle: string; | |||||
id: string; | id: string; | ||||
label: string; | label: string; | ||||
type: string; | type: string; | ||||
@@ -33,12 +32,6 @@ interface Field { | |||||
options?: any[]; | options?: any[]; | ||||
readOnly?: boolean; | readOnly?: boolean; | ||||
} | } | ||||
interface formProps { | |||||
Title?: string[]; | |||||
// fieldLists: Field[][]; | |||||
} | |||||
export interface comboItem { | export interface comboItem { | ||||
company: comboProp[]; | company: comboProp[]; | ||||
team: comboProp[]; | team: comboProp[]; | ||||
@@ -49,101 +42,14 @@ export interface comboItem { | |||||
salary: comboProp[]; | 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[][] = [ | const fieldLists: Field[][] = [ | ||||
[ | [ | ||||
@@ -163,49 +69,49 @@ const CreateStaff: React.FC<formProps> = ({ Title }) => { | |||||
id: "companyId", | id: "companyId", | ||||
label: t("Company"), | label: t("Company"), | ||||
type: "combo-Obj", | type: "combo-Obj", | ||||
options: companyCombo || [], | |||||
options: combos.company || [], | |||||
required: true, | required: true, | ||||
}, | }, | ||||
{ | { | ||||
id: "teamId", | id: "teamId", | ||||
label: t("Team"), | label: t("Team"), | ||||
type: "combo-Obj", | type: "combo-Obj", | ||||
options: teamCombo || [], | |||||
options: combos.team || [], | |||||
required: false, | required: false, | ||||
}, | }, | ||||
{ | { | ||||
id: "departmentId", | id: "departmentId", | ||||
label: t("Department"), | label: t("Department"), | ||||
type: "combo-Obj", | type: "combo-Obj", | ||||
options: departmentCombo || [], | |||||
options: combos.department || [], | |||||
required: true, | required: true, | ||||
}, | }, | ||||
{ | { | ||||
id: "gradeId", | id: "gradeId", | ||||
label: t("Grade"), | label: t("Grade"), | ||||
type: "combo-Obj", | type: "combo-Obj", | ||||
options: gradeCombo || [], | |||||
options: combos.grade || [], | |||||
required: false, | required: false, | ||||
}, | }, | ||||
{ | { | ||||
id: "skillSetId", | id: "skillSetId", | ||||
label: t("Skillset"), | label: t("Skillset"), | ||||
type: "multiSelect-Obj", | type: "multiSelect-Obj", | ||||
options: skillCombo || [], | |||||
options: combos.skill || [], | |||||
required: false, | required: false, | ||||
}, | }, | ||||
{ | { | ||||
id: "currentPositionId", | id: "currentPositionId", | ||||
label: t("Current Position"), | label: t("Current Position"), | ||||
type: "combo-Obj", | type: "combo-Obj", | ||||
options: positionCombo || [], | |||||
options: combos.position || [], | |||||
required: true, | required: true, | ||||
}, | }, | ||||
{ | { | ||||
id: "salaryId", | id: "salaryId", | ||||
label: t("Salary Point"), | label: t("Salary Point"), | ||||
type: "combo-Obj", | type: "combo-Obj", | ||||
options: salaryCombo || [], | |||||
options: combos.salary || [], | |||||
required: true, | required: true, | ||||
}, | }, | ||||
// { | // { | ||||
@@ -279,7 +185,7 @@ const CreateStaff: React.FC<formProps> = ({ Title }) => { | |||||
id: "joinPositionId", | id: "joinPositionId", | ||||
label: t("Join Position"), | label: t("Join Position"), | ||||
type: "combo-Obj", | type: "combo-Obj", | ||||
options: positionCombo || [], | |||||
options: combos.position || [], | |||||
required: true, | required: true, | ||||
}, | }, | ||||
{ | { | ||||
@@ -1,17 +1,48 @@ | |||||
import React from "react"; | import React from "react"; | ||||
import CreateStaff from "./CreateStaff"; | |||||
import CreateStaff, { comboItem } from "./CreateStaff"; | |||||
import CreateStaffLoading from "./CreateStaffLoading"; | import CreateStaffLoading from "./CreateStaffLoading"; | ||||
import { fetchStaff, fetchTeamLeads } from "@/app/api/staff"; | import { fetchStaff, fetchTeamLeads } from "@/app/api/staff"; | ||||
import { useSearchParams } from "next/navigation"; | 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 { | interface SubComponents { | ||||
Loading: typeof CreateStaffLoading; | Loading: typeof CreateStaffLoading; | ||||
} | } | ||||
const CreateStaffWrapper: React.FC & SubComponents = async () => { | 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; | CreateStaffWrapper.Loading = CreateStaffLoading; | ||||
@@ -83,7 +83,7 @@ const EditStaffForm: React.FC<formProps> = ({ Title, fieldLists }) => { | |||||
}; | }; | ||||
return ( | return ( | ||||
<> | <> | ||||
{serverError && ( | |||||
{serverError && ( | |||||
<Typography variant="body2" color="error" alignSelf="flex-end"> | <Typography variant="body2" color="error" alignSelf="flex-end"> | ||||
{serverError} | {serverError} | ||||
</Typography> | </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 [ | const [ | ||||
groups, | groups, | ||||
// auths, | |||||
users, | users, | ||||
] = await Promise.all([ | ] = await Promise.all([ | ||||
fetchGroup(), | fetchGroup(), | ||||
// fetchAuth(), | |||||
fetchUser(), | fetchUser(), | ||||
]); | ]); | ||||
console.log(users) | |||||
return <EditUserGroup groups={groups.records} users={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 { deleteStaff } from "@/app/api/staff/actions"; | ||||
import { useRouter } from "next/navigation"; | import { useRouter } from "next/navigation"; | ||||
import { deleteDialog, successDialog } from "../Swal/CustomAlerts"; | import { deleteDialog, successDialog } from "../Swal/CustomAlerts"; | ||||
import Person from '@mui/icons-material/Person'; | |||||
interface Props { | interface Props { | ||||
staff: StaffResult[]; | staff: StaffResult[]; | ||||
@@ -65,6 +66,14 @@ const StaffSearch: React.FC<Props> = ({ staff }) => { | |||||
[router, t] | [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) => { | const deleteClick = useCallback((staff: StaffResult) => { | ||||
deleteDialog(async () => { | deleteDialog(async () => { | ||||
await deleteStaff(staff.id); | await deleteStaff(staff.id); | ||||
@@ -81,6 +90,12 @@ const StaffSearch: React.FC<Props> = ({ staff }) => { | |||||
onClick: onStaffClick, | onClick: onStaffClick, | ||||
buttonIcon: <EditNote />, | buttonIcon: <EditNote />, | ||||
}, | }, | ||||
{ | |||||
name: "id", | |||||
label: t("Actions"), | |||||
onClick: onUserClick, | |||||
buttonIcon: <Person />, | |||||
}, | |||||
{ name: "team", label: t("Team") }, | { name: "team", label: t("Team") }, | ||||
{ name: "name", label: t("Staff Name") }, | { name: "name", label: t("Staff Name") }, | ||||
{ name: "staffId", label: t("Staff ID") }, | { name: "staffId", label: t("Staff ID") }, | ||||
@@ -71,9 +71,6 @@ export default async function middleware( | |||||
return response; | return response; | ||||
} | } | ||||
// const session = await getServerSession(authOptions); | |||||
// console.log(session); | |||||
let abilities: string[] = [] | let abilities: string[] = [] | ||||
if (token) { | if (token) { | ||||
abilities = (token.abilities as ability[]).map((item: ability) => item.actionSubjectCombo); | 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')) { | if (req.nextUrl.pathname.startsWith('/settings/user')) { | ||||
isAuth = [MAINTAIN_USER, VIEW_USER].some((ability) => abilities.includes(ability)); | 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')) { | if (req.nextUrl.pathname.startsWith('/analytics')) { | ||||
isAuth = [GENERATE_REPORTS].some((ability) => abilities.includes(ability)); | 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 | // Matcher for using the auth middleware | ||||
return PRIVATE_ROUTES.some((route) => req.nextUrl.pathname.startsWith(route)) | return PRIVATE_ROUTES.some((route) => req.nextUrl.pathname.startsWith(route)) | ||||
? await authMiddleware(req, event) // Let auth middleware handle response | ? await authMiddleware(req, event) // Let auth middleware handle response | ||||