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")}
+
+ }
+ LinkComponent={Link}
+ href="/settings/department/new"
+ >
+ {t("Create 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")}
+
+ }
+ LinkComponent={Link}
+ href="/settings/position/new"
+ >
+ {t("Create 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 (
+
+
+ {
+
+ }
+
+
+ }
+ onClick={handleCancel}
+ >
+ {t("Cancel")}
+
+ } type="submit">
+ {t("Confirm")}
+
+
+
+
+ );
+};
+
+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")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+ }>
+ {t("Reset")}
+
+ */}
+
+
+ );
+};
+
+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 (
+
+
+ {
+
+ }
+
+
+ }
+ onClick={handleCancel}
+ >
+ {t("Cancel")}
+
+ } type="submit">
+ {t("Confirm")}
+
+
+
+
+ );
+};
+
+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")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+ }>
+ {t("Reset")}
+
+ */}
+
+
+ );
+};
+
+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";