diff --git a/src/app/(main)/settings/group/create/page.tsx b/src/app/(main)/settings/group/create/page.tsx new file mode 100644 index 0000000..9130236 --- /dev/null +++ b/src/app/(main)/settings/group/create/page.tsx @@ -0,0 +1,22 @@ +// 'use client'; +import { I18nProvider, getServerI18n } from "@/i18n"; +import React, { useCallback, useState } from "react"; +import { Typography } from "@mui/material"; +import CreateGroup from "@/components/CreateGroup"; + +// const Title = ["title1", "title2"]; + +const CreateStaff: React.FC = async () => { + const { t } = await getServerI18n("group"); + + return ( + <> + {t("Create Group")} + + + + + ); +}; + +export default CreateStaff; diff --git a/src/app/(main)/settings/group/edit/page.tsx b/src/app/(main)/settings/group/edit/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/(main)/settings/group/page.tsx b/src/app/(main)/settings/group/page.tsx new file mode 100644 index 0000000..5322132 --- /dev/null +++ b/src/app/(main)/settings/group/page.tsx @@ -0,0 +1,55 @@ +import { preloadClaims } from "@/app/api/claims"; +import { preloadStaff, preloadTeamLeads } from "@/app/api/staff"; +import StaffSearch from "@/components/StaffSearch"; +import TeamSearch from "@/components/TeamSearch"; +import UserGroupSearch from "@/components/UserGroupSearch"; +import UserSearch from "@/components/UserSearch"; +import { I18nProvider, getServerI18n } from "@/i18n"; +import Add from "@mui/icons-material/Add"; +import Button from "@mui/material/Button"; +import Stack from "@mui/material/Stack"; +import Typography from "@mui/material/Typography"; +import { Metadata } from "next"; +import Link from "next/link"; +import { Suspense } from "react"; + + +export const metadata: Metadata = { + title: "User Group", + }; + + + const UserGroup: React.FC = async () => { + const { t } = await getServerI18n("User Group"); + // preloadTeamLeads(); + // preloadStaff(); + return ( + <> + + + {t("User Group")} + + + + + }> + + + + + ); + }; + + export default UserGroup; \ No newline at end of file diff --git a/src/app/(main)/settings/team/create/page.tsx b/src/app/(main)/settings/team/create/page.tsx index 721fda7..a47d81c 100644 --- a/src/app/(main)/settings/team/create/page.tsx +++ b/src/app/(main)/settings/team/create/page.tsx @@ -28,10 +28,6 @@ import CreateTeam from "@/components/CreateTeam"; const CreateTeamPage: React.FC = async () => { const { t } = await getServerI18n("team"); - const title = ['', t('Additional Info')] - // const regex = new RegExp("^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$") - // console.log(regex) - return ( <> {t("Create Team")} diff --git a/src/app/(main)/settings/user/edit/page.tsx b/src/app/(main)/settings/user/edit/page.tsx new file mode 100644 index 0000000..659347b --- /dev/null +++ b/src/app/(main)/settings/user/edit/page.tsx @@ -0,0 +1,24 @@ +import { Edit } from "@mui/icons-material"; +import { useSearchParams } from "next/navigation"; +// import EditStaff from "@/components/EditStaff"; +import { Suspense } from "react"; +import { I18nProvider } from "@/i18n"; +// import EditStaffWrapper from "@/components/EditStaff/EditStaffWrapper"; +import { Metadata } from "next"; +import EditUser from "@/components/EditUser"; + + +const EditUserPage: React.FC = () => { + + return ( + <> + + }> + + + + + ); +}; + +export default EditUserPage; diff --git a/src/app/(main)/settings/user/page.tsx b/src/app/(main)/settings/user/page.tsx index 95973ab..ef7635f 100644 --- a/src/app/(main)/settings/user/page.tsx +++ b/src/app/(main)/settings/user/page.tsx @@ -33,14 +33,14 @@ export const metadata: Metadata = { {t("User")} - + */} }> diff --git a/src/app/api/group/actions.ts b/src/app/api/group/actions.ts new file mode 100644 index 0000000..c8881de --- /dev/null +++ b/src/app/api/group/actions.ts @@ -0,0 +1,44 @@ +"use server"; + +import { serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; +import { BASE_API_URL } from "@/config/api"; +import { revalidateTag } from "next/cache"; +import { cache } from "react"; + + +export interface CreateGroupInputs { + id?: number; + name: string; + description: string; + addUserIds?: number[]; + removeUserIds?: number[]; + addAuthIds?: number[]; + removeAuthIds?: number[]; + } + +export interface auth { + id: number; + module?: any | null; + authority: string; + name: string; + description: string | null; + v: number; + } + +export interface record { + records: auth[]; + } + + export const fetchAuth = cache(async () => { + return serverFetchJson(`${BASE_API_URL}/group/auth/combo`, { + next: { tags: ["auth"] }, + }); + }); + +export const saveGroup = async (data: CreateGroupInputs) => { + return serverFetchJson(`${BASE_API_URL}/group/save`, { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }); + }; \ No newline at end of file diff --git a/src/app/api/group/index.ts b/src/app/api/group/index.ts new file mode 100644 index 0000000..9dcee9e --- /dev/null +++ b/src/app/api/group/index.ts @@ -0,0 +1,21 @@ +import { serverFetchJson } from "@/app/utils/fetchUtil"; +import { BASE_API_URL } from "@/config/api"; +import { cache } from "react"; +import "server-only"; + +export interface Records { + records: UserGroupResult[] +} + +export interface UserGroupResult { + id: number; + action: () => void; + name: string; + description: string; +} + +export const fetchGroup = cache(async () => { + return serverFetchJson(`${BASE_API_URL}/group`, { + next: { tags: ["group"] }, + }); + }); diff --git a/src/app/api/user/actions.ts b/src/app/api/user/actions.ts index 5df734a..4d353c3 100644 --- a/src/app/api/user/actions.ts +++ b/src/app/api/user/actions.ts @@ -8,8 +8,7 @@ import { cache } from "react"; export interface UserInputs { username: string; - firstname: string; - lastname: string; + email: string; } @@ -19,6 +18,14 @@ export const fetchUserDetails = cache(async (id: number) => { }); }); +export const editUser = async (id: number, data: UserInputs) => { + return serverFetchWithNoContent(`${BASE_API_URL}/user/${id}`, { + method: "PUT", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }); + }; + export const deleteUser = async (id: number) => { return serverFetchWithNoContent(`${BASE_API_URL}/user/${id}`, { method: "DELETE", diff --git a/src/app/api/user/index.ts b/src/app/api/user/index.ts index 9a6065b..3151b64 100644 --- a/src/app/api/user/index.ts +++ b/src/app/api/user/index.ts @@ -19,6 +19,7 @@ export interface UserResult { phone1: string; phone2: string; remarks: string; + groupId: number; } // export interface DetailedUser extends UserResult { diff --git a/src/components/CreateGroup/AuthorityAllocation.tsx b/src/components/CreateGroup/AuthorityAllocation.tsx new file mode 100644 index 0000000..fd9610b --- /dev/null +++ b/src/components/CreateGroup/AuthorityAllocation.tsx @@ -0,0 +1,211 @@ +"use client"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { + FieldErrors, + FormProvider, + SubmitErrorHandler, + SubmitHandler, + useForm, + useFormContext, +} from "react-hook-form"; +import { + Box, + Card, + CardContent, + Grid, + IconButton, + InputAdornment, + Stack, + Tab, + Tabs, + TabsProps, + TextField, + Typography, +} from "@mui/material"; +import { differenceBy } from "lodash"; +import { CreateGroupInputs, auth } from "@/app/api/group/actions"; +import SearchResults, { Column } from "../SearchResults"; +import { Add, Clear, Remove, Search } from "@mui/icons-material"; + +export interface Props { + auth: auth[]; +} + +const AuthorityAllocation: React.FC = ({ auth }) => { + const { t } = useTranslation(); + const { + setValue, + getValues, + formState: { defaultValues }, + reset, + resetField, + } = useFormContext(); + const initialAuths = auth.map((a) => ({ ...a })).sort((a, b) => a.id - b.id); + const [filteredAuths, setFilteredAuths] = useState(initialAuths); + const [selectedAuths, setSelectedAuths] = useState( + () => { + return filteredAuths.filter( + (s) => getValues("addAuthIds")?.includes(s.id) + ); + } + ); + // Adding / Removing Auth + const addAuth = useCallback((auth: auth) => { + setSelectedAuths((a) => [...a, auth]); + }, []); + const removeAuth = useCallback((auth: auth) => { + setSelectedAuths((a) => a.filter((a) => a.id !== auth.id)); + }, []); + + const clearAuth = useCallback(() => { + if (defaultValues !== undefined) { + resetField("addAuthIds"); + setSelectedAuths( + initialAuths.filter((s) => defaultValues.addAuthIds?.includes(s.id)) + ); + } + }, [defaultValues]); + + // Sync with form + useEffect(() => { + setValue( + "addAuthIds", + selectedAuths.map((a) => a.id) + ); + }, [selectedAuths, setValue]); + + const AuthPoolColumns = useMemo[]>( + () => [ + { + label: t("Add"), + name: "id", + onClick: addAuth, + buttonIcon: , + }, + { label: t("authority"), name: "authority" }, + { label: t("Auth Name"), name: "name" }, + // { label: t("Current Position"), name: "currentPosition" }, + ], + [addAuth, t] + ); + + const allocatedAuthColumns = useMemo[]>( + () => [ + { + label: t("Remove"), + name: "id", + onClick: removeAuth, + buttonIcon: , + }, + { label: t("authority"), name: "authority" }, + { label: t("Auth Name"), name: "name" }, + ], + [removeAuth, selectedAuths, t] + ); + const [query, setQuery] = React.useState(""); + const onQueryInputChange = React.useCallback< + React.ChangeEventHandler + >((e) => { + setQuery(e.target.value); + }, []); + const clearQueryInput = React.useCallback(() => { + setQuery(""); + }, []); + + React.useEffect(() => { + // setFilteredStaff( + // initialStaffs.filter((s) => { + // const q = query.toLowerCase(); + // // s.staffId.toLowerCase().includes(q) + // // const q = query.toLowerCase(); + // // return s.name.toLowerCase().includes(q); + // // s.code.toString().includes(q) || + // // (s.brNo != null && s.brNo.toLowerCase().includes(q)) + // }) + // ); + }, [auth, query]); + + useEffect(() => { + // console.log(getValues("addStaffIds")) + }, [initialAuths]); + + const resetAuth = React.useCallback(() => { + clearQueryInput(); + clearAuth(); + }, [clearQueryInput, clearAuth]); + + const formProps = useForm({}); + + // Tab related + const [tabIndex, setTabIndex] = React.useState(0); + const handleTabChange = React.useCallback>( + (_e, newValue) => { + setTabIndex(newValue); + }, + [] + ); + + return ( + <> + + + + + + {t("Authority")} + + + + + + + + + + ), + }} + /> + + + + + + + + {tabIndex === 0 && ( + + )} + {tabIndex === 1 && ( + + )} + + + + + + + ); +}; + +export default AuthorityAllocation; diff --git a/src/components/CreateGroup/CreateGroup.tsx b/src/components/CreateGroup/CreateGroup.tsx new file mode 100644 index 0000000..e931521 --- /dev/null +++ b/src/components/CreateGroup/CreateGroup.tsx @@ -0,0 +1,130 @@ +"use client"; + +import { CreateGroupInputs, auth, saveGroup } from "@/app/api/group/actions"; +import { useRouter } from "next/navigation"; +import { useCallback, useState } from "react"; +import { FieldErrors, FormProvider, SubmitHandler, useForm } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { Button, Stack, Tab, Tabs, TabsProps, Typography } from "@mui/material"; +import { Check, Close, Error } from "@mui/icons-material"; +import GroupInfo from "./GroupInfo"; +import AuthorityAllocation from "./AuthorityAllocation"; +import UserAllocation from "./UserAllocation"; +import { UserResult } from "@/app/api/user"; + +interface Props { + auth?: auth[] + users?: UserResult[] +} + +const CreateGroup: React.FC = ({ auth, users }) => { + const formProps = useForm(); + const [serverError, setServerError] = useState(""); + const router = useRouter(); + const [tabIndex, setTabIndex] = useState(0); + const { t } = useTranslation(); + + const errors = formProps.formState.errors; + + const onSubmit = useCallback>( + async (data) => { + try { + console.log(data); + const postData = { + ...data, + removeUserIds: [], + removeAuthIds: [], + + } + console.log(postData) + await saveGroup(postData) + router.replace("/settings/group") + } catch (e) { + console.log(e); + setServerError(t("An error has occurred. Please try again later.")); + } + }, + [router] + ); + + const handleCancel = () => { + router.back(); + }; + + const handleTabChange = useCallback>( + (_e, newValue) => { + setTabIndex(newValue); + }, + [] + ); + + const hasErrorsInTab = ( + tabIndex: number, + errors: FieldErrors, + ) => { + switch (tabIndex) { + case 0: + return Object.keys(errors).length > 0; + default: + false; + } + }; + + return ( + <> + + + + + ) : undefined + } + iconPosition="end" + /> + + + + {serverError && ( + + {serverError} + + )} + {tabIndex === 0 && } + {tabIndex === 1 && } + {tabIndex === 2 && } + + + + + + + + + ); +}; + +export default CreateGroup; diff --git a/src/components/CreateGroup/CreateGroupLoading.tsx b/src/components/CreateGroup/CreateGroupLoading.tsx new file mode 100644 index 0000000..6a48c4e --- /dev/null +++ b/src/components/CreateGroup/CreateGroupLoading.tsx @@ -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 CreateGroupLoading: React.FC = () => { + return ( + <> + + + + + + + + + + + Create Group + + + + + + + + + + + ); +}; + +export default CreateGroupLoading; diff --git a/src/components/CreateGroup/CreateGroupWrapper.tsx b/src/components/CreateGroup/CreateGroupWrapper.tsx new file mode 100644 index 0000000..e4bd018 --- /dev/null +++ b/src/components/CreateGroup/CreateGroupWrapper.tsx @@ -0,0 +1,24 @@ +import React from "react"; +import CreateGroupLoading from "./CreateGroupLoading"; +import { fetchStaff, fetchTeamLeads } from "@/app/api/staff"; +import { useSearchParams } from "next/navigation"; +import CreateGroup from "./CreateGroup"; +import { auth, fetchAuth } from "@/app/api/group/actions"; +import { fetchUser } from "@/app/api/user"; + +interface SubComponents { + Loading: typeof CreateGroupLoading; +} + +const CreateGroupWrapper: React.FC & SubComponents = async () => { + const records = await fetchAuth() + const users = await fetchUser() + console.log(users) + const auth = records.records as auth[] + + return ; +}; + +CreateGroupWrapper.Loading = CreateGroupLoading; + +export default CreateGroupWrapper; diff --git a/src/components/CreateGroup/GroupInfo.tsx b/src/components/CreateGroup/GroupInfo.tsx new file mode 100644 index 0000000..d9141bc --- /dev/null +++ b/src/components/CreateGroup/GroupInfo.tsx @@ -0,0 +1,81 @@ +"use client"; +import Stack from "@mui/material/Stack"; +import Box from "@mui/material/Box"; +import Card from "@mui/material/Card"; +import CardContent from "@mui/material/CardContent"; +import Grid from "@mui/material/Grid"; +import TextField from "@mui/material/TextField"; +import Typography from "@mui/material/Typography"; +import { CreateGroupInputs } from "@/app/api/group/actions"; +import { useFormContext } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { useCallback } from "react"; + +const GroupInfo: React.FC = () => { + const { t } = useTranslation(); + const { + register, + formState: { errors, defaultValues }, + control, + reset, + resetField, + setValue, + } = useFormContext(); + + + const resetGroup = useCallback(() => { + console.log(defaultValues); + if (defaultValues !== undefined) { + resetField("description"); + } + }, [defaultValues]); + + + return ( + + + + + {t("Group Info")} + + + + + + + + + + + + + ); +}; + +export default GroupInfo; diff --git a/src/components/CreateGroup/UserAllocation.tsx b/src/components/CreateGroup/UserAllocation.tsx new file mode 100644 index 0000000..ff13c52 --- /dev/null +++ b/src/components/CreateGroup/UserAllocation.tsx @@ -0,0 +1,209 @@ +"use client"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { + FieldErrors, + FormProvider, + SubmitErrorHandler, + SubmitHandler, + useForm, + useFormContext, +} from "react-hook-form"; +import { + Box, + Card, + CardContent, + Grid, + IconButton, + InputAdornment, + Stack, + Tab, + Tabs, + TabsProps, + TextField, + Typography, +} from "@mui/material"; +import { differenceBy } from "lodash"; +import { CreateGroupInputs, auth } from "@/app/api/group/actions"; +import SearchResults, { Column } from "../SearchResults"; +import { Add, Clear, Remove, Search } from "@mui/icons-material"; +import { UserResult } from "@/app/api/user"; + +export interface Props { + users: UserResult[]; +} + +const UserAllocation: React.FC = ({ users }) => { + const { t } = useTranslation(); + const { + setValue, + getValues, + formState: { defaultValues }, + reset, + resetField, + } = useFormContext(); + const initialUsers = users.map((u) => ({ ...u })).sort((a, b) => a.id - b.id).filter((u) => u.groupId !== null); + const [filteredUsers, setFilteredUsers] = useState(initialUsers); + const [selectedUsers, setSelectedUsers] = useState( + () => { + return filteredUsers.filter( + (s) => getValues("addUserIds")?.includes(s.id) + ); + } + ); + // Adding / Removing Auth + const addUser = useCallback((users: UserResult) => { + setSelectedUsers((a) => [...a, users]); + }, []); + + const removeUser = useCallback((users: UserResult) => { + setSelectedUsers((a) => a.filter((a) => a.id !== users.id)); + }, []); + + const clearUser = useCallback(() => { + if (defaultValues !== undefined) { + resetField("addUserIds"); + setSelectedUsers( + initialUsers.filter((s) => defaultValues.addUserIds?.includes(s.id)) + ); + } + }, [defaultValues]); + + // Sync with form + useEffect(() => { + setValue( + "addUserIds", + selectedUsers.map((u) => u.id) + ); + }, [selectedUsers, setValue]); + + const UserPoolColumns = useMemo[]>( + () => [ + { + label: t("Add"), + name: "id", + onClick: addUser, + buttonIcon: , + }, + { label: t("User Name"), name: "username" }, + { label: t("name"), name: "name" }, + ], + [addUser, t] + ); + + const allocatedUserColumns = useMemo[]>( + () => [ + { + label: t("Remove"), + name: "id", + onClick: removeUser, + buttonIcon: , + }, + { label: t("User Name"), name: "username" }, + { label: t("name"), name: "name" }, + ], + [removeUser, selectedUsers, t] + ); + + const [query, setQuery] = React.useState(""); + const onQueryInputChange = React.useCallback< + React.ChangeEventHandler + >((e) => { + setQuery(e.target.value); + }, []); + const clearQueryInput = React.useCallback(() => { + setQuery(""); + }, []); + + React.useEffect(() => { + // setFilteredStaff( + // initialStaffs.filter((s) => { + // const q = query.toLowerCase(); + // // s.staffId.toLowerCase().includes(q) + // // const q = query.toLowerCase(); + // // return s.name.toLowerCase().includes(q); + // // s.code.toString().includes(q) || + // // (s.brNo != null && s.brNo.toLowerCase().includes(q)) + // }) + // ); + }, [users, query]); + + const resetUser = React.useCallback(() => { + clearQueryInput(); + clearUser(); + }, [clearQueryInput, clearUser]); + + const formProps = useForm({}); + + // Tab related + const [tabIndex, setTabIndex] = React.useState(0); + const handleTabChange = React.useCallback>( + (_e, newValue) => { + setTabIndex(newValue); + }, + [] + ); + + return ( + <> + + + + + + {t("User")} + + + + + + + + + + ), + }} + /> + + + + + + + + {tabIndex === 0 && ( + + )} + {tabIndex === 1 && ( + + )} + + + + + + + ); +}; + +export default UserAllocation; diff --git a/src/components/CreateGroup/index.ts b/src/components/CreateGroup/index.ts new file mode 100644 index 0000000..1034fc8 --- /dev/null +++ b/src/components/CreateGroup/index.ts @@ -0,0 +1 @@ +export { default } from "./CreateGroupWrapper" \ No newline at end of file diff --git a/src/components/CreateTeam/TeamInfo.tsx b/src/components/CreateTeam/TeamInfo.tsx index 4e61f4b..cd8b90a 100644 --- a/src/components/CreateTeam/TeamInfo.tsx +++ b/src/components/CreateTeam/TeamInfo.tsx @@ -27,7 +27,7 @@ const TeamInfo: React.FC = ( setValue, } = useFormContext(); - const resetCustomer = useCallback(() => { + const resetTeam = useCallback(() => { console.log(defaultValues); if (defaultValues !== undefined) { resetField("description"); diff --git a/src/components/EditTeam/Allocation.tsx b/src/components/EditTeam/Allocation.tsx index 2599867..61e9e8f 100644 --- a/src/components/EditTeam/Allocation.tsx +++ b/src/components/EditTeam/Allocation.tsx @@ -49,7 +49,7 @@ const Allocation: React.FC = ({ allStaffs: staff, teamLead }) => { reset, resetField, } = useFormContext(); - + // let firstFilter: StaffResult[] = [] const initialStaffs = staff.map((s) => ({ ...s })); @@ -63,7 +63,6 @@ const Allocation: React.FC = ({ allStaffs: staff, teamLead }) => { return rearrangedStaff.filter((s) => getValues("addStaffIds")?.includes(s.id)) } ); - console.log(filteredStaff.filter((s) => getValues("addStaffIds")?.includes(s.id))) const [seletedTeamLead, setSeletedTeamLead] = useState(); const [deletedStaffIds, setDeletedStaffIds] = useState([]); diff --git a/src/components/NavigationContent/NavigationContent.tsx b/src/components/NavigationContent/NavigationContent.tsx index 233f228..226482e 100644 --- a/src/components/NavigationContent/NavigationContent.tsx +++ b/src/components/NavigationContent/NavigationContent.tsx @@ -143,6 +143,7 @@ const NavigationContent: React.FC = ({ abilities }) => { { icon: , label: "Salary", path: "/settings/salary" }, { icon: , label: "Team", path: "/settings/team" }, { icon: , label: "User", path: "/settings/user" }, + { icon: , label: "User Group", path: "/settings/group" }, { icon: , label: "Holiday", path: "/settings/holiday" }, ], }, diff --git a/src/components/UserGroupSearch/UserGroupSearch.tsx b/src/components/UserGroupSearch/UserGroupSearch.tsx new file mode 100644 index 0000000..0480167 --- /dev/null +++ b/src/components/UserGroupSearch/UserGroupSearch.tsx @@ -0,0 +1,94 @@ +"use client"; + +import SearchBox, { Criterion } from "../SearchBox"; +import { useCallback, useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; +import SearchResults, { Column } from "../SearchResults/index"; +import EditNote from "@mui/icons-material/EditNote"; +import DeleteIcon from "@mui/icons-material/Delete"; +import { useRouter } from "next/navigation"; +import { deleteDialog, successDialog } from "../Swal/CustomAlerts"; +import { UserGroupResult } from "@/app/api/group"; +import { deleteUser } from "@/app/api/user/actions"; + +interface Props { + users: UserGroupResult[]; +} +type SearchQuery = Partial>; +type SearchParamNames = keyof SearchQuery; + +const UserGroupSearch: React.FC = ({ users }) => { + const { t } = useTranslation(); + const [filteredUser, setFilteredUser] = useState(users); + const router = useRouter(); + + const searchCriteria: Criterion[] = useMemo( + () => [ + { + label: t("User Name"), + paramName: "name", + type: "text", + }, + ], + [t] + ); + + const onUserClick = useCallback( + (users: UserGroupResult) => { + console.log(users); + // router.push(`/settings/user/edit?id=${users.id}`) + }, + [router, t] + ); + + const onDeleteClick = useCallback((users: UserGroupResult) => { + deleteDialog(async () => { + await deleteUser(users.id); + + successDialog(t("Delete Success"), t); + + setFilteredUser((prev) => prev.filter((obj) => obj.id !== users.id)); + }, t); + }, []); + + const columns = useMemo[]>( + () => [ + { + name: "action", + label: t("Edit"), + onClick: onUserClick, + buttonIcon: , + }, + { name: "name", label: t("Group Name") }, + { name: "description", label: t("Description") }, + { + name: "action", + label: t("Delete"), + onClick: onDeleteClick, + buttonIcon: , + color: "error" + }, + ], + [t] + ); + + return ( + <> + { + // setFilteredUser( + // users.filter( + // (t) => + // t.name.toLowerCase().includes(query.name.toLowerCase()) && + // t.code.toLowerCase().includes(query.code.toLowerCase()) && + // t.description.toLowerCase().includes(query.description.toLowerCase()) + // ) + // ) + }} + /> + items={filteredUser} columns={columns} /> + + ); +}; +export default UserGroupSearch; diff --git a/src/components/UserGroupSearch/UserGroupSearchLoading.tsx b/src/components/UserGroupSearch/UserGroupSearchLoading.tsx new file mode 100644 index 0000000..5d8df0f --- /dev/null +++ b/src/components/UserGroupSearch/UserGroupSearchLoading.tsx @@ -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 UserGroupSearchLoading: React.FC = () => { + return ( + <> + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default UserGroupSearchLoading; diff --git a/src/components/UserGroupSearch/UserGroupSearchWrapper.tsx b/src/components/UserGroupSearch/UserGroupSearchWrapper.tsx new file mode 100644 index 0000000..9f792ed --- /dev/null +++ b/src/components/UserGroupSearch/UserGroupSearchWrapper.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import UserGroupSearchLoading from "./UserGroupSearchLoading"; +import { UserGroupResult, fetchGroup } from "@/app/api/group"; +import UserGroupSearch from "./UserGroupSearch"; + +interface SubComponents { + Loading: typeof UserGroupSearchLoading; +} + +const UserGroupSearchWrapper: React.FC & SubComponents = async () => { +const group = await fetchGroup() + console.log(group.records); + + return ; +}; + +UserGroupSearchWrapper.Loading = UserGroupSearchLoading; + +export default UserGroupSearchWrapper; diff --git a/src/components/UserGroupSearch/index.ts b/src/components/UserGroupSearch/index.ts new file mode 100644 index 0000000..f2e5e63 --- /dev/null +++ b/src/components/UserGroupSearch/index.ts @@ -0,0 +1 @@ +export { default } from "./UserGroupSearchWrapper";