import React, { useEffect, useState } from "react"; import { HttpError, IResourceComponentsProps, useTranslate } from "@refinedev/core"; import { Edit, useForm, useSelect } from "@refinedev/antd"; import { Form, Input, DatePicker, Select, InputNumber, Radio, Divider, Alert, Typography } from "antd"; import dayjs from "dayjs"; import TextArea from "antd/es/input/TextArea"; import { IFilament } from "../filaments/model"; import { ISpool, ISpoolParsedExtras } from "./model"; import { numberFormatter, numberParser } from "../../utils/parsing"; import { useSpoolmanLocations } from "../../components/otherModels"; import { message } from "antd/lib"; import { EntityType, useGetFields } from "../../utils/queryFields"; import { ExtraFieldFormItem, StringifiedExtras } from "../../components/extraFields"; import { ParsedExtras } from "../../components/extraFields"; /* The API returns the extra fields as JSON values, but we need to parse them into their real types in order for Ant design's form to work properly. ParsedExtras does this for us. We also need to stringify them again before sending them back to the API, which is done by overriding the form's onFinish method. Form.Item's normalize should do this, but it doesn't seem to work. */ export const SpoolEdit: React.FC = () => { const t = useTranslate(); const [messageApi, contextHolder] = message.useMessage(); const [hasChanged, setHasChanged] = useState(false); const extraFields = useGetFields(EntityType.spool); const { form, formProps, saveButtonProps } = useForm({ liveMode: "manual", onLiveEvent() { // Warn the user if the spool has been updated since the form was opened messageApi.warning(t("spool.form.spool_updated")); setHasChanged(true); }, queryOptions: { select(data) { return { data: ParsedExtras(data.data), }; }, }, }); // Get filament selection options const { queryResult } = useSelect({ resource: "filament", }); // Override the form's onFinish method to stringify the extra fields const originalOnFinish = formProps.onFinish; formProps.onFinish = (allValues: ISpoolParsedExtras) => { if (allValues !== undefined && allValues !== null) { allValues = StringifiedExtras(allValues); } originalOnFinish?.(allValues); }; const filamentOptions = queryResult.data?.data.map((item) => { let vendorPrefix = ""; if (item.vendor) { vendorPrefix = `${item.vendor.name} - `; } let name = item.name; if (!name) { name = `ID: ${item.id}`; } let material = ""; if (item.material) { material = ` - ${item.material}`; } const label = `${vendorPrefix}${name}${material}`; return { label: label, value: item.id, weight: item.weight, spool_weight: item.spool_weight, }; }); filamentOptions?.sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: "base" })); const [weightToEnter, setWeightToEnter] = useState(1); const [usedWeight, setUsedWeight] = useState(0); const selectedFilamentID = Form.useWatch("filament_id", form); const selectedFilament = filamentOptions?.find((obj) => { return obj.value === selectedFilamentID; }); const filamentWeight = selectedFilament?.weight || 0; const spoolWeight = selectedFilament?.spool_weight || 0; const filamentChange = (newID: number) => { const newSelectedFilament = filamentOptions?.find((obj) => { return obj.value === newID; }); const newFilamentWeight = newSelectedFilament?.weight || 0; const newSpoolWeight = newSelectedFilament?.spool_weight || 0; if (weightToEnter >= 3) { if (!(newFilamentWeight && newSpoolWeight)) { setWeightToEnter(2); } } if (weightToEnter >= 2) { if (!newFilamentWeight) { setWeightToEnter(1); } } }; const weightChange = (weight: number) => { setUsedWeight(weight); form.setFieldValue("used_weight", weight); }; const locations = useSpoolmanLocations(true); const [newLocation, setNewLocation] = useState(""); const allLocations = [...(locations.data || [])]; if (newLocation.trim() && !allLocations.includes(newLocation)) { allLocations.push(newLocation.trim()); } if (formProps.initialValues) { formProps.initialValues["filament_id"] = formProps.initialValues["filament"].id; } useEffect(() => { if (formProps.initialValues) { setUsedWeight(formProps.initialValues["used_weight"]); } }, [formProps.initialValues]); return ( {contextHolder}
({ value: value ? dayjs(value) : undefined, })} > ({ value: value ? dayjs(value) : undefined, })} > ({ value: value ? dayjs(value) : undefined, })} > ( <> {menu} setNewLocation(event.target.value)} /> )} loading={locations.isLoading} options={allLocations.map((item) => ({ label: item, value: item }))} />