|
- import { BomCombo } from "@/app/api/bom";
- import { JoDetail } from "@/app/api/jo";
- import { SaveJo, manualCreateJo } from "@/app/api/jo/actions";
- import { OUTPUT_DATE_FORMAT, OUTPUT_TIME_FORMAT, dateStringToDayjs, dayjsToDateString, dayjsToDateTimeString } from "@/app/utils/formatUtil";
- import { Check } from "@mui/icons-material";
- import { Autocomplete, Box, Button, Card, Grid, Modal, Stack, TextField, Typography ,FormControl, InputLabel, Select, MenuItem,InputAdornment} from "@mui/material";
- import { DatePicker, DateTimePicker, LocalizationProvider } from "@mui/x-date-pickers";
- import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
- import dayjs, { Dayjs } from "dayjs";
- import { isFinite } from "lodash";
- import React, { SetStateAction, SyntheticEvent, useCallback, useEffect } from "react";
- import { Controller, FormProvider, SubmitErrorHandler, SubmitHandler, useForm, useFormContext } from "react-hook-form";
- import { useTranslation } from "react-i18next";
- import { msg } from "../Swal/CustomAlerts";
-
- interface Props {
- open: boolean;
- bomCombo: BomCombo[];
- onClose: () => void;
- onSearch: () => void;
- }
-
- const JoCreateFormModal: React.FC<Props> = ({
- open,
- bomCombo,
- onClose,
- onSearch,
- }) => {
- const { t } = useTranslation("jo");
- const formProps = useForm<SaveJo>({
- mode: "onChange",
- });
- const { reset, trigger, watch, control, register, formState: { errors } } = formProps
-
- const onModalClose = useCallback(() => {
- reset()
- onClose()
- }, [])
-
- const handleAutoCompleteChange = useCallback((event: SyntheticEvent<Element, Event>, value: BomCombo, onChange: (...event: any[]) => void) => {
- onChange(value.id)
- if (value.outputQty != null) {
- formProps.setValue("reqQty", Number(value.outputQty), { shouldValidate: true, shouldDirty: true })
- }
- }, [])
-
- const handleDateTimePickerChange = useCallback((value: Dayjs | null, onChange: (...event: any[]) => void) => {
- if (value != null) {
- const updatedValue = dayjsToDateTimeString(value)
- onChange(updatedValue)
- } else {
- onChange(value)
- }
- }, [])
-
- const onSubmit = useCallback<SubmitHandler<SaveJo>>(async (data) => {
- data.type = "manual"
- if (data.planStart) {
- const dateDayjs = dateStringToDayjs(data.planStart)
- data.planStart = dayjsToDateTimeString(dateDayjs.startOf('day'))
- }
- data.jobTypeId = Number(data.jobTypeId);
- const response = await manualCreateJo(data)
- if (response) {
- onSearch();
- msg(t("update success"));
- onModalClose();
- }
- }, [onSearch, onModalClose, t])
-
- const onSubmitError = useCallback<SubmitErrorHandler<SaveJo>>((error) => {
- console.log(error)
- }, [])
-
- const planStart = watch("planStart")
- const planEnd = watch("planEnd")
- useEffect(() => {
- trigger(['planStart', 'planEnd']);
- }, [trigger, planStart, planEnd])
-
- return (
- <Modal
- open={open}
- onClose={onModalClose}
- >
- <Card
- style={{
- flex: 10,
- marginBottom: "20px",
- width: "90%",
- // height: "80%",
- position: "fixed",
- top: "50%",
- left: "50%",
- transform: "translate(-50%, -50%)",
- }}
- >
- <Box
- sx={{
- display: "flex",
- "flex-direction": "column",
- padding: "20px",
- height: "100%", //'30rem',
- width: "100%",
- "& .actions": {
- color: "text.secondary",
- },
- "& .header": {
- // border: 1,
- // 'border-width': '1px',
- // 'border-color': 'grey',
- },
- "& .textPrimary": {
- color: "text.primary",
- },
- }}
- >
- <FormProvider {...formProps}>
- <Stack
- // spacing={2}
- component="form"
- onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
- >
- <LocalizationProvider
- dateAdapter={AdapterDayjs}
- // TODO: Should maybe use a custom adapterLocale here to support YYYY-MM-DD
- adapterLocale="zh-hk"
- >
- <Grid container spacing={2}>
- <Grid item xs={12} sm={12} md={12}>
- <Typography variant="h6">{t("Create Job Order")}</Typography>
- </Grid>
- <Grid item xs={12} sm={12} md={6}>
- <Controller
- control={control}
- name="bomId"
- rules={{
- required: "Bom required!",
- validate: (value) => isFinite(value)
- }}
- render={({ field, fieldState: { error } }) => (
- <Autocomplete
- disableClearable
- options={bomCombo}
- onChange={(event, value) => {
- handleAutoCompleteChange(event, value, field.onChange)
- }}
- onBlur={field.onBlur}
- renderInput={(params) => (
- <TextField
- {...params}
- error={Boolean(error)}
- variant="outlined"
- label={t("Bom")}
- />
- )}
- />
- )}
- />
- </Grid>
- <Grid item xs={12} sm={12} md={6}>
- <Controller
- control={control}
- name="reqQty"
- rules={{
- required: "Req. Qty. required!",
- validate: (value) => value > 0
- }}
- render={({ field, fieldState: { error } }) => {
- const selectedBom = bomCombo.find(bom => bom.id === formProps.watch("bomId"));
- const uom = selectedBom?.outputQtyUom || "";
-
- return (
- <TextField
- {...field}
- label={t("Req. Qty")}
- fullWidth
- error={Boolean(error)}
- variant="outlined"
- type="number"
- disabled={true}
- value={field.value ?? ""}
- onChange={(e) => {
- const val = e.target.value === "" ? undefined : Number(e.target.value);
- field.onChange(val);
- }}
- InputProps={{
- endAdornment: uom ? (
- <InputAdornment position="end">
- <Typography variant="body2" sx={{ color: "text.secondary" }}>
- {uom}
- </Typography>
- </InputAdornment>
- ) : null
- }}
- />
- );
- }}
- />
- </Grid>
- <Grid item xs={12} sm={12} md={6}>
- <Controller
- control={control}
- name="jobTypeId"
- rules={{ required: t("Job Type required!") as string }}
- render={({ field, fieldState: { error } }) => (
- <FormControl fullWidth error={Boolean(error)}>
- <InputLabel>{t("Job Type")}</InputLabel>
- <Select
- {...field}
- label={t("Job Type")}
- value={field.value?.toString() ?? ""}
- onChange={(event) => {
- const value = event.target.value;
- field.onChange(value === "" ? undefined : Number(value));
- }}
- >
- <MenuItem value="">
- <em>{t("Please select")}</em>
- </MenuItem>
- <MenuItem value="1">{t("FG")}</MenuItem>
- <MenuItem value="2">{t("WIP")}</MenuItem>
- <MenuItem value="3">{t("R&D")}</MenuItem>
- <MenuItem value="4">{t("STF")}</MenuItem>
- <MenuItem value="5">{t("Other")}</MenuItem>
- </Select>
- {/*{error && <FormHelperText>{error.message}</FormHelperText>}*/}
- </FormControl>
- )}
- />
- </Grid>
- <Grid item xs={12} sm={12} md={6}>
- <Controller
- control={control}
- name="planStart"
- rules={{
- required: "Plan start required!",
- validate: {
- isValid: (value) => dateStringToDayjs(value).isValid(),
- // isBeforePlanEnd: (value) => {
- // const planStartDayjs = dateStringToDayjs(value)
- // const planEndDayjs = dateStringToDayjs(planEnd)
- // return planStartDayjs.isBefore(planEndDayjs) || planStartDayjs.isSame(planEndDayjs)
- // }
- }
- }}
- render={({ field, fieldState: { error } }) => (
- // <DateTimePicker
- <DatePicker
- label={t("Plan Start")}
- // views={['year','month','day','hours', 'minutes', 'seconds']}
- //format={`${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`}
- format={OUTPUT_DATE_FORMAT}
- value={field.value ? dateStringToDayjs(field.value) : null}
- onChange={(newValue: Dayjs | null) => {
- handleDateTimePickerChange(newValue, field.onChange)
- }}
- slotProps={{ textField: { fullWidth: true, error: Boolean(error) } }}
- />
- )}
- />
- </Grid>
- {/* <Grid item xs={12} sm={12} md={6}>
- <Controller
- control={control}
- name="planEnd"
- rules={{
- required: "Plan end required!",
- validate: {
- isValid: (value) => dateStringToDayjs(value).isValid(),
- isBeforePlanEnd: (value) => {
- const planStartDayjs = dateStringToDayjs(planStart)
- const planEndDayjs = dateStringToDayjs(value)
- return planEndDayjs.isAfter(planStartDayjs) || planEndDayjs.isSame(planStartDayjs)
- }
- }
- }}
- render={({ field, fieldState: { error } }) => (
- <DateTimePicker
- label={t("Plan End")}
- format={`${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`}
- onChange={(newValue: Dayjs | null) => {
- handleDateTimePickerChange(newValue, field.onChange)
- }}
- slotProps={{ textField: { fullWidth: true } }}
- />
- )}
- />
- </Grid> */}
- </Grid>
- <Stack
- direction="row"
- justifyContent="flex-end"
- spacing={2}
- sx={{ mt: 2 }}
- >
- <Button
- name="submit"
- variant="contained"
- startIcon={<Check />}
- type="submit"
- >
- {t("Create")}
- </Button>
- </Stack>
- </LocalizationProvider>
- </Stack>
- </FormProvider>
- </Box>
- </Card>
- </Modal>
- )
- }
-
- export default JoCreateFormModal;
|