FPSMS-frontend
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

UpdateMaintenanceForm.tsx 6.8 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. "use client";
  2. import { useCallback, useEffect, useState } from "react";
  3. import { useRouter } from "next/navigation";
  4. import { useTranslation } from "react-i18next";
  5. import {
  6. Button,
  7. Card,
  8. CardContent,
  9. FormControl,
  10. InputLabel,
  11. MenuItem,
  12. Select,
  13. TextField,
  14. Typography,
  15. Stack,
  16. Grid,
  17. } from "@mui/material";
  18. import { Check, Close } from "@mui/icons-material";
  19. import axiosInstance from "@/app/(main)/axios/axiosInstance";
  20. import { NEXT_PUBLIC_API_URL } from "@/config/api";
  21. type Props = {
  22. id: number;
  23. };
  24. type EquipmentDetailData = {
  25. id: number;
  26. code: string;
  27. name: string;
  28. equipmentCode?: string;
  29. repairAndMaintenanceStatus?: boolean | null;
  30. repairAndMaintenanceRemarks?: string | null;
  31. };
  32. const UpdateMaintenanceForm: React.FC<Props> = ({ id }) => {
  33. const { t } = useTranslation("common");
  34. const router = useRouter();
  35. const [loading, setLoading] = useState(false);
  36. const [fetching, setFetching] = useState(true);
  37. const [equipmentData, setEquipmentData] = useState<EquipmentDetailData | null>(null);
  38. const [status, setStatus] = useState<boolean | null>(null);
  39. const [remarks, setRemarks] = useState<string>("");
  40. useEffect(() => {
  41. const fetchEquipmentDetail = async () => {
  42. try {
  43. setFetching(true);
  44. const response = await axiosInstance.get<EquipmentDetailData>(
  45. `${NEXT_PUBLIC_API_URL}/EquipmentDetail/details/${id}`
  46. );
  47. if (response.data) {
  48. setEquipmentData(response.data);
  49. setStatus(response.data.repairAndMaintenanceStatus ?? null);
  50. setRemarks(response.data.repairAndMaintenanceRemarks ?? "");
  51. }
  52. } catch (error) {
  53. console.error("Error fetching equipment detail:", error);
  54. } finally {
  55. setFetching(false);
  56. }
  57. };
  58. fetchEquipmentDetail();
  59. }, [id]);
  60. const handleSave = useCallback(async () => {
  61. if (!equipmentData) return;
  62. try {
  63. setLoading(true);
  64. const updateData = {
  65. repairAndMaintenanceStatus: status,
  66. repairAndMaintenanceRemarks: remarks,
  67. };
  68. await axiosInstance.put(
  69. `${NEXT_PUBLIC_API_URL}/EquipmentDetail/update/${id}`,
  70. updateData,
  71. {
  72. headers: { "Content-Type": "application/json" },
  73. }
  74. );
  75. router.push("/settings/equipment?tab=1");
  76. } catch (error) {
  77. console.error("Error updating maintenance:", error);
  78. alert(t("Error saving data") || "Error saving data");
  79. } finally {
  80. setLoading(false);
  81. }
  82. }, [equipmentData, status, remarks, id, router, t]);
  83. const handleCancel = useCallback(() => {
  84. router.push("/settings/equipment?tab=1");
  85. }, [router]);
  86. if (fetching) {
  87. return (
  88. <Stack sx={{ p: 3 }}>
  89. <Typography>{t("Loading") || "Loading..."}</Typography>
  90. </Stack>
  91. );
  92. }
  93. if (!equipmentData) {
  94. return (
  95. <Stack sx={{ p: 3 }}>
  96. <Typography>{t("Equipment not found") || "Equipment not found"}</Typography>
  97. </Stack>
  98. );
  99. }
  100. return (
  101. <Stack
  102. spacing={2}
  103. component="form"
  104. >
  105. <Card>
  106. <CardContent component={Stack} spacing={4}>
  107. <Typography variant="overline" display="block" marginBlockEnd={1}>
  108. {t("Equipment Information")}
  109. </Typography>
  110. <Grid container spacing={2} columns={{ xs: 6, sm: 12 }}>
  111. <Grid item xs={6}>
  112. <TextField
  113. label={t("Equipment Name") || "設備名稱"}
  114. value={equipmentData.code || ""}
  115. disabled
  116. fullWidth
  117. variant="filled"
  118. InputLabelProps={{
  119. shrink: !!equipmentData.code,
  120. sx: { fontSize: "0.9375rem" },
  121. }}
  122. InputProps={{
  123. sx: { paddingTop: "8px" },
  124. }}
  125. />
  126. </Grid>
  127. <Grid item xs={6}>
  128. <TextField
  129. label={t("Equipment Code") || "設備編號"}
  130. value={equipmentData.equipmentCode || ""}
  131. disabled
  132. fullWidth
  133. variant="filled"
  134. InputLabelProps={{
  135. shrink: !!equipmentData.equipmentCode,
  136. sx: { fontSize: "0.9375rem" },
  137. }}
  138. InputProps={{
  139. sx: { paddingTop: "8px" },
  140. }}
  141. />
  142. </Grid>
  143. <Grid item xs={6}>
  144. <FormControl fullWidth variant="filled">
  145. <InputLabel
  146. shrink={status !== null}
  147. sx={{ fontSize: "0.9375rem" }}
  148. >
  149. {t("Repair and Maintenance Status")}
  150. </InputLabel>
  151. <Select
  152. value={status === null ? "" : status ? "yes" : "no"}
  153. onChange={(e) => {
  154. const value = e.target.value;
  155. if (value === "yes") {
  156. setStatus(true);
  157. } else if (value === "no") {
  158. setStatus(false);
  159. } else {
  160. setStatus(null);
  161. }
  162. }}
  163. sx={{ paddingTop: "8px" }}
  164. >
  165. <MenuItem value="yes">{t("Yes")}</MenuItem>
  166. <MenuItem value="no">{t("No")}</MenuItem>
  167. </Select>
  168. </FormControl>
  169. </Grid>
  170. <Grid item xs={6}>
  171. <TextField
  172. label={t("Repair and Maintenance Remarks")}
  173. value={remarks}
  174. onChange={(e) => setRemarks(e.target.value)}
  175. fullWidth
  176. multiline
  177. rows={4}
  178. variant="filled"
  179. InputLabelProps={{
  180. shrink: true,
  181. sx: { fontSize: "0.9375rem" },
  182. }}
  183. InputProps={{
  184. sx: {
  185. paddingTop: "8px",
  186. alignItems: "flex-start",
  187. paddingBottom: "8px",
  188. },
  189. }}
  190. sx={{
  191. "& .MuiInputBase-input": {
  192. paddingTop: "16px",
  193. },
  194. }}
  195. />
  196. </Grid>
  197. </Grid>
  198. </CardContent>
  199. </Card>
  200. <Stack direction="row" justifyContent="flex-end" gap={1}>
  201. <Button
  202. variant="outlined"
  203. startIcon={<Close />}
  204. onClick={handleCancel}
  205. disabled={loading}
  206. type="button"
  207. >
  208. {t("Cancel") || "取消"}
  209. </Button>
  210. <Button
  211. variant="contained"
  212. startIcon={<Check />}
  213. onClick={handleSave}
  214. disabled={loading}
  215. type="button"
  216. >
  217. {t("Save") || "保存"}
  218. </Button>
  219. </Stack>
  220. </Stack>
  221. );
  222. };
  223. export default UpdateMaintenanceForm;