25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 

253 satır
7.2 KiB

  1. "use client";
  2. import React, { useCallback, useEffect, useMemo, useState } from "react";
  3. import CustomInputForm from "../CustomInputForm";
  4. import { useRouter } from "next/navigation";
  5. import { useTranslation } from "react-i18next";
  6. import {
  7. FieldErrors,
  8. FormProvider,
  9. SubmitErrorHandler,
  10. SubmitHandler,
  11. useForm,
  12. useFormContext,
  13. } from "react-hook-form";
  14. // import CreateTeamForm from "../CreateTeamForm";
  15. import { CreateTeamInputs } from "@/app/api/team/actions";
  16. // import { Staff4TransferList, fetchStaffCombo } from "@/app/api/staff/actions";
  17. import { StaffResult } from "@/app/api/staff";
  18. import SearchResults, { Column } from "../SearchResults";
  19. import { Clear, PersonAdd, PersonRemove, Search } from "@mui/icons-material";
  20. import { Card } from "reactstrap";
  21. import {
  22. Box,
  23. CardContent,
  24. Grid,
  25. IconButton,
  26. InputAdornment,
  27. Stack,
  28. Tab,
  29. Tabs,
  30. TabsProps,
  31. TextField,
  32. Typography,
  33. } from "@mui/material";
  34. import { differenceBy } from "lodash";
  35. import StarsIcon from "@mui/icons-material/Stars";
  36. export interface Props {
  37. allStaffs: StaffResult[];
  38. }
  39. const StaffAllocation: React.FC<Props> = ({ allStaffs: staff }) => {
  40. const { t } = useTranslation();
  41. const {
  42. setValue,
  43. getValues,
  44. formState: { defaultValues },
  45. reset,
  46. resetField,
  47. } = useFormContext<CreateTeamInputs>();
  48. const initialStaffs = staff.map((s) => ({ ...s }));
  49. // console.log(initialStaffs)
  50. const [filteredStaff, setFilteredStaff] = useState(initialStaffs);
  51. const [selectedStaff, setSelectedStaff] = useState<typeof filteredStaff>(
  52. initialStaffs.filter((s) => getValues("addStaffIds")?.includes(s.id))
  53. );
  54. // Adding / Removing staff
  55. const addStaff = useCallback((staff: StaffResult) => {
  56. setSelectedStaff((s) => [...s, staff]);
  57. }, []);
  58. const removeStaff = useCallback((staff: StaffResult) => {
  59. setSelectedStaff((s) => s.filter((s) => s.id !== staff.id));
  60. }, []);
  61. const setTeamLead = useCallback(
  62. (staff: StaffResult) => {
  63. const rearrangedList = getValues("addStaffIds").reduce<number[]>(
  64. (acc, num, index) => {
  65. if (num === staff.id && index !== 0) {
  66. acc.splice(index, 1);
  67. acc.unshift(num);
  68. }
  69. return acc;
  70. },
  71. getValues("addStaffIds")
  72. );
  73. console.log(rearrangedList);
  74. console.log(selectedStaff);
  75. const rearrangedStaff = rearrangedList.map((id) => {
  76. return selectedStaff.find((staff) => staff.id === id);
  77. });
  78. console.log(rearrangedStaff);
  79. setSelectedStaff(rearrangedStaff as StaffResult[]);
  80. setValue("addStaffIds", rearrangedList);
  81. },
  82. [addStaff, selectedStaff]
  83. );
  84. const clearSubsidiary = useCallback(() => {
  85. if (defaultValues !== undefined) {
  86. resetField("addStaffIds");
  87. setSelectedStaff(
  88. initialStaffs.filter((s) => defaultValues.addStaffIds?.includes(s.id))
  89. );
  90. }
  91. }, [defaultValues]);
  92. // Sync with form
  93. useEffect(() => {
  94. console.log(selectedStaff);
  95. setValue(
  96. "addStaffIds",
  97. selectedStaff.map((s) => s.id)
  98. );
  99. }, [selectedStaff, setValue]);
  100. useEffect(() => {
  101. console.log(selectedStaff);
  102. }, [selectedStaff]);
  103. const StaffPoolColumns = useMemo<Column<StaffResult>[]>(
  104. () => [
  105. {
  106. label: t("Add"),
  107. name: "id",
  108. onClick: addStaff,
  109. buttonIcon: <PersonAdd />,
  110. },
  111. { label: t("Staff Id"), name: "staffId" },
  112. { label: t("Staff Name"), name: "name" },
  113. { label: t("Position"), name: "currentPosition" },
  114. ],
  115. [addStaff, t]
  116. );
  117. const allocatedStaffColumns = useMemo<Column<StaffResult>[]>(
  118. () => [
  119. {
  120. label: t("Remove"),
  121. name: "action",
  122. onClick: removeStaff,
  123. buttonIcon: <PersonRemove />,
  124. },
  125. { label: t("Staff Id"), name: "staffId" },
  126. { label: t("Staff Name"), name: "name" },
  127. { label: t("Position"), name: "currentPosition" },
  128. {
  129. label: t("Team Lead"),
  130. name: "action",
  131. onClick: setTeamLead,
  132. buttonIcon: <StarsIcon />,
  133. },
  134. ],
  135. [removeStaff, selectedStaff, t]
  136. );
  137. const [query, setQuery] = React.useState("");
  138. const onQueryInputChange = React.useCallback<
  139. React.ChangeEventHandler<HTMLInputElement>
  140. >((e) => {
  141. setQuery(e.target.value);
  142. }, []);
  143. const clearQueryInput = React.useCallback(() => {
  144. setQuery("");
  145. }, []);
  146. React.useEffect(() => {
  147. setFilteredStaff(
  148. initialStaffs.filter((i) => {
  149. const q = query.toLowerCase();
  150. return (
  151. i.staffId.toLowerCase().includes(q) ||
  152. i.name.toLowerCase().includes(q) ||
  153. i.currentPosition.toLowerCase().includes(q)
  154. );
  155. })
  156. );
  157. }, [staff, query]);
  158. const resetStaff = React.useCallback(() => {
  159. clearQueryInput();
  160. clearSubsidiary();
  161. }, [clearQueryInput, clearSubsidiary]);
  162. const formProps = useForm({});
  163. // Tab related
  164. const [tabIndex, setTabIndex] = React.useState(0);
  165. const handleTabChange = React.useCallback<NonNullable<TabsProps["onChange"]>>(
  166. (_e, newValue) => {
  167. setTabIndex(newValue);
  168. },
  169. []
  170. );
  171. return (
  172. <>
  173. <FormProvider {...formProps}>
  174. <Card sx={{ display: "block" }}>
  175. <CardContent
  176. sx={{ display: "flex", flexDirection: "column", gap: 1 }}
  177. >
  178. <Stack gap={2}>
  179. <Typography variant="overline" display="block">
  180. {t("staff")}
  181. </Typography>
  182. <Grid container spacing={2} columns={{ xs: 6, sm: 12 }}>
  183. <Grid item xs={6} display="flex" alignItems="center">
  184. <Search sx={{ marginInlineEnd: 1 }} />
  185. <TextField
  186. variant="standard"
  187. fullWidth
  188. onChange={onQueryInputChange}
  189. value={query}
  190. placeholder={t("Search by Staff Id, Name or Position.")}
  191. InputProps={{
  192. endAdornment: query && (
  193. <InputAdornment position="end">
  194. <IconButton onClick={clearQueryInput}>
  195. <Clear />
  196. </IconButton>
  197. </InputAdornment>
  198. ),
  199. }}
  200. />
  201. </Grid>
  202. </Grid>
  203. <Tabs value={tabIndex} onChange={handleTabChange}>
  204. <Tab label={t("Staff Pool")} />
  205. <Tab
  206. label={`${t("Allocated Staff")} (${selectedStaff.length})`}
  207. />
  208. </Tabs>
  209. <Box sx={{ marginInline: -3 }}>
  210. {tabIndex === 0 && (
  211. <SearchResults
  212. noWrapper
  213. items={differenceBy(filteredStaff, selectedStaff, "id")}
  214. columns={StaffPoolColumns}
  215. />
  216. )}
  217. {tabIndex === 1 && (
  218. <SearchResults
  219. noWrapper
  220. items={selectedStaff}
  221. columns={allocatedStaffColumns}
  222. />
  223. )}
  224. </Box>
  225. </Stack>
  226. </CardContent>
  227. </Card>
  228. </FormProvider>
  229. </>
  230. );
  231. };
  232. export default StaffAllocation;