From ffaf2e764b12acfbae9586050bab0c0353c581c7 Mon Sep 17 00:00:00 2001 From: "MSI\\2Fi" Date: Tue, 2 Apr 2024 17:51:00 +0800 Subject: [PATCH] 1. Department Search Page 2. Create Department Page 3. Postion Search Page 4. Create Position Page --- .../(main)/settings/department/new/page.tsx | 25 +++++ src/app/(main)/settings/department/page.tsx | 50 +++++++++ src/app/(main)/settings/position/new/page.tsx | 25 +++++ src/app/(main)/settings/position/page.tsx | 50 +++++++++ src/app/api/departments/actions.ts | 18 ++++ src/app/api/departments/index.ts | 21 ++++ src/app/api/positions/actions.ts | 18 ++++ src/app/api/positions/index.ts | 21 ++++ src/components/Breadcrumb/Breadcrumb.tsx | 5 + .../CreateDepartment/CreateDepartment.tsx | 102 ++++++++++++++++++ .../CreateDepartmentWrapper.tsx | 20 ++++ .../CreateDepartment/DepartmentDetails.tsx | 81 ++++++++++++++ src/components/CreateDepartment/index.ts | 1 + .../CreatePosition/CreatePosition.tsx | 102 ++++++++++++++++++ .../CreatePosition/CreatePositionWrapper.tsx | 18 ++++ .../CreatePosition/PositionDetails.tsx | 81 ++++++++++++++ src/components/CreatePosition/index.ts | 1 + .../DepartmentSearch/DepartmentSearch.tsx | 82 ++++++++++++++ .../DepartmentSearchLoading.tsx | 40 +++++++ .../DepartmentSearchWrapper.tsx | 20 ++++ src/components/DepartmentSearch/index.ts | 1 + .../NavigationContent/NavigationContent.tsx | 7 +- .../PositionSearch/PositionSearch.tsx | 81 ++++++++++++++ .../PositionSearch/PositionSearchLoading.tsx | 40 +++++++ .../PositionSearch/PositionSearchWrapper.tsx | 20 ++++ src/components/PositionSearch/index.ts | 1 + 26 files changed, 930 insertions(+), 1 deletion(-) create mode 100644 src/app/(main)/settings/department/new/page.tsx create mode 100644 src/app/(main)/settings/department/page.tsx create mode 100644 src/app/(main)/settings/position/new/page.tsx create mode 100644 src/app/(main)/settings/position/page.tsx create mode 100644 src/app/api/departments/actions.ts create mode 100644 src/app/api/departments/index.ts create mode 100644 src/app/api/positions/actions.ts create mode 100644 src/app/api/positions/index.ts create mode 100644 src/components/CreateDepartment/CreateDepartment.tsx create mode 100644 src/components/CreateDepartment/CreateDepartmentWrapper.tsx create mode 100644 src/components/CreateDepartment/DepartmentDetails.tsx create mode 100644 src/components/CreateDepartment/index.ts create mode 100644 src/components/CreatePosition/CreatePosition.tsx create mode 100644 src/components/CreatePosition/CreatePositionWrapper.tsx create mode 100644 src/components/CreatePosition/PositionDetails.tsx create mode 100644 src/components/CreatePosition/index.ts create mode 100644 src/components/DepartmentSearch/DepartmentSearch.tsx create mode 100644 src/components/DepartmentSearch/DepartmentSearchLoading.tsx create mode 100644 src/components/DepartmentSearch/DepartmentSearchWrapper.tsx create mode 100644 src/components/DepartmentSearch/index.ts create mode 100644 src/components/PositionSearch/PositionSearch.tsx create mode 100644 src/components/PositionSearch/PositionSearchLoading.tsx create mode 100644 src/components/PositionSearch/PositionSearchWrapper.tsx create mode 100644 src/components/PositionSearch/index.ts diff --git a/src/app/(main)/settings/department/new/page.tsx b/src/app/(main)/settings/department/new/page.tsx new file mode 100644 index 0000000..1f94edc --- /dev/null +++ b/src/app/(main)/settings/department/new/page.tsx @@ -0,0 +1,25 @@ +import CreateDepartment from "@/components/CreateDepartment"; +import { I18nProvider, getServerI18n } from "@/i18n"; +import Typography from "@mui/material/Typography"; +import { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Create Department", +}; + +const Department: React.FC = async () => { + const { t } = await getServerI18n("departments"); + + // Preload necessary dependencies + + return ( + <> + {t("Create Department")} + + + + + ); +}; + +export default Department; diff --git a/src/app/(main)/settings/department/page.tsx b/src/app/(main)/settings/department/page.tsx new file mode 100644 index 0000000..a051721 --- /dev/null +++ b/src/app/(main)/settings/department/page.tsx @@ -0,0 +1,50 @@ +import DepartmentSearch from "@/components/DepartmentSearch"; +import { Metadata } from "next"; +import { 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 Link from "next/link"; +import { Suspense } from "react"; +import { fetchDepartments, preloadDepartments } from "@/app/api/departments"; + +export const metadata: Metadata = { + title: "Department", +}; + +const Department: React.FC = async () => { + const { t } = await getServerI18n("department"); + + // Preload necessary dependencies + // fetchDepartments(); + // preloadDepartments(); + + return ( + <> + + + {t("Department")} + + + + }> + + + + ) +}; + +export default Department; diff --git a/src/app/(main)/settings/position/new/page.tsx b/src/app/(main)/settings/position/new/page.tsx new file mode 100644 index 0000000..6da7d2d --- /dev/null +++ b/src/app/(main)/settings/position/new/page.tsx @@ -0,0 +1,25 @@ +import CreatePosition from "@/components/CreatePosition"; +import { I18nProvider, getServerI18n } from "@/i18n"; +import Typography from "@mui/material/Typography"; +import { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Create Position", +}; + +const Positions: React.FC = async () => { + const { t } = await getServerI18n("positions"); + + // Preload necessary dependencies + + return ( + <> + {t("Create Position")} + + + + + ); +}; + +export default Positions; \ No newline at end of file diff --git a/src/app/(main)/settings/position/page.tsx b/src/app/(main)/settings/position/page.tsx new file mode 100644 index 0000000..5342145 --- /dev/null +++ b/src/app/(main)/settings/position/page.tsx @@ -0,0 +1,50 @@ +import PositionSearch from "@/components/PositionSearch"; +import { Metadata } from "next"; +import { 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 Link from "next/link"; +import { Suspense } from "react"; +import { fetchPositions, preloadPositions } from "@/app/api/positions"; + +export const metadata: Metadata = { + title: "Position", +}; + +const Position: React.FC = async () => { + const { t } = await getServerI18n("Position"); + + // Preload necessary dependencies + // fetchPositions(); + // preloadPositions(); + + return ( + <> + + + {t("Position")} + + + + }> + + + + ) +}; + +export default Position; diff --git a/src/app/api/departments/actions.ts b/src/app/api/departments/actions.ts new file mode 100644 index 0000000..7248efb --- /dev/null +++ b/src/app/api/departments/actions.ts @@ -0,0 +1,18 @@ +"use server" + +import { serverFetchJson } from "@/app/utils/fetchUtil"; +import { BASE_API_URL } from "@/config/api"; + +export interface CreateDepartmentInputs { + departmentCode: string; + departmentName: string; + description: string; +} + +export const saveDepartment = async (data: CreateDepartmentInputs) => { + return serverFetchJson(`${BASE_API_URL}/departments/new`, { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }); + }; \ No newline at end of file diff --git a/src/app/api/departments/index.ts b/src/app/api/departments/index.ts new file mode 100644 index 0000000..9bb4354 --- /dev/null +++ b/src/app/api/departments/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 DepartmentResult { + id: number; + code: string; + name: string; + description: string; +} + +export const preloadDepartments = () => { + fetchDepartments(); +}; + +export const fetchDepartments = cache(async () => { + return serverFetchJson(`${BASE_API_URL}/departments`, { + next: { tags: ["departments"] }, + }); +}); \ No newline at end of file diff --git a/src/app/api/positions/actions.ts b/src/app/api/positions/actions.ts new file mode 100644 index 0000000..ea6004c --- /dev/null +++ b/src/app/api/positions/actions.ts @@ -0,0 +1,18 @@ +"use server" + +import { serverFetchJson } from "@/app/utils/fetchUtil"; +import { BASE_API_URL } from "@/config/api"; + +export interface CreatePositionInputs { + positionCode: string; + positionName: string; + description: string; +} + +export const savePosition = async (data: CreatePositionInputs) => { + return serverFetchJson(`${BASE_API_URL}/positions/new`, { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }); + }; \ No newline at end of file diff --git a/src/app/api/positions/index.ts b/src/app/api/positions/index.ts new file mode 100644 index 0000000..981554f --- /dev/null +++ b/src/app/api/positions/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 PositionResult { + id: number; + code: string; + name: string; + description: string; +} + +export const preloadPositions = () => { + fetchPositions(); +}; + +export const fetchPositions = cache(async () => { + return serverFetchJson(`${BASE_API_URL}/positions`, { + next: { tags: ["positions"] }, + }); +}); \ No newline at end of file diff --git a/src/components/Breadcrumb/Breadcrumb.tsx b/src/components/Breadcrumb/Breadcrumb.tsx index 44b16a8..5b05018 100644 --- a/src/components/Breadcrumb/Breadcrumb.tsx +++ b/src/components/Breadcrumb/Breadcrumb.tsx @@ -15,7 +15,12 @@ const pathToLabelMap: { [path: string]: string } = { "/tasks/create": "Create Task Template", "/customer": "Customer", "/customer/create": "Create Customer", + "/settings": "Settings", "/company": "Company", + "/settings/department": "Department", + "/settings/department/new": "Create Department", + "/settings/position": "Position", + "/settings/position/new": "Create Position", }; const Breadcrumb = () => { diff --git a/src/components/CreateDepartment/CreateDepartment.tsx b/src/components/CreateDepartment/CreateDepartment.tsx new file mode 100644 index 0000000..d3b1d5a --- /dev/null +++ b/src/components/CreateDepartment/CreateDepartment.tsx @@ -0,0 +1,102 @@ +"use client"; + +import Check from "@mui/icons-material/Check"; +import Close from "@mui/icons-material/Close"; +import Button from "@mui/material/Button"; +import Stack from "@mui/material/Stack"; +import Tab from "@mui/material/Tab"; +import Tabs, { TabsProps } from "@mui/material/Tabs"; +import { useRouter } from "next/navigation"; +import React, { useCallback, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Task, TaskTemplate } from "@/app/api/tasks"; +import { + FieldErrors, + FormProvider, + SubmitErrorHandler, + SubmitHandler, + useForm, +} from "react-hook-form"; +import { CreateDepartmentInputs, saveDepartment } from "@/app/api/departments/actions"; +import { Error } from "@mui/icons-material"; +import { ProjectCategory } from "@/app/api/projects"; +import { Staff } from "@/app/api/staff"; +import { Typography } from "@mui/material"; +import DepartmentDetails from "./DepartmentDetails"; + + +const CreateDepartment: React.FC = ({ + // allTasks, + // projectCategories, + // taskTemplates, + // teamLeads, +}) => { + const [serverError, setServerError] = useState(""); + const { t } = useTranslation(); + const router = useRouter(); + + const handleCancel = () => { + router.back(); + }; + + const onSubmit = useCallback>( + async (data) => { + try { + console.log(data); + setServerError(""); + // console.log(JSON.stringify(data)); + await saveDepartment(data) + router.replace("/settings/department"); + } catch (e) { + setServerError(t("An error has occurred. Please try again later.")); + } + }, + [router, t], + ); + + const onSubmitError = useCallback>( + (errors) => { + console.log(errors) + }, + [], + ); + + const formProps = useForm({ + defaultValues: { + departmentCode: "", + departmentName: "", + description: "", + }, + }); + + const errors = formProps.formState.errors; + + return ( + + + { + + } + + + + + + + + ); +}; + +export default CreateDepartment; diff --git a/src/components/CreateDepartment/CreateDepartmentWrapper.tsx b/src/components/CreateDepartment/CreateDepartmentWrapper.tsx new file mode 100644 index 0000000..cf32044 --- /dev/null +++ b/src/components/CreateDepartment/CreateDepartmentWrapper.tsx @@ -0,0 +1,20 @@ +import { fetchAllTasks, fetchTaskTemplates } from "@/app/api/tasks"; +import CreateDepartment from "./CreateDepartment"; +import { fetchTeamLeads } from "@/app/api/staff"; + +const CreateDepartmentWrapper: React.FC = async () => { + // const [tasks, taskTemplates, DepartmentCategories, teamLeads] = + // await Promise.all([ + // fetchAllTasks(), + // fetchTaskTemplates(), + // fetchDepartmentCategories(), + // fetchTeamLeads(), + // ]); + + return ( + + ); +}; + +export default CreateDepartmentWrapper; diff --git a/src/components/CreateDepartment/DepartmentDetails.tsx b/src/components/CreateDepartment/DepartmentDetails.tsx new file mode 100644 index 0000000..ea3fd3e --- /dev/null +++ b/src/components/CreateDepartment/DepartmentDetails.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 FormControl from "@mui/material/FormControl"; +import Grid from "@mui/material/Grid"; +import InputLabel from "@mui/material/InputLabel"; +import MenuItem from "@mui/material/MenuItem"; +import Select from "@mui/material/Select"; +import TextField from "@mui/material/TextField"; +import Typography from "@mui/material/Typography"; +import { useTranslation } from "react-i18next"; +import CardActions from "@mui/material/CardActions"; +import RestartAlt from "@mui/icons-material/RestartAlt"; +import Button from "@mui/material/Button"; +import { Controller, useFormContext } from "react-hook-form"; +import { CreateDepartmentInputs } from "@/app/api/departments/actions"; +import { Staff } from "@/app/api/staff"; + +const DepartmentDetails: React.FC = ({ +}) => { + const { t } = useTranslation(); + const { + register, + formState: { errors }, + control, + } = useFormContext(); + + return ( + + + + + {t("Department Details")} + + + + + + + + + + + + + + {/* + + */} + + + ); +}; + +export default DepartmentDetails; \ No newline at end of file diff --git a/src/components/CreateDepartment/index.ts b/src/components/CreateDepartment/index.ts new file mode 100644 index 0000000..622818b --- /dev/null +++ b/src/components/CreateDepartment/index.ts @@ -0,0 +1 @@ +export { default } from "./CreateDepartmentWrapper" \ No newline at end of file diff --git a/src/components/CreatePosition/CreatePosition.tsx b/src/components/CreatePosition/CreatePosition.tsx new file mode 100644 index 0000000..eb3a06a --- /dev/null +++ b/src/components/CreatePosition/CreatePosition.tsx @@ -0,0 +1,102 @@ +"use client"; + +import Check from "@mui/icons-material/Check"; +import Close from "@mui/icons-material/Close"; +import Button from "@mui/material/Button"; +import Stack from "@mui/material/Stack"; +import Tab from "@mui/material/Tab"; +import Tabs, { TabsProps } from "@mui/material/Tabs"; +import { useRouter } from "next/navigation"; +import React, { useCallback, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Task, TaskTemplate } from "@/app/api/tasks"; +import { + FieldErrors, + FormProvider, + SubmitErrorHandler, + SubmitHandler, + useForm, +} from "react-hook-form"; +import { CreatePositionInputs, savePosition } from "@/app/api/positions/actions"; +import { Error } from "@mui/icons-material"; +import { ProjectCategory } from "@/app/api/projects"; +import { Staff } from "@/app/api/staff"; +import { Typography } from "@mui/material"; +import PositionDetails from "./PositionDetails"; + + +const CreatePosition: React.FC = ({ + // allTasks, + // projectCategories, + // taskTemplates, + // teamLeads, +}) => { + const [serverError, setServerError] = useState(""); + const { t } = useTranslation(); + const router = useRouter(); + + const handleCancel = () => { + router.back(); + }; + + const onSubmit = useCallback>( + async (data) => { + try { + console.log(data); + setServerError(""); + // console.log(JSON.stringify(data)); + await savePosition(data) + router.replace("/settings/position"); + } catch (e) { + setServerError(t("An error has occurred. Please try again later.")); + } + }, + [router, t], + ); + + const onSubmitError = useCallback>( + (errors) => { + console.log(errors) + }, + [], + ); + + const formProps = useForm({ + defaultValues: { + positionCode: "", + positionName: "", + description: "", + }, + }); + + const errors = formProps.formState.errors; + + return ( + + + { + + } + + + + + + + + ); +}; + +export default CreatePosition; diff --git a/src/components/CreatePosition/CreatePositionWrapper.tsx b/src/components/CreatePosition/CreatePositionWrapper.tsx new file mode 100644 index 0000000..88dcf24 --- /dev/null +++ b/src/components/CreatePosition/CreatePositionWrapper.tsx @@ -0,0 +1,18 @@ +import CreatePosition from "./CreatePosition"; + +const CreatePositionWrapper: React.FC = async () => { + // const [tasks, taskTemplates, PositionCategories, teamLeads] = + // await Promise.all([ + // fetchAllTasks(), + // fetchTaskTemplates(), + // fetchPositionCategories(), + // fetchTeamLeads(), + // ]); + + return ( + + ); +}; + +export default CreatePositionWrapper; diff --git a/src/components/CreatePosition/PositionDetails.tsx b/src/components/CreatePosition/PositionDetails.tsx new file mode 100644 index 0000000..042a8e2 --- /dev/null +++ b/src/components/CreatePosition/PositionDetails.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 FormControl from "@mui/material/FormControl"; +import Grid from "@mui/material/Grid"; +import InputLabel from "@mui/material/InputLabel"; +import MenuItem from "@mui/material/MenuItem"; +import Select from "@mui/material/Select"; +import TextField from "@mui/material/TextField"; +import Typography from "@mui/material/Typography"; +import { useTranslation } from "react-i18next"; +import CardActions from "@mui/material/CardActions"; +import RestartAlt from "@mui/icons-material/RestartAlt"; +import Button from "@mui/material/Button"; +import { Controller, useFormContext } from "react-hook-form"; +import { CreatePositionInputs } from "@/app/api/positions/actions"; +import { Staff } from "@/app/api/staff"; + +const PositionDetails: React.FC = ({ +}) => { + const { t } = useTranslation(); + const { + register, + formState: { errors }, + control, + } = useFormContext(); + + return ( + + + + + {t("Position Details")} + + + + + + + + + + + + + + {/* + + */} + + + ); +}; + +export default PositionDetails; \ No newline at end of file diff --git a/src/components/CreatePosition/index.ts b/src/components/CreatePosition/index.ts new file mode 100644 index 0000000..5e1ec57 --- /dev/null +++ b/src/components/CreatePosition/index.ts @@ -0,0 +1 @@ +export { default } from "./CreatePositionWrapper" \ No newline at end of file diff --git a/src/components/DepartmentSearch/DepartmentSearch.tsx b/src/components/DepartmentSearch/DepartmentSearch.tsx new file mode 100644 index 0000000..57cd3ab --- /dev/null +++ b/src/components/DepartmentSearch/DepartmentSearch.tsx @@ -0,0 +1,82 @@ +"use client"; + +import React, { useCallback, useMemo, useState } from "react"; +import SearchBox, { Criterion } from "../SearchBox"; +import { useTranslation } from "react-i18next"; +import SearchResults, { Column } from "../SearchResults"; +import EditNote from "@mui/icons-material/EditNote"; +import uniq from "lodash/uniq"; +import { DepartmentResult } from "@/app/api/departments"; + +interface Props { + departments: DepartmentResult[]; +} + +type SearchQuery = Partial>; +type SearchParamNames = keyof SearchQuery; + +const DepartmentSearch: React.FC = ({ departments }) => { + const { t } = useTranslation("departments"); + + const [filteredDepartments, setFilteredDepartments] = useState(departments); + + const searchCriteria: Criterion[] = useMemo( + () => [ + { label: t("Department code"), paramName: "code", type: "text" }, + { label: t("Department name"), paramName: "name", type: "text" }, + { label: t("Department Description"), paramName: "description", type: "text" }, + ], + [t, departments], + ); + + const onReset = useCallback(() => { + setFilteredDepartments(departments); + }, [departments]); + + const onProjectClick = useCallback((project: DepartmentResult) => { + console.log(project); + }, []); + + const columns = useMemo[]>( + () => [ + { + name: "id", + label: t("Details"), + onClick: onProjectClick, + buttonIcon: , + }, + { name: "code", label: t("Department Code") }, + { name: "name", label: t("Department Name") }, + { name: "description", label: t("Department Description") }, + ], + [t, onProjectClick], + ); + + return ( + <> + { + setFilteredDepartments( + departments.filter( + (d) => + d.code.toLowerCase().includes(query.code.toLowerCase()) && + d.name.toLowerCase().includes(query.name.toLowerCase()) && + d.description.toLowerCase().includes(query.description.toLowerCase()) && + {/*(query.client === "All" || p.client === query.client) && + (query.category === "All" || p.category === query.category) && + (query.team === "All" || p.team === query.team), **/} + ), + ); + }} + onReset={onReset} + /> + + items={filteredDepartments} + columns={columns} + /> + + ); +}; + +export default DepartmentSearch; diff --git a/src/components/DepartmentSearch/DepartmentSearchLoading.tsx b/src/components/DepartmentSearch/DepartmentSearchLoading.tsx new file mode 100644 index 0000000..1ff8af2 --- /dev/null +++ b/src/components/DepartmentSearch/DepartmentSearchLoading.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 DepartmentSearchLoading: React.FC = () => { + return ( + <> + + + + + + + + + + + Department + + + + + + + + + + + ); +}; + +export default DepartmentSearchLoading; diff --git a/src/components/DepartmentSearch/DepartmentSearchWrapper.tsx b/src/components/DepartmentSearch/DepartmentSearchWrapper.tsx new file mode 100644 index 0000000..4249dfd --- /dev/null +++ b/src/components/DepartmentSearch/DepartmentSearchWrapper.tsx @@ -0,0 +1,20 @@ +// import { fetchDepartmentCategories, fetchDepartments } from "@/app/api/companys"; +import React from "react"; +import DepartmentSearch from "./DepartmentSearch"; +import DepartmentSearchLoading from "./DepartmentSearchLoading"; +import { fetchDepartments } from "@/app/api/departments"; + +interface SubComponents { + Loading: typeof DepartmentSearchLoading; +} + +const DepartmentSearchWrapper: React.FC & SubComponents = async () => { + const Departments = await fetchDepartments(); + // const Departments:any[] = [] + + return ; +}; + +DepartmentSearchWrapper.Loading = DepartmentSearchLoading; + +export default DepartmentSearchWrapper; diff --git a/src/components/DepartmentSearch/index.ts b/src/components/DepartmentSearch/index.ts new file mode 100644 index 0000000..f6047ea --- /dev/null +++ b/src/components/DepartmentSearch/index.ts @@ -0,0 +1 @@ +export { default } from "./DepartmentSearchWrapper"; diff --git a/src/components/NavigationContent/NavigationContent.tsx b/src/components/NavigationContent/NavigationContent.tsx index 9eb5ebc..fbb1aa5 100644 --- a/src/components/NavigationContent/NavigationContent.tsx +++ b/src/components/NavigationContent/NavigationContent.tsx @@ -18,6 +18,9 @@ import Settings from "@mui/icons-material/Settings"; import Analytics from "@mui/icons-material/Analytics"; import Payments from "@mui/icons-material/Payments"; import Staff from "@mui/icons-material/PeopleAlt"; +import Company from '@mui/icons-material/Store'; +import Department from '@mui/icons-material/Diversity3'; +import Position from '@mui/icons-material/Paragliding'; import { useTranslation } from "react-i18next"; import Typography from "@mui/material/Typography"; import { usePathname } from "next/navigation"; @@ -92,7 +95,9 @@ const navigationItems: NavigationItem[] = [ children: [ { icon: , label: "Customer", path: "/customer" }, { icon: , label: "Staff", path: "/staff" }, - { icon: , label: "Company", path: "/settings/company" } + { icon: , label: "Company", path: "/settings/company" }, + { icon: , label: "Department", path: "/settings/department" }, + { icon: , label: "Position", path: "/settings/position" }, ], }, ]; diff --git a/src/components/PositionSearch/PositionSearch.tsx b/src/components/PositionSearch/PositionSearch.tsx new file mode 100644 index 0000000..bd3cc4e --- /dev/null +++ b/src/components/PositionSearch/PositionSearch.tsx @@ -0,0 +1,81 @@ +"use client"; + +import React, { useCallback, useMemo, useState } from "react"; +import SearchBox, { Criterion } from "../SearchBox"; +import { useTranslation } from "react-i18next"; +import SearchResults, { Column } from "../SearchResults"; +import EditNote from "@mui/icons-material/EditNote"; +import { PositionResult } from "@/app/api/positions"; + +interface Props { + positions: PositionResult[]; +} + +type SearchQuery = Partial>; +type SearchParamNames = keyof SearchQuery; + +const PositionSearch: React.FC = ({ positions }) => { + const { t } = useTranslation("positions"); + + const [filteredPositions, setFilteredPositions] = useState(positions); + + const searchCriteria: Criterion[] = useMemo( + () => [ + { label: t("Position code"), paramName: "code", type: "text" }, + { label: t("Position name"), paramName: "name", type: "text" }, + { label: t("Position Description"), paramName: "description", type: "text" }, + ], + [t, positions], + ); + + const onReset = useCallback(() => { + setFilteredPositions(positions); + }, [positions]); + + const onProjectClick = useCallback((project: PositionResult) => { + console.log(project); + }, []); + + const columns = useMemo[]>( + () => [ + { + name: "id", + label: t("Details"), + onClick: onProjectClick, + buttonIcon: , + }, + { name: "code", label: t("Position Code") }, + { name: "name", label: t("Position Name") }, + { name: "description", label: t("Position Description") }, + ], + [t, onProjectClick], + ); + + return ( + <> + { + setFilteredPositions( + positions.filter( + (d) => + d.code.toLowerCase().includes(query.code.toLowerCase()) && + d.name.toLowerCase().includes(query.name.toLowerCase()) && + d.description.toLowerCase().includes(query.description.toLowerCase()) && + {/*(query.client === "All" || p.client === query.client) && + (query.category === "All" || p.category === query.category) && + (query.team === "All" || p.team === query.team), **/} + ), + ); + }} + onReset={onReset} + /> + + items={filteredPositions} + columns={columns} + /> + + ); +}; + +export default PositionSearch; diff --git a/src/components/PositionSearch/PositionSearchLoading.tsx b/src/components/PositionSearch/PositionSearchLoading.tsx new file mode 100644 index 0000000..aa403b7 --- /dev/null +++ b/src/components/PositionSearch/PositionSearchLoading.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 PositionSearchLoading: React.FC = () => { + return ( + <> + + + + + + + + + + + Position + + + + + + + + + + + ); +}; + +export default PositionSearchLoading; diff --git a/src/components/PositionSearch/PositionSearchWrapper.tsx b/src/components/PositionSearch/PositionSearchWrapper.tsx new file mode 100644 index 0000000..f115a77 --- /dev/null +++ b/src/components/PositionSearch/PositionSearchWrapper.tsx @@ -0,0 +1,20 @@ +// import { fetchPositionCategories, fetchPositions } from "@/app/api/companys"; +import React from "react"; +import PositionSearch from "./PositionSearch"; +import PositionSearchLoading from "./PositionSearchLoading"; +import { fetchPositions } from "@/app/api/positions"; + +interface SubComponents { + Loading: typeof PositionSearchLoading; +} + +const PositionSearchWrapper: React.FC & SubComponents = async () => { + const Positions = await fetchPositions(); + // const Positions:any[] = [] + + return ; +}; + +PositionSearchWrapper.Loading = PositionSearchLoading; + +export default PositionSearchWrapper; diff --git a/src/components/PositionSearch/index.ts b/src/components/PositionSearch/index.ts new file mode 100644 index 0000000..0b2c0f1 --- /dev/null +++ b/src/components/PositionSearch/index.ts @@ -0,0 +1 @@ +export { default } from "./PositionSearchWrapper";