소스 검색

Salary page

tags/Baseline_30082024_FRONTEND_UAT
MSI\2Fi 1 년 전
부모
커밋
8d50d43726
8개의 변경된 파일213개의 추가작업 그리고 0개의 파일을 삭제
  1. +50
    -0
      src/app/(main)/settings/salary/page.tsx
  2. +22
    -0
      src/app/api/salarys/index.ts
  3. +1
    -0
      src/components/Breadcrumb/Breadcrumb.tsx
  4. +2
    -0
      src/components/NavigationContent/NavigationContent.tsx
  5. +77
    -0
      src/components/SalarySearch/SalarySearch.tsx
  6. +40
    -0
      src/components/SalarySearch/SalarySearchLoading.tsx
  7. +20
    -0
      src/components/SalarySearch/SalarySearchWrapper.tsx
  8. +1
    -0
      src/components/SalarySearch/index.ts

+ 50
- 0
src/app/(main)/settings/salary/page.tsx 파일 보기

@@ -0,0 +1,50 @@
import SalarySearch from "@/components/SalarySearch";
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 { fetchSalarys, preloadSalarys } from "@/app/api/salarys";

export const metadata: Metadata = {
title: "Salary",
};

const Salary: React.FC = async () => {
const { t } = await getServerI18n("Salary");
// Preload necessary dependencies
// fetchSalarys();
// preloadSalarys();
return (
<>
<Stack
direction="row"
justifyContent="space-between"
flexWrap="wrap"
rowGap={2}
>
<Typography variant="h4" marginInlineEnd={2}>
{t("Salary")}
</Typography>
<Button
variant="contained"
startIcon={<Add />}
LinkComponent={Link}
href="/settings/position/new"
>
{t("Create Salary")}
</Button>
</Stack>
<Suspense fallback={<SalarySearch.Loading />}>
<SalarySearch/>
</Suspense>
</>
)
};

export default Salary;

+ 22
- 0
src/app/api/salarys/index.ts 파일 보기

@@ -0,0 +1,22 @@
import { serverFetchJson } from "@/app/utils/fetchUtil";
import { BASE_API_URL } from "@/config/api";
import { cache } from "react";
import "server-only";

export interface SalaryResult {
id: number;
lowerLimit: number;
upperLimit: number;
salaryPoint: number;
salary: number;
}

export const preloadSalarys = () => {
fetchSalarys();
};

export const fetchSalarys = cache(async () => {
return serverFetchJson<SalaryResult[]>(`${BASE_API_URL}/salarys`, {
next: { tags: ["salarys"] },
});
});

+ 1
- 0
src/components/Breadcrumb/Breadcrumb.tsx 파일 보기

@@ -22,6 +22,7 @@ const pathToLabelMap: { [path: string]: string } = {
"/settings/department/new": "Create Department",
"/settings/position": "Position",
"/settings/position/new": "Create Position",
"/settings/salarys": "Salary",
};

const Breadcrumb = () => {


+ 2
- 0
src/components/NavigationContent/NavigationContent.tsx 파일 보기

@@ -21,6 +21,7 @@ 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 Salary from '@mui/icons-material/AttachMoney';
import { useTranslation } from "react-i18next";
import Typography from "@mui/material/Typography";
import { usePathname } from "next/navigation";
@@ -98,6 +99,7 @@ const navigationItems: NavigationItem[] = [
{ icon: <Company />, label: "Company", path: "/settings/company" },
{ icon: <Department />, label: "Department", path: "/settings/department" },
{ icon: <Position />, label: "Position", path: "/settings/position" },
{ icon: <Salary />, label: "Salary", path: "/settings/salary" },
],
},
];


+ 77
- 0
src/components/SalarySearch/SalarySearch.tsx 파일 보기

@@ -0,0 +1,77 @@
"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 { SalaryResult } from "@/app/api/salarys";

interface Props {
salarys: SalaryResult[];
}

type SearchQuery = Partial<Omit<SalaryResult, "id">>;
type SearchParamNames = keyof SearchQuery;

const SalarySearch: React.FC<Props> = ({ salarys }) => {
const { t } = useTranslation("salarys");

const [filteredSalarys, setFilteredSalarys] = useState(salarys);

const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => [
{ label: t("Salary"), paramName: "salary", type: "text" },
{ label: t("Salary Point"), paramName: "salaryPoint", type: "text" },
],
[t, salarys],
);

const onReset = useCallback(() => {
setFilteredSalarys(salarys);
}, [salarys]);

const onSalaryClick = useCallback((project: SalaryResult) => {
console.log(project);
}, []);

const columns = useMemo<Column<SalaryResult>[]>(
() => [
{
name: "id",
label: t("Details"),
onClick: onSalaryClick,
buttonIcon: <EditNote />,
},
{ name: "salaryPoint", label: t("Salary Point") },
{ name: "lowerLimit", label: t("Lower Limit") },
{ name: "upperLimit", label: t("Upper Limit") },
],
[t, onSalaryClick],
);

return (
<>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
setFilteredSalarys(
salarys.filter(
(s) =>
((s.lowerLimit <= Number(query.salary))&&
(s.upperLimit >= Number(query.salary)))||
(s.salaryPoint === Number(query.salaryPoint))
),
);
}}
onReset={onReset}
/>
<SearchResults<SalaryResult>
items={filteredSalarys}
columns={columns}
/>
</>
);
};

export default SalarySearch;

+ 40
- 0
src/components/SalarySearch/SalarySearchLoading.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 SalarySearchLoading: 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>Salary
<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 SalarySearchLoading;

+ 20
- 0
src/components/SalarySearch/SalarySearchWrapper.tsx 파일 보기

@@ -0,0 +1,20 @@
// import { fetchSalaryCategories, fetchSalarys } from "@/app/api/companys";
import React from "react";
import SalarySearch from "./SalarySearch";
import SalarySearchLoading from "./SalarySearchLoading";
import { fetchSalarys } from "@/app/api/salarys";

interface SubComponents {
Loading: typeof SalarySearchLoading;
}

const SalarySearchWrapper: React.FC & SubComponents = async () => {
const Salarys = await fetchSalarys();
// const Salarys:any[] = []

return <SalarySearch salarys={Salarys} />;
};

SalarySearchWrapper.Loading = SalarySearchLoading;

export default SalarySearchWrapper;

+ 1
- 0
src/components/SalarySearch/index.ts 파일 보기

@@ -0,0 +1 @@
export { default } from "./SalarySearchWrapper";

불러오는 중...
취소
저장