549 lines
18 KiB
TypeScript
549 lines
18 KiB
TypeScript
import { Controller, useForm } from "react-hook-form";
|
||
import { Grid } from "../../../components/Grid/Grid";
|
||
import { FormApiBasedAutoComplete } from "../../../components/FormItems/FormApiBasedAutoComplete";
|
||
import {
|
||
zValidateAutoComplete,
|
||
zValidateAutoCompleteOptional,
|
||
zValidateNumber,
|
||
zValidateString,
|
||
} from "../../../data/getFormTypeErrors";
|
||
import { zodResolver } from "@hookform/resolvers/zod";
|
||
import { z } from "zod";
|
||
import AutoComplete from "../../../components/AutoComplete/AutoComplete";
|
||
import { getMonthsList } from "../../../data/getMonths";
|
||
import { RadioGroup } from "../../../components/RadioButton/RadioGroup";
|
||
import { useEffect, useRef, useState } from "react";
|
||
import ToggleButton from "../../../components/ToggleButton/ToggleButton";
|
||
import Typography from "../../../components/Typography/Typography";
|
||
import Textfield from "../../../components/Textfeild/Textfeild";
|
||
import { useApiRequest } from "../../../utils/useApiRequest";
|
||
|
||
type Props = {
|
||
item: any;
|
||
getData: () => void;
|
||
onSubmit: (data: any) => void;
|
||
setFormRef: (ref: HTMLFormElement | null) => void;
|
||
visible: boolean;
|
||
};
|
||
|
||
const saleTypes = [
|
||
{ value: "gov", label: "دولتی" },
|
||
{ value: "free", label: "آزاد" },
|
||
];
|
||
|
||
const groupTypes = [
|
||
{ value: "روستایی", key: "rural", disabled: false },
|
||
{ value: "صنعتی", key: "industrial", disabled: false },
|
||
{ value: "عشایری", key: "nomadic", disabled: true },
|
||
];
|
||
|
||
const posSaleTypes = [
|
||
{ value: "هردو", key: "all", disabled: false },
|
||
{ value: "بر اساس وزن", key: "weight", disabled: false },
|
||
{ value: "بر اساس تعداد راس دام", key: "count", disabled: false },
|
||
];
|
||
|
||
export const QuotaLevel1 = ({ item, onSubmit, setFormRef, visible }: Props) => {
|
||
const [hasDistributionLimit, setHasDistributionLimit] = useState(
|
||
item?.distribution_mode?.length ? true : false,
|
||
);
|
||
const internalRef = useRef<HTMLFormElement>(null);
|
||
const [livestockTypes, setLivestockTypes] = useState<
|
||
Array<{
|
||
livestock_group: string;
|
||
livestock_type: any;
|
||
weight_type: any;
|
||
quantity_kg: number;
|
||
fa: string;
|
||
}>
|
||
>([]);
|
||
|
||
useEffect(() => {
|
||
if (visible) {
|
||
setFormRef(internalRef.current);
|
||
}
|
||
}, [visible]);
|
||
|
||
const schema = z.object({
|
||
product: zValidateNumber("محصول"),
|
||
month_choices: zValidateAutoComplete("سهمیه ماه"),
|
||
distribution_mode: hasDistributionLimit
|
||
? zValidateAutoComplete("محدودیت توزیع دوره")
|
||
: zValidateAutoCompleteOptional(),
|
||
sale_license: zValidateAutoComplete("مجوز فروش"),
|
||
pos_sale_type: zValidateString("نوع فروش در دستگاه"),
|
||
sale_type: zValidateString("نوع فروش"),
|
||
group: zValidateAutoComplete("گروه"),
|
||
quota_weight: zValidateNumber("وزن سهمیه"),
|
||
sale_unit: zValidateNumber("نوع مولفه"),
|
||
});
|
||
|
||
type FormValues = z.infer<typeof schema>;
|
||
|
||
const {
|
||
control,
|
||
handleSubmit,
|
||
setValue,
|
||
getValues,
|
||
trigger,
|
||
formState: { errors },
|
||
} = useForm<FormValues>({
|
||
resolver: zodResolver(schema),
|
||
defaultValues: {
|
||
product: item?.product ? item?.product?.product_id : "",
|
||
month_choices: item?.month_choices || [],
|
||
distribution_mode: item?.distribution_mode || [],
|
||
sale_license: item?.sale_license || [],
|
||
sale_type: item?.sale_type || "gov",
|
||
group: item?.group || [],
|
||
pos_sale_type: item?.pos_sale_type || "all",
|
||
quota_weight: item?.quota_weight || 0,
|
||
sale_unit: item?.sale_unit ? item?.sale_unit?.id : "",
|
||
},
|
||
});
|
||
|
||
const { data: livestockData } = useApiRequest({
|
||
api: "/livestock/web/api/v1/livestock_type/",
|
||
method: "get",
|
||
params: { page: 1, page_size: 100 },
|
||
queryKey: ["livestockTypes"],
|
||
});
|
||
|
||
useEffect(() => {
|
||
if (livestockData?.results) {
|
||
const getQuantity = (allocate: any, group: string) => {
|
||
const result = item?.livestock_allocations?.find(
|
||
(option: any) =>
|
||
option?.livestock_type?.weight_type === allocate?.weight_type &&
|
||
option?.livestock_group === group &&
|
||
option?.livestock_type?.name === allocate?.name,
|
||
);
|
||
return result?.quantity_kg || 0;
|
||
};
|
||
|
||
const formattedData = livestockData.results.flatMap((item: any) => [
|
||
{
|
||
livestock_group: "rural",
|
||
livestock_type: item.id,
|
||
weight_type: item.weight_type,
|
||
quantity_kg: getQuantity(item, "rural"),
|
||
fa: item.name,
|
||
},
|
||
{
|
||
livestock_group: "industrial",
|
||
livestock_type: item.id,
|
||
weight_type: item.weight_type,
|
||
quantity_kg: getQuantity(item, "industrial"),
|
||
fa: item.name,
|
||
},
|
||
]);
|
||
|
||
setLivestockTypes(formattedData);
|
||
}
|
||
}, [livestockData, item]);
|
||
|
||
const handleQuantityChange = (index: number, value: number) => {
|
||
setLivestockTypes((prev) => {
|
||
const newTypes = [...prev];
|
||
newTypes[index] = { ...newTypes[index], quantity_kg: value };
|
||
return newTypes;
|
||
});
|
||
};
|
||
|
||
const findLivestockIndex = (
|
||
group: string,
|
||
weightType: string,
|
||
fa: string,
|
||
) => {
|
||
return livestockTypes.findIndex(
|
||
(item) =>
|
||
item.livestock_group === group &&
|
||
item.weight_type === weightType &&
|
||
item.fa === fa,
|
||
);
|
||
};
|
||
|
||
const handleSubmitForm = (data: FormValues) => {
|
||
onSubmit({ ...data, livestockTypes, hasDistributionLimit });
|
||
};
|
||
|
||
return (
|
||
<form ref={internalRef} onSubmit={handleSubmit(handleSubmitForm)}>
|
||
<Grid container column>
|
||
<Grid className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 mt-8 gap-4 items-start">
|
||
<Controller
|
||
name="product"
|
||
control={control}
|
||
render={() => (
|
||
<>
|
||
<FormApiBasedAutoComplete
|
||
defaultKey={item?.product?.product_id}
|
||
title="انتخاب محصول"
|
||
api={`product/web/api/v1/product`}
|
||
keyField="id"
|
||
valueField="name"
|
||
error={!!errors.product}
|
||
errorMessage={errors.product?.message}
|
||
onChange={(r) => {
|
||
setValue("product", r);
|
||
trigger("product");
|
||
}}
|
||
/>
|
||
</>
|
||
)}
|
||
/>
|
||
|
||
<Controller
|
||
name="quota_weight"
|
||
control={control}
|
||
render={({ field }) => (
|
||
<Textfield
|
||
formattedNumber
|
||
fullWidth
|
||
placeholder="وزن سهمیه"
|
||
value={field.value}
|
||
onChange={field.onChange}
|
||
error={!!errors.quota_weight}
|
||
helperText={errors.quota_weight?.message}
|
||
/>
|
||
)}
|
||
/>
|
||
|
||
<Controller
|
||
name="month_choices"
|
||
control={control}
|
||
render={({ field }) => (
|
||
<AutoComplete
|
||
data={getMonthsList}
|
||
selectField
|
||
selectedKeys={field.value}
|
||
multiselect
|
||
onChange={(keys: (string | number)[]) => {
|
||
setValue("month_choices", keys);
|
||
trigger("month_choices");
|
||
}}
|
||
error={!!errors.month_choices}
|
||
helperText={errors.month_choices?.message}
|
||
title="سهمیه ماه"
|
||
/>
|
||
)}
|
||
/>
|
||
|
||
<Controller
|
||
name="sale_license"
|
||
control={control}
|
||
render={({ field }) => (
|
||
<AutoComplete
|
||
selectField
|
||
data={getMonthsList}
|
||
selectedKeys={field.value}
|
||
multiselect
|
||
onChange={(keys: (string | number)[]) => {
|
||
setValue("sale_license", keys);
|
||
trigger("sale_license");
|
||
}}
|
||
error={!!errors.sale_license}
|
||
helperText={errors.sale_license?.message}
|
||
title="مجوز فروش"
|
||
/>
|
||
)}
|
||
/>
|
||
|
||
<Grid
|
||
container
|
||
className="p-2 border-1 rounded-lg items-center border-gray-200"
|
||
>
|
||
<Controller
|
||
name="sale_type"
|
||
control={control}
|
||
render={({ field }) => (
|
||
<RadioGroup
|
||
groupTitle="نوع فروش"
|
||
className="mr-2"
|
||
direction="row"
|
||
options={saleTypes}
|
||
value={field.value}
|
||
onChange={(e) => {
|
||
setValue("sale_type", e.target.value);
|
||
}}
|
||
/>
|
||
)}
|
||
/>
|
||
</Grid>
|
||
|
||
<Controller
|
||
name="group"
|
||
control={control}
|
||
render={({ field }) => (
|
||
<AutoComplete
|
||
selectField
|
||
data={groupTypes}
|
||
selectedKeys={field.value}
|
||
multiselect
|
||
onChange={(keys: (string | number)[]) => {
|
||
setValue("group", keys);
|
||
trigger("group");
|
||
}}
|
||
error={!!errors.group}
|
||
helperText={errors.group?.message}
|
||
title="گروه"
|
||
/>
|
||
)}
|
||
/>
|
||
|
||
<Controller
|
||
name="product"
|
||
control={control}
|
||
render={() => (
|
||
<>
|
||
<FormApiBasedAutoComplete
|
||
selectField
|
||
defaultKey={item?.sale_unit?.id}
|
||
title="نوع مولفه"
|
||
api={`product/web/api/v1/sale_unit`}
|
||
keyField="id"
|
||
valueField="unit"
|
||
error={!!errors.sale_unit}
|
||
errorMessage={errors.sale_unit?.message}
|
||
onChange={(r) => {
|
||
setValue("sale_unit", r);
|
||
trigger("sale_unit");
|
||
}}
|
||
/>
|
||
</>
|
||
)}
|
||
/>
|
||
<Grid
|
||
container
|
||
column
|
||
className="p-2 border-1 rounded-lg border-gray-200 items-start gap-2"
|
||
>
|
||
<ToggleButton
|
||
type="button"
|
||
isActive={hasDistributionLimit}
|
||
onClick={() => {
|
||
if (!hasDistributionLimit) {
|
||
setValue("distribution_mode", []);
|
||
trigger("distribution_mode");
|
||
}
|
||
setHasDistributionLimit(!hasDistributionLimit);
|
||
}}
|
||
title="محدودیت توزیع دوره"
|
||
aria-label="Toggle like"
|
||
/>
|
||
|
||
{hasDistributionLimit && (
|
||
<Controller
|
||
name="distribution_mode"
|
||
control={control}
|
||
render={({ field }) => (
|
||
<AutoComplete
|
||
data={getMonthsList}
|
||
selectedKeys={field.value || []}
|
||
multiselect
|
||
onChange={(keys: (string | number)[]) => {
|
||
setValue("distribution_mode", keys);
|
||
trigger("distribution_mode");
|
||
}}
|
||
error={!!errors.distribution_mode}
|
||
helperText={errors.distribution_mode?.message}
|
||
title="محدودیت توزیع دوره"
|
||
/>
|
||
)}
|
||
/>
|
||
)}
|
||
</Grid>
|
||
<Controller
|
||
name="pos_sale_type"
|
||
control={control}
|
||
render={({ field }) => (
|
||
<AutoComplete
|
||
selectField
|
||
data={posSaleTypes}
|
||
selectedKeys={[field.value]}
|
||
onChange={(keys: (string | number)[]) => {
|
||
setValue("pos_sale_type", keys.toString());
|
||
trigger("pos_sale_type");
|
||
}}
|
||
error={!!errors.pos_sale_type}
|
||
helperText={errors.pos_sale_type?.message}
|
||
title="نوع فروش در دستگاه"
|
||
/>
|
||
)}
|
||
/>
|
||
</Grid>
|
||
|
||
{getValues("group")?.includes("rural") && (
|
||
<>
|
||
<Typography
|
||
color="text-gray-600 dark:text-dark-100 my-4"
|
||
variant="body2"
|
||
>
|
||
سهمیه دام روستایی
|
||
</Typography>
|
||
<Grid className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 gap-4 items-start">
|
||
<Grid className="grid gap-2 p-2 border-1 border-gray-200 rounded-xl">
|
||
<Typography
|
||
color="text-gray-600 dark:text-dark-100"
|
||
className="flex justify-center select-none"
|
||
variant="caption"
|
||
>
|
||
سنگین
|
||
</Typography>
|
||
{livestockTypes
|
||
?.filter(
|
||
(option) =>
|
||
option.livestock_group === "rural" &&
|
||
option?.weight_type === "H",
|
||
)
|
||
.map((item, i) => {
|
||
const index = findLivestockIndex("rural", "H", item.fa);
|
||
return (
|
||
<Textfield
|
||
value={item.quantity_kg}
|
||
key={i}
|
||
start={item.fa}
|
||
end="کیلوگرم"
|
||
formattedNumber
|
||
onChange={(e) => {
|
||
const value =
|
||
parseInt(e.target.value.replace(/,/g, "")) || 0;
|
||
if (index !== -1) {
|
||
handleQuantityChange(index, value);
|
||
}
|
||
}}
|
||
/>
|
||
);
|
||
})}
|
||
</Grid>
|
||
<Grid className="grid gap-2 p-2 border-1 border-gray-200 rounded-xl">
|
||
<Typography
|
||
color="text-gray-600 dark:text-dark-100"
|
||
className="flex justify-center select-none"
|
||
variant="caption"
|
||
>
|
||
سبک
|
||
</Typography>
|
||
{livestockTypes
|
||
?.filter(
|
||
(option) =>
|
||
option.livestock_group === "rural" &&
|
||
option?.weight_type === "L",
|
||
)
|
||
.map((item, i) => {
|
||
const index = findLivestockIndex("rural", "L", item.fa);
|
||
return (
|
||
<Textfield
|
||
key={i}
|
||
start={item.fa}
|
||
end="کیلوگرم"
|
||
formattedNumber
|
||
value={item.quantity_kg}
|
||
onChange={(e) => {
|
||
const value =
|
||
parseInt(e.target.value.replace(/,/g, "")) || 0;
|
||
if (index !== -1) {
|
||
handleQuantityChange(index, value);
|
||
}
|
||
}}
|
||
/>
|
||
);
|
||
})}
|
||
</Grid>
|
||
</Grid>
|
||
</>
|
||
)}
|
||
|
||
{getValues("group")?.includes("industrial") && (
|
||
<>
|
||
<Typography
|
||
color="text-gray-600 dark:text-dark-100 my-4"
|
||
variant="body2"
|
||
>
|
||
سهمیه دام صنعتی
|
||
</Typography>
|
||
<Grid className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 gap-4 items-start">
|
||
<Grid className="grid gap-2 p-2 border-1 border-gray-200 rounded-xl">
|
||
<Typography
|
||
color="text-gray-600 dark:text-dark-100"
|
||
className="flex justify-center select-none"
|
||
variant="caption"
|
||
>
|
||
سنگین
|
||
</Typography>
|
||
{livestockTypes
|
||
?.filter(
|
||
(option) =>
|
||
option.livestock_group === "industrial" &&
|
||
option?.weight_type === "H",
|
||
)
|
||
.map((item, i) => {
|
||
const index = findLivestockIndex(
|
||
"industrial",
|
||
"H",
|
||
item.fa,
|
||
);
|
||
return (
|
||
<Textfield
|
||
value={item.quantity_kg}
|
||
key={i}
|
||
start={item.fa}
|
||
end="کیلوگرم"
|
||
formattedNumber
|
||
onChange={(e) => {
|
||
const value =
|
||
parseInt(e.target.value.replace(/,/g, "")) || 0;
|
||
if (index !== -1) {
|
||
handleQuantityChange(index, value);
|
||
}
|
||
}}
|
||
/>
|
||
);
|
||
})}
|
||
</Grid>
|
||
<Grid className="grid gap-2 p-2 border-1 border-gray-200 rounded-xl">
|
||
<Typography
|
||
color="text-gray-600 dark:text-dark-100"
|
||
className="flex justify-center select-none"
|
||
variant="caption"
|
||
>
|
||
سبک
|
||
</Typography>
|
||
{livestockTypes
|
||
?.filter(
|
||
(option) =>
|
||
option.livestock_group === "industrial" &&
|
||
option?.weight_type === "L",
|
||
)
|
||
.map((item, i) => {
|
||
const index = findLivestockIndex(
|
||
"industrial",
|
||
"L",
|
||
item.fa,
|
||
);
|
||
return (
|
||
<Textfield
|
||
key={i}
|
||
start={item.fa}
|
||
end="کیلوگرم"
|
||
formattedNumber
|
||
value={item.quantity_kg}
|
||
onChange={(e) => {
|
||
const value =
|
||
parseInt(e.target.value.replace(/,/g, "")) || 0;
|
||
if (index !== -1) {
|
||
handleQuantityChange(index, value);
|
||
}
|
||
}}
|
||
/>
|
||
);
|
||
})}
|
||
</Grid>
|
||
</Grid>
|
||
</>
|
||
)}
|
||
</Grid>
|
||
</form>
|
||
);
|
||
};
|