Some cleanup in create spool page
This commit is contained in:
@@ -29,6 +29,7 @@ import utc from "dayjs/plugin/utc";
|
|||||||
import { getCurrencySymbol, useCurrency } from "../../utils/settings";
|
import { getCurrencySymbol, useCurrency } from "../../utils/settings";
|
||||||
import { ExternalFilament, useGetExternalDBFilaments } from "../../utils/queryExternalDB";
|
import { ExternalFilament, useGetExternalDBFilaments } from "../../utils/queryExternalDB";
|
||||||
import { createFilamentFromExternal } from "../filaments/functions";
|
import { createFilamentFromExternal } from "../filaments/functions";
|
||||||
|
import { formatFilamentLabel, useGetFilamentSelectOptions } from "./functions";
|
||||||
|
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc);
|
||||||
|
|
||||||
@@ -40,23 +41,6 @@ type ISpoolRequest = Omit<ISpoolParsedExtras, "id" | "registered"> & {
|
|||||||
filament_id: number | string;
|
filament_id: number | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function formatFilamentLabel(name: string, diameter: number, vendorName?: string, material?: string, weight?: number) {
|
|
||||||
const portions = [];
|
|
||||||
if (vendorName) {
|
|
||||||
portions.push(vendorName);
|
|
||||||
}
|
|
||||||
portions.push(name);
|
|
||||||
const extras = [];
|
|
||||||
if (material) {
|
|
||||||
extras.push(material);
|
|
||||||
}
|
|
||||||
extras.push(formatLength(diameter));
|
|
||||||
if (weight) {
|
|
||||||
extras.push(formatWeight(weight));
|
|
||||||
}
|
|
||||||
return `${portions.join(" - ")} (${extras.join(", ")})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a case-insensitive search for the given query in the given string.
|
* Performs a case-insensitive search for the given query in the given string.
|
||||||
* The query is broken down into words and the search is performed on each word.
|
* The query is broken down into words and the search is performed on each word.
|
||||||
@@ -70,7 +54,6 @@ export const SpoolCreate: React.FC<IResourceComponentsProps & CreateOrCloneProps
|
|||||||
const t = useTranslate();
|
const t = useTranslate();
|
||||||
const extraFields = useGetFields(EntityType.spool);
|
const extraFields = useGetFields(EntityType.spool);
|
||||||
const currency = useCurrency();
|
const currency = useCurrency();
|
||||||
const externalFilaments = useGetExternalDBFilaments();
|
|
||||||
|
|
||||||
const { form, formProps, formLoading, onFinish, redirect } = useForm<
|
const { form, formProps, formLoading, onFinish, redirect } = useForm<
|
||||||
ISpool,
|
ISpool,
|
||||||
@@ -107,12 +90,25 @@ export const SpoolCreate: React.FC<IResourceComponentsProps & CreateOrCloneProps
|
|||||||
formProps.initialValues.filament_id = parseInt(filament_id);
|
formProps.initialValues.filament_id = parseInt(filament_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set up the filament selection options
|
||||||
|
//
|
||||||
|
const { options: filamentOptions, getById, allExternalFilaments } = useGetFilamentSelectOptions();
|
||||||
|
|
||||||
|
const selectedFilamentID = Form.useWatch("filament_id", form);
|
||||||
|
const selectedFilament = getById(selectedFilamentID);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Submit handler
|
||||||
|
//
|
||||||
|
|
||||||
const handleSubmit = async (redirectTo: "list" | "edit" | "create") => {
|
const handleSubmit = async (redirectTo: "list" | "edit" | "create") => {
|
||||||
const values = StringifiedExtras(await form.validateFields());
|
const values = StringifiedExtras(await form.validateFields());
|
||||||
if (typeof values.filament_id === "string") {
|
const selectOption = getById(values.filament_id);
|
||||||
|
if (selectOption?.is_internal === false) {
|
||||||
// Filament ID being a string indicates its an external filament.
|
// Filament ID being a string indicates its an external filament.
|
||||||
// If so, we should first create the internal filament version, then create the spool(s)
|
// If so, we should first create the internal filament version, then create the spool(s)
|
||||||
const externalFilament = externalFilaments.data?.find((f) => f.id === values.filament_id);
|
const externalFilament = allExternalFilaments?.find((f) => f.id === values.filament_id);
|
||||||
if (!externalFilament) {
|
if (!externalFilament) {
|
||||||
throw new Error("Unknown external filament");
|
throw new Error("Unknown external filament");
|
||||||
}
|
}
|
||||||
@@ -131,10 +127,6 @@ export const SpoolCreate: React.FC<IResourceComponentsProps & CreateOrCloneProps
|
|||||||
redirect(redirectTo);
|
redirect(redirectTo);
|
||||||
};
|
};
|
||||||
|
|
||||||
const { queryResult: filamentsQuery } = useSelect<IFilament>({
|
|
||||||
resource: "filament",
|
|
||||||
});
|
|
||||||
|
|
||||||
// Use useEffect to update the form's initialValues when the extra fields are loaded
|
// Use useEffect to update the form's initialValues when the extra fields are loaded
|
||||||
// This is necessary because the form is rendered before the extra fields are loaded
|
// This is necessary because the form is rendered before the extra fields are loaded
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -146,72 +138,6 @@ export const SpoolCreate: React.FC<IResourceComponentsProps & CreateOrCloneProps
|
|||||||
});
|
});
|
||||||
}, [form, extraFields.data, formProps.initialValues]);
|
}, [form, extraFields.data, formProps.initialValues]);
|
||||||
|
|
||||||
//
|
|
||||||
// Set up the filament selection options
|
|
||||||
//
|
|
||||||
|
|
||||||
interface SelectOption {
|
|
||||||
label: string;
|
|
||||||
value: string | number;
|
|
||||||
weight?: number;
|
|
||||||
spool_weight?: number;
|
|
||||||
is_internal: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filamentSelectInternal: SelectOption[] | undefined = filamentsQuery.data?.data.map((item) => {
|
|
||||||
return {
|
|
||||||
label: formatFilamentLabel(
|
|
||||||
item.name ?? `ID ${item.id}`,
|
|
||||||
item.diameter,
|
|
||||||
item.vendor?.name,
|
|
||||||
item.material,
|
|
||||||
item.weight
|
|
||||||
),
|
|
||||||
value: item.id,
|
|
||||||
weight: item.weight,
|
|
||||||
spool_weight: item.spool_weight,
|
|
||||||
is_internal: true,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
filamentSelectInternal?.sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: "base" }));
|
|
||||||
|
|
||||||
const filamentSelectExternal: SelectOption[] | undefined = externalFilaments.data?.map((item) => {
|
|
||||||
return {
|
|
||||||
label: formatFilamentLabel(item.name, item.diameter, item.manufacturer, item.material, item.weight),
|
|
||||||
value: item.id,
|
|
||||||
weight: item.weight,
|
|
||||||
spool_weight: item.spool_weight || undefined,
|
|
||||||
is_internal: false,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
filamentSelectExternal?.sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: "base" }));
|
|
||||||
|
|
||||||
const filamentSelectOptions = [
|
|
||||||
{
|
|
||||||
label: <span>{t("spool.fields.filament_internal")}</span>,
|
|
||||||
options: filamentSelectInternal ?? [],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: <span>{t("spool.fields.filament_external")}</span>,
|
|
||||||
options: filamentSelectExternal ?? [],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const selectedFilamentID: number | string | undefined = Form.useWatch("filament_id", form);
|
|
||||||
let selectedFilament: SelectOption | null = null;
|
|
||||||
// selectedFilamentID is a number of it's an internal filament, and a string of it's an external filament.
|
|
||||||
if (typeof selectedFilamentID === "number") {
|
|
||||||
selectedFilament =
|
|
||||||
filamentSelectInternal?.find((obj) => {
|
|
||||||
return obj.value === selectedFilamentID;
|
|
||||||
}) ?? null;
|
|
||||||
} else if (typeof selectedFilamentID === "string") {
|
|
||||||
selectedFilament =
|
|
||||||
filamentSelectExternal?.find((obj) => {
|
|
||||||
return obj.value === selectedFilamentID;
|
|
||||||
}) ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Weight calculations
|
// Weight calculations
|
||||||
//
|
//
|
||||||
@@ -220,17 +146,11 @@ export const SpoolCreate: React.FC<IResourceComponentsProps & CreateOrCloneProps
|
|||||||
const [usedWeight, setUsedWeight] = useState(0);
|
const [usedWeight, setUsedWeight] = useState(0);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const initial_weight = initialWeightValue ?? 0;
|
|
||||||
const spool_weight = spoolWeightValue ?? 0;
|
|
||||||
|
|
||||||
const newFilamentWeight = selectedFilament?.weight || 0;
|
const newFilamentWeight = selectedFilament?.weight || 0;
|
||||||
const newSpoolWeight = selectedFilament?.spool_weight || 0;
|
const newSpoolWeight = selectedFilament?.spool_weight || 0;
|
||||||
|
|
||||||
const currentCalculatedFilamentWeight = selectedFilament ? calcTotalWeight(selectedFilament) : 0;
|
|
||||||
if (newFilamentWeight > 0) {
|
if (newFilamentWeight > 0) {
|
||||||
form.setFieldValue("initial_weight", newFilamentWeight);
|
form.setFieldValue("initial_weight", newFilamentWeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newSpoolWeight > 0) {
|
if (newSpoolWeight > 0) {
|
||||||
form.setFieldValue("spool_weight", newSpoolWeight);
|
form.setFieldValue("spool_weight", newSpoolWeight);
|
||||||
}
|
}
|
||||||
@@ -274,10 +194,6 @@ export const SpoolCreate: React.FC<IResourceComponentsProps & CreateOrCloneProps
|
|||||||
return net_weight + spool_weight;
|
return net_weight + spool_weight;
|
||||||
};
|
};
|
||||||
|
|
||||||
function calcTotalWeight(filament: SelectOption): number {
|
|
||||||
return (filament.weight ?? 0) + (filament.spool_weight ?? 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const getMeasuredWeight = (): number => {
|
const getMeasuredWeight = (): number => {
|
||||||
const grossWeight = getGrossWeight();
|
const grossWeight = getGrossWeight();
|
||||||
|
|
||||||
@@ -390,7 +306,7 @@ export const SpoolCreate: React.FC<IResourceComponentsProps & CreateOrCloneProps
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
options={filamentSelectOptions}
|
options={filamentOptions}
|
||||||
showSearch
|
showSearch
|
||||||
filterOption={(input, option) =>
|
filterOption={(input, option) =>
|
||||||
typeof option?.label === "string" && selectSearchMatches(input, option?.label)
|
typeof option?.label === "string" && selectSearchMatches(input, option?.label)
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import { getAPIURL } from "../../utils/url";
|
|
||||||
import { ISpool } from "./model";
|
|
||||||
|
|
||||||
export async function setSpoolArchived(spool: ISpool, archived: boolean) {
|
|
||||||
const init: RequestInit = {
|
|
||||||
method: "PATCH",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
archived: archived,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
const request = new Request(getAPIURL() + "/spool/" + spool.id);
|
|
||||||
await fetch(request, init);
|
|
||||||
}
|
|
||||||
127
client/src/pages/spools/functions.tsx
Normal file
127
client/src/pages/spools/functions.tsx
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
import { useSelect, useTranslate } from "@refinedev/core";
|
||||||
|
import { formatLength, formatWeight } from "../../utils/parsing";
|
||||||
|
import { getAPIURL } from "../../utils/url";
|
||||||
|
import { ISpool } from "./model";
|
||||||
|
import { IFilament } from "../filaments/model";
|
||||||
|
import { useGetExternalDBFilaments } from "../../utils/queryExternalDB";
|
||||||
|
|
||||||
|
export async function setSpoolArchived(spool: ISpool, archived: boolean) {
|
||||||
|
const init: RequestInit = {
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
archived: archived,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const request = new Request(getAPIURL() + "/spool/" + spool.id);
|
||||||
|
await fetch(request, init);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a filament label with the given parameters.
|
||||||
|
*/
|
||||||
|
export function formatFilamentLabel(
|
||||||
|
name: string,
|
||||||
|
diameter: number,
|
||||||
|
vendorName?: string,
|
||||||
|
material?: string,
|
||||||
|
weight?: number
|
||||||
|
): string {
|
||||||
|
const portions = [];
|
||||||
|
if (vendorName) {
|
||||||
|
portions.push(vendorName);
|
||||||
|
}
|
||||||
|
portions.push(name);
|
||||||
|
const extras = [];
|
||||||
|
if (material) {
|
||||||
|
extras.push(material);
|
||||||
|
}
|
||||||
|
extras.push(formatLength(diameter));
|
||||||
|
if (weight) {
|
||||||
|
extras.push(formatWeight(weight));
|
||||||
|
}
|
||||||
|
return `${portions.join(" - ")} (${extras.join(", ")})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SelectOption {
|
||||||
|
label: string;
|
||||||
|
value: string | number;
|
||||||
|
weight?: number;
|
||||||
|
spool_weight?: number;
|
||||||
|
is_internal: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGetFilamentSelectOptions() {
|
||||||
|
// Setup hooks
|
||||||
|
const t = useTranslate();
|
||||||
|
const { queryResult: internalFilaments } = useSelect<IFilament>({
|
||||||
|
resource: "filament",
|
||||||
|
});
|
||||||
|
const externalFilaments = useGetExternalDBFilaments();
|
||||||
|
|
||||||
|
// Format and sort internal filament options
|
||||||
|
const filamentSelectInternal: SelectOption[] =
|
||||||
|
internalFilaments.data?.data.map((item) => {
|
||||||
|
return {
|
||||||
|
label: formatFilamentLabel(
|
||||||
|
item.name ?? `ID ${item.id}`,
|
||||||
|
item.diameter,
|
||||||
|
item.vendor?.name,
|
||||||
|
item.material,
|
||||||
|
item.weight
|
||||||
|
),
|
||||||
|
value: item.id,
|
||||||
|
weight: item.weight,
|
||||||
|
spool_weight: item.spool_weight,
|
||||||
|
is_internal: true,
|
||||||
|
};
|
||||||
|
}) ?? [];
|
||||||
|
filamentSelectInternal.sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: "base" }));
|
||||||
|
|
||||||
|
// Format and sort external filament options
|
||||||
|
const filamentSelectExternal: SelectOption[] =
|
||||||
|
externalFilaments.data?.map((item) => {
|
||||||
|
return {
|
||||||
|
label: formatFilamentLabel(item.name, item.diameter, item.manufacturer, item.material, item.weight),
|
||||||
|
value: item.id,
|
||||||
|
weight: item.weight,
|
||||||
|
spool_weight: item.spool_weight || undefined,
|
||||||
|
is_internal: false,
|
||||||
|
};
|
||||||
|
}) ?? [];
|
||||||
|
filamentSelectExternal.sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: "base" }));
|
||||||
|
|
||||||
|
return {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: <span>{t("spool.fields.filament_internal")}</span>,
|
||||||
|
options: filamentSelectInternal,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: <span>{t("spool.fields.filament_external")}</span>,
|
||||||
|
options: filamentSelectExternal,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
getById: (id: number | string | null) => {
|
||||||
|
// id is a number of it's an internal filament, and a string of it's an external filament.
|
||||||
|
if (typeof id === "number") {
|
||||||
|
return (
|
||||||
|
filamentSelectInternal?.find((obj) => {
|
||||||
|
return obj.value === id;
|
||||||
|
}) ?? null
|
||||||
|
);
|
||||||
|
} else if (typeof id === "string") {
|
||||||
|
return (
|
||||||
|
filamentSelectExternal?.find((obj) => {
|
||||||
|
return obj.value === id;
|
||||||
|
}) ?? null
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
allExternalFilaments: externalFilaments.data,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user