real boxing create and edit components
This commit is contained in:
@@ -1,33 +1,25 @@
|
||||
'use client';
|
||||
|
||||
import BaseButton from '@/components/ui-kit/BaseButton';
|
||||
import BaseInput from '@/components/ui-kit/BaseInput';
|
||||
import { party_requests } from '@/data/party/party.requests';
|
||||
import { pageLinks } from '@/helpers/constants';
|
||||
import { notifyError, notifyUnknownError } from '@/services/notification';
|
||||
import { Box, Divider, FormHelperText, Grid, Stack, Typography, styled } from '@mui/material';
|
||||
import { useParams, useSearchParams, useRouter } from 'next/navigation';
|
||||
import { notifyUnknownError } from '@/services/notification';
|
||||
import { Box, FormHelperText, Grid, Stack, Typography, styled } from '@mui/material';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useLocale } from 'use-intl';
|
||||
import { Controller, useFieldArray, useForm } from 'react-hook-form';
|
||||
import BaseIconButton from '@/components/ui-kit/BaseIconButton';
|
||||
import { AddCircleRounded, Close } from '@mui/icons-material';
|
||||
import { box_requests } from '@/data/box/box.requests';
|
||||
import useRequest from '@/hooks/useRequest';
|
||||
import { useMyTranslation } from '@/hooks/useMyTranslation';
|
||||
import { BoxStatus, CreateBoxBodyType, UpdateBoxBodyType } from '@/data/box/box.model';
|
||||
import BaseReactSelect, { selectDefaultStyles } from '@/components/ui-kit/BaseReactSelect';
|
||||
import { customer_requests } from '@/data/customers/customer.requests';
|
||||
import { selectDefaultStyles } from '@/components/ui-kit/BaseReactSelect';
|
||||
import { useAuthContext } from '@/context/auth-context';
|
||||
import { useMyNavigation } from '@/hooks/useMyNavigation';
|
||||
import AsyncSelect from 'react-select/async';
|
||||
import cloneDeep from 'lodash.clonedeep';
|
||||
import { item_requests } from '@/data/item/item.requests';
|
||||
import { box_requests } from '@/data/box/box.requests';
|
||||
import { real_box_requests } from '@/data/real-box/real-box.requests';
|
||||
|
||||
import get from 'lodash.get';
|
||||
import Loader from '@/components/common/Loader';
|
||||
import { Customer } from '@/data/customers/customer.model';
|
||||
import { Passport } from '@/data/passport/passport.model';
|
||||
import { passport_requests } from '@/data/passport/passport.request';
|
||||
|
||||
const StyledCreateBox = styled(Box)`
|
||||
.item-row {
|
||||
@@ -37,9 +29,6 @@ const StyledCreateBox = styled(Box)`
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.item-row-field {
|
||||
}
|
||||
|
||||
& > * {
|
||||
flex: 1 1 1;
|
||||
}
|
||||
@@ -49,20 +38,11 @@ type Props = {
|
||||
partiesData?: { value: number; label: string }[];
|
||||
initialValues?: {
|
||||
id: number;
|
||||
boxId: string;
|
||||
box_name: string;
|
||||
net_weight: number;
|
||||
box_weight: number;
|
||||
box_type: string;
|
||||
box_size: string;
|
||||
status: BoxStatus;
|
||||
packetId: string;
|
||||
passportName: string;
|
||||
passportId: number;
|
||||
partyId: number;
|
||||
partyName: string;
|
||||
clientId: number;
|
||||
client_id: string;
|
||||
clientName: string;
|
||||
packetId: string;
|
||||
products_list: {
|
||||
id: number;
|
||||
price: number | string;
|
||||
@@ -77,31 +57,30 @@ type Props = {
|
||||
};
|
||||
|
||||
const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => {
|
||||
const [cargoIdValue, setCargoIdValue] = useState<string>('');
|
||||
const { user, isAdmin: isAdminUser } = useAuthContext();
|
||||
const editMode = !!initialValues && !!initialValues.id;
|
||||
const isAdmin = isAdminUser && editMode;
|
||||
const t = useMyTranslation();
|
||||
const params = useSearchParams();
|
||||
const navigation = useMyNavigation();
|
||||
const [partyId, setPartyId] = useState<number | string>("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const helperRef = useRef<{
|
||||
finished: boolean;
|
||||
partyFinished: boolean;
|
||||
clientFinished: boolean;
|
||||
settedDefaultParty: any;
|
||||
settedDefaultClient: Customer | null;
|
||||
}>({
|
||||
settedDefaultParty: null,
|
||||
settedDefaultClient: null,
|
||||
partyFinished: false,
|
||||
clientFinished: false,
|
||||
finished: false,
|
||||
});
|
||||
|
||||
const {
|
||||
register,
|
||||
control,
|
||||
handleSubmit,
|
||||
watch,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm<any>({
|
||||
@@ -112,80 +91,46 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => {
|
||||
: params.get('party_id')
|
||||
? [{ id: +params.get('party_id')! }]
|
||||
: [{ id: '' }],
|
||||
box_weight: 0.9,
|
||||
box_type: 'KG',
|
||||
box_size: '50x40x40',
|
||||
status: 'READY_TO_INVOICE',
|
||||
cargoId: initialValues?.client_id,
|
||||
products_list: editMode
|
||||
? initialValues?.products_list
|
||||
: [
|
||||
{
|
||||
id: '',
|
||||
cargoId: '',
|
||||
trekId: '',
|
||||
name: '',
|
||||
nameRu: '',
|
||||
amount: '',
|
||||
weight: '',
|
||||
price: '',
|
||||
},
|
||||
],
|
||||
...initialValues,
|
||||
},
|
||||
});
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const products = useFieldArray({
|
||||
control,
|
||||
name: 'products_list',
|
||||
keyName: 'key',
|
||||
});
|
||||
const pakets = useFieldArray({
|
||||
control,
|
||||
name: 'paketIds',
|
||||
keyName: 'key',
|
||||
});
|
||||
const controlledProductFields = watch('products_list');
|
||||
const partyIdValue = watch('partyId');
|
||||
const clientIdValue = watch('client_id');
|
||||
const cargoId = watch('cargoId');
|
||||
|
||||
const requiredText = t('required');
|
||||
const [selectedPassport, setSelectedPassport] = useState<Passport | null>(null);
|
||||
|
||||
const passportOptionsInitial = initialValues?.passportId &&
|
||||
initialValues?.passportName && [
|
||||
{
|
||||
value: initialValues?.passportId,
|
||||
label: initialValues?.passportName,
|
||||
const getBoxesQuery = useRequest(
|
||||
() =>
|
||||
box_requests.getAll({
|
||||
partyId: partyId,
|
||||
}),
|
||||
{
|
||||
selectData(data) {
|
||||
return data?.data?.data;
|
||||
},
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
const { data: passportOptions } = useRequest(() => passport_requests.getAll({ cargoId: cargoId?.toUpperCase() }), {
|
||||
enabled: !!cargoId,
|
||||
selectData: data => {
|
||||
const passportOptions = data.data.data.map((passport: Passport) => ({
|
||||
value: passport.id,
|
||||
label: passport.fullName,
|
||||
}));
|
||||
|
||||
const passportId = watch('passportId');
|
||||
if (!passportId && initialValues?.passportId && cargoId === initialValues?.client_id) {
|
||||
const currentOption = passportOptions?.find((item: { value: number }) => item.value === initialValues?.passportId);
|
||||
setValue('passportId', currentOption);
|
||||
}
|
||||
|
||||
return passportOptions;
|
||||
},
|
||||
dependencies: [cargoId],
|
||||
placeholderData: [],
|
||||
});
|
||||
const { data: list } = useMemo(() => {
|
||||
if (getBoxesQuery.data?.data) {
|
||||
return {
|
||||
data: getBoxesQuery.data.data.filter((box: any) => box.status === 'READY_TO_INVOICE'),
|
||||
};
|
||||
}
|
||||
return { data: [] };
|
||||
}, [getBoxesQuery, partyId]);
|
||||
|
||||
useEffect(() => {
|
||||
setValue('passportId', '');
|
||||
}, [cargoId]);
|
||||
if (partyId) {
|
||||
getBoxesQuery.refetch();
|
||||
}
|
||||
}, [partyId]);
|
||||
|
||||
const { data: defaultParties, status: defaultPartiesStatus } = useRequest(() => party_requests.getAll({ status: 'COLLECTING' }), {
|
||||
const { data: defaultParties } = useRequest(() => party_requests.getAll({ status: 'COLLECTING' }), {
|
||||
enabled: true,
|
||||
selectData(data) {
|
||||
return data.data.data.data.map(p => ({ value: p.id, label: p.name }));
|
||||
@@ -204,98 +149,24 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => {
|
||||
placeholderData: [],
|
||||
});
|
||||
|
||||
const { data: defaultClients } = useRequest(
|
||||
() =>
|
||||
customer_requests.getAll({
|
||||
page: 1,
|
||||
}),
|
||||
{
|
||||
enabled: !!partyIdValue,
|
||||
selectData(data) {
|
||||
return data.data.data.data.map(p => ({ value: p.aviaCargoId, label: p.fullName }));
|
||||
},
|
||||
dependencies: [partyIdValue],
|
||||
onSuccess(data) {
|
||||
if (!editMode && !clientIdValue && data?.data?.data?.data?.[0]) {
|
||||
helperRef.current.settedDefaultClient = data.data.data?.data?.[0];
|
||||
setValue('client_id', data.data.data.data[0].aviaCargoId);
|
||||
}
|
||||
helperRef.current.clientFinished = true;
|
||||
if (helperRef.current.partyFinished) {
|
||||
helperRef.current.finished = true;
|
||||
}
|
||||
},
|
||||
placeholderData: [],
|
||||
}
|
||||
);
|
||||
|
||||
const onPassportChange = (newValue: Passport | null) => {
|
||||
setSelectedPassport(newValue);
|
||||
if (newValue) {
|
||||
setValue('passport_id', newValue.id || null);
|
||||
} else {
|
||||
setValue('passport_id', null);
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = handleSubmit(async values => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const packetDtos = values.paketIds.map((paket: any) => paket.id).filter((id: any) => id);
|
||||
|
||||
if (editMode) {
|
||||
const updateBody: UpdateBoxBodyType = {
|
||||
cargoId: values.client_id,
|
||||
passportId: values.passportId?.value,
|
||||
status: values.status,
|
||||
packetId: values.paketIds.map((p: any) => p.id), // Bir nechta paketId
|
||||
items: values.products_list.map((item: any) => {
|
||||
const _price = +item.price ? +item.price : 0;
|
||||
const _amount = +item.amount ? +item.amount : 0;
|
||||
const _total_price = _price ? _price * _amount : 0;
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
trekId: item.trekId,
|
||||
name: item.name,
|
||||
nameRu: item?.nameRu,
|
||||
weight: +item.weight,
|
||||
amount: +item.amount,
|
||||
price: _price,
|
||||
totalPrice: _total_price,
|
||||
};
|
||||
}),
|
||||
const updateBody: UpdateRealBoxBodyType = {
|
||||
boxId: initialValues?.boxId,
|
||||
partyName: values.partyName,
|
||||
packetDtos,
|
||||
};
|
||||
|
||||
const item_delete_promises = initialValues.products_list
|
||||
.filter(item => {
|
||||
if (!updateBody.items.find(i => String(i.id) === String(item.id))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.map(item => {
|
||||
return item_requests.delete({ itemId: item.id });
|
||||
});
|
||||
|
||||
await box_requests.update(updateBody);
|
||||
await Promise.all(item_delete_promises);
|
||||
await real_box_requests.update(updateBody);
|
||||
} else {
|
||||
const createBody: CreateBoxBodyType = {
|
||||
status: values.status,
|
||||
cargoId: values.cargoId,
|
||||
passportId: values.passportId?.value,
|
||||
partyId: values.partyId,
|
||||
items: values.products_list.map((item: any) => {
|
||||
return {
|
||||
trekId: item.trekId,
|
||||
name: item.name,
|
||||
weight: +item.weight,
|
||||
amount: +item.amount,
|
||||
};
|
||||
}),
|
||||
const createBody: RealCreateBoxBodyType = {
|
||||
partyName: values.partyName,
|
||||
packetDtos,
|
||||
};
|
||||
await box_requests.create(createBody);
|
||||
await real_box_requests.create(createBody);
|
||||
}
|
||||
|
||||
navigation.push(pageLinks.dashboard.boxes.index);
|
||||
@@ -320,67 +191,6 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => {
|
||||
pakets.remove(index);
|
||||
};
|
||||
|
||||
const appendProduct = () => {
|
||||
products.append({
|
||||
id: '',
|
||||
cargoId: '',
|
||||
trekId: '',
|
||||
name: '',
|
||||
amount: '',
|
||||
weight: '',
|
||||
price: '',
|
||||
totalPrice: '',
|
||||
});
|
||||
};
|
||||
|
||||
const removeProduct = (index: number) => {
|
||||
products.remove(index);
|
||||
};
|
||||
|
||||
const translateAndUpdateRussianName = async (text: string, index: number) => {
|
||||
if (!text) return;
|
||||
|
||||
try {
|
||||
const responseText = await box_requests.translateWithMemoryApi({ text });
|
||||
setValue(`products_list.${index}.nameRu`, responseText || '');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
notifyError('Translation api error');
|
||||
}
|
||||
};
|
||||
|
||||
const boxTypes = [
|
||||
{
|
||||
label: 'KG',
|
||||
value: 'KG',
|
||||
},
|
||||
{
|
||||
label: 'GABARIT',
|
||||
value: 'GABARIT',
|
||||
},
|
||||
];
|
||||
|
||||
const boxStatuses = useMemo(() => {
|
||||
const p: {
|
||||
label: string;
|
||||
value: BoxStatus;
|
||||
}[] = [
|
||||
{
|
||||
label: t('READY_TO_INVOICE'),
|
||||
value: 'READY_TO_INVOICE',
|
||||
},
|
||||
];
|
||||
|
||||
if (isAdmin) {
|
||||
p.push({
|
||||
label: t('READY'),
|
||||
value: 'READY',
|
||||
});
|
||||
}
|
||||
|
||||
return p;
|
||||
}, [isAdmin]);
|
||||
|
||||
return (
|
||||
<StyledCreateBox
|
||||
width={1}
|
||||
@@ -405,40 +215,36 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => {
|
||||
name='partyId'
|
||||
control={control}
|
||||
rules={{ required: requiredText }}
|
||||
render={({ field, fieldState, formState }) => {
|
||||
return (
|
||||
<AsyncSelect
|
||||
onChange={(newValue: any) => {
|
||||
field.onChange(newValue.value);
|
||||
}}
|
||||
defaultValue={
|
||||
editMode
|
||||
render={({ field }) => (
|
||||
<AsyncSelect
|
||||
onChange={(newValue: any) => {
|
||||
field.onChange(newValue.value);
|
||||
setPartyId(newValue.value);
|
||||
}}
|
||||
defaultValue={
|
||||
editMode
|
||||
? {
|
||||
value: initialValues.partyId,
|
||||
label: initialValues.partyName,
|
||||
}
|
||||
: partiesData?.length
|
||||
? {
|
||||
value: initialValues.partyId,
|
||||
label: initialValues.partyName,
|
||||
value: partiesData[0].value,
|
||||
label: partiesData[0].label,
|
||||
}
|
||||
: partiesData?.length
|
||||
? {
|
||||
value: partiesData[0].value,
|
||||
label: partiesData[0].label,
|
||||
}
|
||||
: null
|
||||
}
|
||||
styles={selectDefaultStyles}
|
||||
noOptionsMessage={() => t('not_found')}
|
||||
loadingMessage={() => t('loading')}
|
||||
onBlur={field.onBlur}
|
||||
name={field.name}
|
||||
defaultOptions={defaultParties!}
|
||||
loadOptions={partyOptions}
|
||||
placeholder={t('enter_party_name_to_find')}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
: null
|
||||
}
|
||||
styles={selectDefaultStyles}
|
||||
noOptionsMessage={() => t('not_found')}
|
||||
loadingMessage={() => t('loading')}
|
||||
onBlur={field.onBlur}
|
||||
name={field.name}
|
||||
defaultOptions={defaultParties!}
|
||||
loadOptions={partyOptions}
|
||||
placeholder={t('enter_party_name_to_find')}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{/* {!!errors.partyId?.message && (
|
||||
<FormHelperText sx={{ color: 'red' }}>{errors.partyId?.message}</FormHelperText>
|
||||
)} */}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
@@ -460,32 +266,48 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => {
|
||||
name={`paketIds.${index}.id`}
|
||||
control={control}
|
||||
rules={{ required: requiredText }}
|
||||
render={({ field: paketField, fieldState }) => (
|
||||
render={({ field: paketField }) => (
|
||||
<AsyncSelect
|
||||
onChange={(newValue: any) => {
|
||||
paketField.onChange(newValue?.value);
|
||||
}}
|
||||
defaultValue={
|
||||
editMode && index === 0
|
||||
editMode && index === 0 && initialValues.packetId
|
||||
? {
|
||||
value: initialValues.partyId,
|
||||
label: initialValues.partyName,
|
||||
value: initialValues.packetId,
|
||||
label: initialValues.box_name || `Box ${initialValues.packetId}`,
|
||||
}
|
||||
: partiesData?.length && index === 0
|
||||
? {
|
||||
value: partiesData[0].value,
|
||||
label: partiesData[0].label,
|
||||
}
|
||||
: null
|
||||
: null
|
||||
}
|
||||
styles={selectDefaultStyles}
|
||||
noOptionsMessage={() => t('not_found')}
|
||||
loadingMessage={() => t('loading')}
|
||||
onBlur={paketField.onBlur}
|
||||
name={paketField.name}
|
||||
defaultOptions={defaultParties!}
|
||||
loadOptions={partyOptions}
|
||||
placeholder={t('enter_party_name_to_find')}
|
||||
defaultOptions={
|
||||
list.length > 0
|
||||
? list.map((box: any) => ({
|
||||
value: box.id,
|
||||
label: box.box_name || box.name || `Box ${box.id}`,
|
||||
}))
|
||||
: []
|
||||
}
|
||||
loadOptions={async (inputValue: string) => {
|
||||
if (!partyId || partyId === '') return [];
|
||||
try {
|
||||
const res = await box_requests.getAll({
|
||||
partyId: partyId,
|
||||
});
|
||||
return res.data.data.data.map((box: any) => ({
|
||||
label: box.box_name || box.name || `Box ${box.id}`,
|
||||
value: box.id,
|
||||
}));
|
||||
} catch (error) {
|
||||
notifyUnknownError(error);
|
||||
return [];
|
||||
}
|
||||
}}
|
||||
placeholder={t('enter_box_name_to_find')}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -528,4 +350,15 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardCreateRealBoxPage;
|
||||
export default DashboardCreateRealBoxPage;
|
||||
|
||||
export type RealCreateBoxBodyType = {
|
||||
partyName: string;
|
||||
packetDtos: number[];
|
||||
};
|
||||
|
||||
export type UpdateRealBoxBodyType = {
|
||||
boxId: string;
|
||||
partyName: string;
|
||||
packetDtos: number[];
|
||||
};
|
||||
Reference in New Issue
Block a user