Переглянути джерело

staff and skill update

tags/Baseline_30082024_FRONTEND_UAT
MSI\derek 1 рік тому
джерело
коміт
71d0b03db6
7 змінених файлів з 61 додано та 24 видалено
  1. +3
    -3
      src/app/api/skill/actions.ts
  2. +17
    -3
      src/components/CreateSkill/CreateSkill.tsx
  3. +3
    -2
      src/components/CreateSkill/CreateSkillWrapper.tsx
  4. +2
    -2
      src/components/CreateStaff/CreateStaff.tsx
  5. +24
    -11
      src/components/StaffSearch/StaffSearch.tsx
  6. +11
    -3
      src/components/StaffSearch/StaffSearchWrapper.tsx
  7. +1
    -0
      src/i18n/zh/staff.json

+ 3
- 3
src/app/api/skill/actions.ts Переглянути файл

@@ -8,9 +8,9 @@ import { cache } from "react";

export interface CreateSkillInputs {
id?: number;
name: String;
code: String;
description: String;
name: string;
code: string;
description: string;
}

export interface comboProp {


+ 17
- 3
src/components/CreateSkill/CreateSkill.tsx Переглянути файл

@@ -15,10 +15,16 @@ import { useTranslation } from "react-i18next";
import { CreateSkillInputs, saveSkill } from "@/app/api/skill/actions";
import { Error } from "@mui/icons-material";
import SkillInfo from "./SkillInfo";
import { SkillResult } from "@/app/api/skill";

interface Props {}
interface Props {
skill: SkillResult[]
}

const CreateSkill: React.FC<Props> = () => {
const CreateSkill: React.FC<Props> = ({
skill
}) => {
const codeList = skill.map(s => s.code.toLowerCase().trim())
const formProps = useForm<CreateSkillInputs>();
const [serverError, setServerError] = useState("");
const router = useRouter();
@@ -29,7 +35,15 @@ const CreateSkill: React.FC<Props> = () => {
const onSubmit = useCallback<SubmitHandler<CreateSkillInputs>>(
async (data) => {
try {
console.log(data);
let haveError = false
haveError = codeList.includes(data.code.toLowerCase().trim())
if (haveError) {
formProps.setError("code", { message: t("Duplicated Code"), type: "required" })
return
}
data.name = data.name.trim()
data.code = data.code.trim()
data.description = data.description.trim()
await saveSkill(data)
router.replace(`/settings/skill`)
} catch (e) {


+ 3
- 2
src/components/CreateSkill/CreateSkillWrapper.tsx Переглянути файл

@@ -3,15 +3,16 @@ import CreateSkill from "./CreateSkill";
import CreateSkillLoading from "./CreateSkillLoading";
import { fetchStaff, fetchTeamLeads } from "@/app/api/staff";
import { useSearchParams } from "next/navigation";
import { fetchSkill } from "@/app/api/skill";

interface SubComponents {
Loading: typeof CreateSkillLoading;
}

const CreateSkillWrapper: React.FC & SubComponents = async () => {
const skill = await fetchSkill()


return <CreateSkill/>;
return <CreateSkill skill={skill}/>;
};

CreateSkillWrapper.Loading = CreateSkillLoading;


+ 2
- 2
src/components/CreateStaff/CreateStaff.tsx Переглянути файл

@@ -69,8 +69,8 @@ const CreateStaff: React.FC<formProps> = ({ combos }) => {
try {
console.log(data);
let haveError = false;
let regex_email = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/
let regex_phone = /^\d{8}$/
const regex_email = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/
const regex_phone = /^\d{8}$/

if (!regex_email.test(data.email)) {
haveError = true


+ 24
- 11
src/components/StaffSearch/StaffSearch.tsx Переглянути файл

@@ -11,27 +11,38 @@ import { useRouter } from "next/navigation";
import { deleteDialog, successDialog } from "../Swal/CustomAlerts";
import Person from '@mui/icons-material/Person';
import { MAINTAIN_USER, VIEW_USER } from "@/middleware";
import { TeamResult } from "@/app/api/team";
import { Grade } from "@/app/api/grades";
import { PositionResult } from "@/app/api/positions";

interface Props {
staff: StaffResult[];
abilities: string[]
teams: TeamResult[]
grades: Grade[]
positions: PositionResult[]
isAuthed: boolean
}

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

const StaffSearch: React.FC<Props> = ({ staff, abilities }) => {
const StaffSearch: React.FC<Props> = ({ staff, teams, grades, positions, isAuthed }) => {
console.log(staff)
const { t } = useTranslation();
const [filteredStaff, setFilteredStaff] = useState(staff);
const router = useRouter();

const teamCombo = teams.map(t => `${t.name} - ${t.code}`)
const gradeCombo = grades.map(g => `${g.name}`)
const positionCombo = positions.map(p => `${p.name}`)

const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => [
{
label: t("Team"),
paramName: "team",
type: "select",
options: ["1", "2"],
options: teamCombo,
},
{
label: t("Staff Name"),
@@ -47,13 +58,13 @@ const StaffSearch: React.FC<Props> = ({ staff, abilities }) => {
label: t("Grade"),
paramName: "grade",
type: "select",
options: ["pos1", "CEO"],
options: gradeCombo,
},
{
label: t("Current Position"),
paramName: "currentPosition",
type: "select",
options: ["pos1", "CEO"],
options: positionCombo,
},
],
[t]
@@ -97,7 +108,7 @@ const StaffSearch: React.FC<Props> = ({ staff, abilities }) => {
label: t("Users"),
onClick: onUserClick,
buttonIcon: <Person />,
isHidden: ![MAINTAIN_USER, VIEW_USER].some((ability) => abilities.includes(ability)),
isHidden: !isAuthed,
},
{ name: "team", label: t("Team") },
{ name: "name", label: t("Staff Name") },
@@ -114,20 +125,22 @@ const StaffSearch: React.FC<Props> = ({ staff, abilities }) => {
],
[t, onStaffClick, deleteClick]
);
// postData.teamId = team[index].id

return (
<>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
// console.log(teamCombo.findIndex(team => team === query.team))
setFilteredStaff(
staff.filter(
(s) =>
s.staffId.toLowerCase().includes(query.staffId.toLowerCase()) &&
s.name.toLowerCase().includes(query.name.toLowerCase())
// (query.team === "All" || s.team === query.team) &&
// (query.category === "All" || s.category === query.category) &&
// (query.team === "All" || s.team === query.team),
s.staffId.toLowerCase().includes(query.staffId.toLowerCase())
&& s.name.toLowerCase().includes(query.name.toLowerCase())
&& (query.team === "All" || s.teamId === teams[teamCombo.findIndex(team => team === query.team)].id)
&& (query.grade === "All" || s.grade === query.grade)
&& (query.currentPosition === "All" || s.currentPosition === query.currentPosition)
)
);
}}


+ 11
- 3
src/components/StaffSearch/StaffSearchWrapper.tsx Переглянути файл

@@ -4,6 +4,10 @@ import StaffSearch from "./StaffSearch";
import StaffSearchLoading from "./StaffSearchLoading";
import { Session, getServerSession } from "next-auth";
import { authOptions } from "@/config/authConfig";
import { fetchTeam } from "@/app/api/team";
import { fetchPositions } from "@/app/api/positions";
import { fetchGrades } from "@/app/api/grades";
import { MAINTAIN_USER, VIEW_USER } from "@/middleware";

interface SubComponents {
Loading: typeof StaffSearchLoading;
@@ -14,11 +18,15 @@ interface SessionWithAbilities extends Session {
}

const StaffSearchWrapper: React.FC & SubComponents = async () => {
const staff = await fetchStaff();
const session = await getServerSession(authOptions) as SessionWithAbilities;
const abilities: string[] = session.abilities!!
const isAuthed = ![MAINTAIN_USER, VIEW_USER].some((ability) => session.abilities!.includes(ability))

const staff = await fetchStaff();
const teams = await fetchTeam();
const grades = await fetchGrades();
const positions = await fetchPositions();

return <StaffSearch staff={staff} abilities={abilities}/>;
return <StaffSearch staff={staff} teams={teams} grades={grades} positions={positions} isAuthed={isAuthed}/>;
};

StaffSearchWrapper.Loading = StaffSearchLoading;


+ 1
- 0
src/i18n/zh/staff.json Переглянути файл

@@ -25,6 +25,7 @@
"Depart Date": "離職日期",
"Depart Reason": "離職原因",
"Remark": "備註",
"Reset": "重設",
"Confirm": "確認",
"Cancel": "取消"
}

Завантаження…
Відмінити
Зберегти