mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE-316): Add Uniformity form with validation and upload
This commit is contained in:
@@ -0,0 +1,86 @@
|
|||||||
|
import * as Yup from 'yup';
|
||||||
|
import { Uniformity } from '@/types/api/uniformity/uniformity';
|
||||||
|
|
||||||
|
type UniformityFormSchemaType = {
|
||||||
|
date: string;
|
||||||
|
location?: {
|
||||||
|
value: number;
|
||||||
|
label: string;
|
||||||
|
} | null;
|
||||||
|
location_id: number;
|
||||||
|
project_flock_kandang_id: number;
|
||||||
|
kandang?: {
|
||||||
|
value: number;
|
||||||
|
label: string;
|
||||||
|
} | null;
|
||||||
|
kandang_id: number;
|
||||||
|
files: File | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const FileSchema = Yup.mixed<File>()
|
||||||
|
.test('fileSize', 'Ukuran file maksimal 2 MB', (value): boolean => {
|
||||||
|
if (!value) return true;
|
||||||
|
if (value instanceof File) return value.size <= 2 * 1024 * 1024;
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.test('fileType', 'Format file harus Excel', (value): boolean => {
|
||||||
|
if (!value) return true;
|
||||||
|
if (value instanceof File) {
|
||||||
|
const allowedTypes = [
|
||||||
|
'application/vnd.ms-excel',
|
||||||
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
'text/csv',
|
||||||
|
];
|
||||||
|
return allowedTypes.includes(value.type);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const UniformityFormSchema: Yup.ObjectSchema<UniformityFormSchemaType> =
|
||||||
|
Yup.object({
|
||||||
|
date: Yup.string().required('Tanggal wajib diisi!'),
|
||||||
|
location: Yup.object({
|
||||||
|
value: Yup.number().min(1).required(),
|
||||||
|
label: Yup.string().required(),
|
||||||
|
}).nullable(),
|
||||||
|
location_id: Yup.number()
|
||||||
|
.required('Location wajib diisi!')
|
||||||
|
.typeError('Location wajib diisi!'),
|
||||||
|
project_flock_kandang_id: Yup.number()
|
||||||
|
.required('Project flock kandang wajib diisi!')
|
||||||
|
.typeError('Project flock kandang wajib diisi!'),
|
||||||
|
kandang: Yup.object({
|
||||||
|
value: Yup.number().min(1).required(),
|
||||||
|
label: Yup.string().required(),
|
||||||
|
}).nullable(),
|
||||||
|
kandang_id: Yup.number()
|
||||||
|
.required('Kandang wajib diisi!')
|
||||||
|
.typeError('Kandang wajib diisi!'),
|
||||||
|
files: FileSchema.required('File wajib diisi!'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type UniformityFormValues = Yup.InferType<typeof UniformityFormSchema>;
|
||||||
|
|
||||||
|
export const getUniformityFormInitialValues = (
|
||||||
|
initialValues?: Uniformity
|
||||||
|
): UniformityFormValues => {
|
||||||
|
return {
|
||||||
|
date: initialValues?.week ? '' : '',
|
||||||
|
location: initialValues?.location
|
||||||
|
? {
|
||||||
|
value: initialValues.location.id,
|
||||||
|
label: initialValues.location.name,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
location_id: initialValues?.location?.id ?? 0,
|
||||||
|
project_flock_kandang_id: initialValues?.project_flock_kandang_id ?? 0,
|
||||||
|
kandang: initialValues?.kandang
|
||||||
|
? {
|
||||||
|
value: initialValues.kandang.id,
|
||||||
|
label: initialValues.kandang.name,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
kandang_id: initialValues?.kandang?.id ?? 0,
|
||||||
|
files: undefined,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,22 +1,191 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { useFormik } from 'formik';
|
||||||
|
import useSWR from 'swr';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { Icon } from '@iconify/react';
|
||||||
|
import { toast } from 'react-hot-toast';
|
||||||
import DrawerHeader from '@/components/helper/drawer/DrawerHeader';
|
import DrawerHeader from '@/components/helper/drawer/DrawerHeader';
|
||||||
import { useUiStore } from '@/stores/ui/ui.store';
|
import { useUiStore } from '@/stores/ui/ui.store';
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
import { Icon } from '@iconify/react';
|
import DateInput from '@/components/input/DateInput';
|
||||||
|
|
||||||
|
import SelectInput, {
|
||||||
|
OptionType,
|
||||||
|
useSelect,
|
||||||
|
} from '@/components/input/SelectInput';
|
||||||
|
import FileInput from '@/components/input/FileInput';
|
||||||
|
|
||||||
|
import {
|
||||||
|
UniformityFormSchema,
|
||||||
|
UniformityFormValues,
|
||||||
|
getUniformityFormInitialValues,
|
||||||
|
} from '@/components/pages/uniformity/form/UniformityForm.schema';
|
||||||
|
import { LocationApi, KandangApi } from '@/services/api/master-data';
|
||||||
|
import { UniformityApi } from '@/services/api/uniformity';
|
||||||
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
|
import {
|
||||||
|
Uniformity,
|
||||||
|
CreateUniformityPayload,
|
||||||
|
} from '@/types/api/uniformity/uniformity';
|
||||||
import ExpandedDrawerForm from '@/components/pages/uniformity/form/ExpandedDrawerForm';
|
import ExpandedDrawerForm from '@/components/pages/uniformity/form/ExpandedDrawerForm';
|
||||||
|
|
||||||
interface UniformityFormProps {
|
interface UniformityFormProps {
|
||||||
formType?: 'add' | 'edit';
|
formType?: 'add' | 'edit';
|
||||||
|
initialValues?: Uniformity;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UniformityForm = ({ formType = 'add' }: UniformityFormProps) => {
|
const UniformityForm = ({
|
||||||
|
formType = 'add',
|
||||||
|
initialValues,
|
||||||
|
}: UniformityFormProps) => {
|
||||||
|
const router = useRouter();
|
||||||
const subscribeValidate = useUiStore((s) => s.subscribeValidate);
|
const subscribeValidate = useUiStore((s) => s.subscribeValidate);
|
||||||
const setIsValid = useUiStore((s) => s.setIsValid);
|
const setIsValid = useUiStore((s) => s.setIsValid);
|
||||||
const expandedDrawerOpen = useUiStore((s) => s.expandedDrawerOpen);
|
const expandedDrawerOpen = useUiStore((s) => s.expandedDrawerOpen);
|
||||||
const setExpandedDrawerOpen = useUiStore((s) => s.setExpandedDrawerOpen);
|
const setExpandedDrawerOpen = useUiStore((s) => s.setExpandedDrawerOpen);
|
||||||
|
|
||||||
|
const [locationSelectInputValue, setLocationSelectInputValue] = useState('');
|
||||||
|
const [uniformityFormErrorMessage, setUniformityFormErrorMessage] =
|
||||||
|
useState('');
|
||||||
|
|
||||||
|
// ===== SELECT INPUT DATA =====
|
||||||
|
const {
|
||||||
|
setInputValue: setKandangSelectInputValue,
|
||||||
|
options: kandangOptions,
|
||||||
|
isLoadingOptions: isLoadingKandangs,
|
||||||
|
} = useSelect(KandangApi.basePath, 'id', 'name', 'search');
|
||||||
|
|
||||||
|
// ===== FORM CONFIGURATION =====
|
||||||
|
const formikInitialValues = useMemo<UniformityFormValues>(
|
||||||
|
() => getUniformityFormInitialValues(initialValues),
|
||||||
|
[initialValues]
|
||||||
|
);
|
||||||
|
|
||||||
|
const formik = useFormik<UniformityFormValues>({
|
||||||
|
initialValues: formikInitialValues,
|
||||||
|
validationSchema: UniformityFormSchema,
|
||||||
|
validateOnChange: true,
|
||||||
|
validateOnBlur: true,
|
||||||
|
validateOnMount: false,
|
||||||
|
enableReinitialize: true,
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('date', values.date);
|
||||||
|
formData.append('location_id', values.location_id.toString());
|
||||||
|
formData.append(
|
||||||
|
'project_flock_kandang_id',
|
||||||
|
values.project_flock_kandang_id.toString()
|
||||||
|
);
|
||||||
|
formData.append('kandang_id', values.kandang_id.toString());
|
||||||
|
|
||||||
|
if (values.files) {
|
||||||
|
formData.append('files[]', values.files);
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await UniformityApi.create(
|
||||||
|
formData as unknown as CreateUniformityPayload
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isResponseError(res)) {
|
||||||
|
setUniformityFormErrorMessage(res.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.success(res?.message as string);
|
||||||
|
router.push('/uniformity');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// ===== API DATA FETCHING =====
|
||||||
|
const locationsUrl = useMemo(() => {
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
search: locationSelectInputValue,
|
||||||
|
});
|
||||||
|
return `${LocationApi.basePath}?${params.toString()}`;
|
||||||
|
}, [locationSelectInputValue]);
|
||||||
|
|
||||||
|
const { data: locations, isLoading: isLoadingLocations } = useSWR(
|
||||||
|
locationsUrl,
|
||||||
|
LocationApi.getAllFetcher
|
||||||
|
);
|
||||||
|
|
||||||
|
const locationOptions = useMemo(() => {
|
||||||
|
if (!locations || !isResponseSuccess(locations)) return [];
|
||||||
|
return (
|
||||||
|
locations.data.map((location) => ({
|
||||||
|
value: location.id,
|
||||||
|
label: location.name,
|
||||||
|
})) || []
|
||||||
|
);
|
||||||
|
}, [locations]);
|
||||||
|
|
||||||
|
// ===== FORM HANDLERS =====
|
||||||
|
const handleLocationChange = useCallback(
|
||||||
|
(val: OptionType | OptionType[] | null) => {
|
||||||
|
const location = val as OptionType | null;
|
||||||
|
formik.setFieldTouched('location', true);
|
||||||
|
formik.setFieldValue('location', location);
|
||||||
|
formik.setFieldTouched('location_id', true);
|
||||||
|
formik.setFieldValue('location_id', (location as OptionType)?.value || 0);
|
||||||
|
},
|
||||||
|
[formik]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleKandangChange = useCallback(
|
||||||
|
(val: OptionType | OptionType[] | null) => {
|
||||||
|
const kandang = val as OptionType | null;
|
||||||
|
formik.setFieldTouched('kandang', true);
|
||||||
|
formik.setFieldValue('kandang', kandang);
|
||||||
|
formik.setFieldTouched('kandang_id', true);
|
||||||
|
formik.setFieldValue('kandang_id', (kandang as OptionType)?.value || 0);
|
||||||
|
},
|
||||||
|
[formik]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleFileChange = useCallback(
|
||||||
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const file = e.target.files?.[0];
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
formik.setFieldValue('files', undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.size > 2 * 1024 * 1024) {
|
||||||
|
toast.error(`Ukuran file ${file.name} maksimal 2 MB!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const allowedTypes = [
|
||||||
|
'application/vnd.ms-excel',
|
||||||
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
'text/csv',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!allowedTypes.includes(file.type)) {
|
||||||
|
toast.error(`Format file ${file.name} harus Excel atau CSV!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
formik.setFieldValue('files', file);
|
||||||
|
},
|
||||||
|
[formik]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleDateChange = useCallback(
|
||||||
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
formik.setFieldValue('date', e.target.value);
|
||||||
|
},
|
||||||
|
[formik]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleRemoveFile = useCallback(() => {
|
||||||
|
formik.setFieldValue('files', undefined);
|
||||||
|
}, [formik]);
|
||||||
|
|
||||||
|
// ===== EFFECTS =====
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsub = subscribeValidate(() => {
|
const unsub = subscribeValidate(() => {
|
||||||
setIsValid(true);
|
setIsValid(true);
|
||||||
@@ -31,9 +200,7 @@ const UniformityForm = ({ formType = 'add' }: UniformityFormProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex h-screen'>
|
<div className='flex h-screen'>
|
||||||
{/* Primary Drawer Content */}
|
|
||||||
<section className='w-full'>
|
<section className='w-full'>
|
||||||
{/* Header */}
|
|
||||||
<DrawerHeader
|
<DrawerHeader
|
||||||
leftIcon={formType == 'add' ? 'mdi:close' : 'mdi:arrow-left'}
|
leftIcon={formType == 'add' ? 'mdi:close' : 'mdi:arrow-left'}
|
||||||
leftIconSize={24}
|
leftIconSize={24}
|
||||||
@@ -45,28 +212,175 @@ const UniformityForm = ({ formType = 'add' }: UniformityFormProps) => {
|
|||||||
subtitleClassName='text-sm text-neutral'
|
subtitleClassName='text-sm text-neutral'
|
||||||
showDivider
|
showDivider
|
||||||
/>
|
/>
|
||||||
{/* Form Section */}
|
|
||||||
<div className='divider mt-3'></div>
|
<div className='divider mt-3'></div>
|
||||||
<section className='w-full px-6'>
|
<section className='w-full px-6'>
|
||||||
<h2 className='text-2xl font-semibold'>Informasi Umum</h2>
|
<h2 className='text-2xl font-semibold mb-6'>Informasi Umum</h2>
|
||||||
<form
|
|
||||||
onSubmit={(e) => {
|
<form onSubmit={formik.handleSubmit} className='flex flex-col gap-6'>
|
||||||
e.preventDefault();
|
{uniformityFormErrorMessage && (
|
||||||
}}
|
<div className='alert alert-error' role='alert'>
|
||||||
>
|
<Icon
|
||||||
|
icon='material-symbols:error-outline'
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
/>
|
||||||
|
<span>{uniformityFormErrorMessage}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<DateInput
|
||||||
|
required
|
||||||
|
label='Tanggal'
|
||||||
|
name='date'
|
||||||
|
value={formik.values.date}
|
||||||
|
onChange={handleDateChange}
|
||||||
|
onBlur={formik.handleBlur}
|
||||||
|
isError={formik.touched.date && Boolean(formik.errors.date)}
|
||||||
|
errorMessage={formik.errors.date as string}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SelectInput
|
||||||
|
required
|
||||||
|
label='Lokasi Farm'
|
||||||
|
placeholder='Pilih Lokasi...'
|
||||||
|
value={formik.values.location}
|
||||||
|
onChange={handleLocationChange}
|
||||||
|
options={locationOptions}
|
||||||
|
onInputChange={setLocationSelectInputValue}
|
||||||
|
isLoading={isLoadingLocations}
|
||||||
|
isError={
|
||||||
|
formik.touched.location_id && Boolean(formik.errors.location_id)
|
||||||
|
}
|
||||||
|
errorMessage={formik.errors.location_id as string}
|
||||||
|
isClearable
|
||||||
|
className={{ wrapper: 'w-full' }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SelectInput
|
||||||
|
required
|
||||||
|
label='Project Flock Kandang'
|
||||||
|
placeholder='Pilih Project Flock Kandang...'
|
||||||
|
value={
|
||||||
|
formik.values.project_flock_kandang_id
|
||||||
|
? {
|
||||||
|
value: formik.values.project_flock_kandang_id,
|
||||||
|
label: formik.values.project_flock_kandang_id.toString(),
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
onChange={(val) => {
|
||||||
|
const option = val as OptionType | null;
|
||||||
|
formik.setFieldValue(
|
||||||
|
'project_flock_kandang_id',
|
||||||
|
option?.value || 0
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
options={[
|
||||||
|
{ value: 1, label: '1' },
|
||||||
|
{ value: 2, label: '2' },
|
||||||
|
{ value: 3, label: '3' },
|
||||||
|
]}
|
||||||
|
isError={
|
||||||
|
formik.touched.project_flock_kandang_id &&
|
||||||
|
Boolean(formik.errors.project_flock_kandang_id)
|
||||||
|
}
|
||||||
|
errorMessage={formik.errors.project_flock_kandang_id as string}
|
||||||
|
isClearable
|
||||||
|
className={{ wrapper: 'w-full' }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SelectInput
|
||||||
|
required
|
||||||
|
label='Kandang'
|
||||||
|
placeholder='Pilih Kandang...'
|
||||||
|
value={formik.values.kandang}
|
||||||
|
onChange={handleKandangChange}
|
||||||
|
options={kandangOptions}
|
||||||
|
onInputChange={setKandangSelectInputValue}
|
||||||
|
isLoading={isLoadingKandangs}
|
||||||
|
isError={
|
||||||
|
formik.touched.kandang_id && Boolean(formik.errors.kandang_id)
|
||||||
|
}
|
||||||
|
errorMessage={formik.errors.kandang_id as string}
|
||||||
|
isClearable
|
||||||
|
className={{ wrapper: 'w-full' }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<FileInput
|
||||||
|
required
|
||||||
|
name='files'
|
||||||
|
label='Upload File'
|
||||||
|
onChange={handleFileChange}
|
||||||
|
accept='application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,text/csv'
|
||||||
|
isError={formik.touched.files && Boolean(formik.errors.files)}
|
||||||
|
errorMessage={formik.errors.files as string}
|
||||||
|
className={{ wrapper: 'w-full' }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{formik.values.files && (
|
||||||
|
<div className='mt-4 flex flex-col gap-2'>
|
||||||
|
<label className='text-sm font-semibold'>
|
||||||
|
File yang dipilih:
|
||||||
|
</label>
|
||||||
|
<div className='flex items-center justify-between gap-4 p-3 bg-base-200 rounded-lg'>
|
||||||
|
<div className='flex items-center gap-2'>
|
||||||
|
<Icon
|
||||||
|
icon='material-symbols:attach-file'
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
/>
|
||||||
|
<span className='text-sm'>
|
||||||
|
{formik.values.files.name}
|
||||||
|
</span>
|
||||||
|
<span className='text-xs text-base-content/60'>
|
||||||
|
({(formik.values.files.size / 1024).toFixed(2)} KB)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
type='button'
|
||||||
|
color='error'
|
||||||
|
onClick={handleRemoveFile}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon='material-symbols:delete-outline-rounded'
|
||||||
|
width={18}
|
||||||
|
height={18}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type='submit'
|
||||||
|
color='primary'
|
||||||
|
className='w-full'
|
||||||
|
disabled={formik.isSubmitting}
|
||||||
|
>
|
||||||
|
{formik.isSubmitting ? (
|
||||||
|
<span className='loading loading-spinner'></span>
|
||||||
|
) : (
|
||||||
|
'Simpan'
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{formType === 'add' && (
|
||||||
<Button
|
<Button
|
||||||
color='primary'
|
color='primary'
|
||||||
onClick={handleOpenExpandedDrawer}
|
onClick={handleOpenExpandedDrawer}
|
||||||
className='mt-6 w-full'
|
className='mt-4 w-full'
|
||||||
>
|
>
|
||||||
<Icon icon='ic:round-plus' width={18} height={18} />
|
<Icon icon='ic:round-plus' width={18} height={18} />
|
||||||
Expand Drawer
|
Expand Drawer
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
)}
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Expanded Drawer - shown when open */}
|
|
||||||
{expandedDrawerOpen && <ExpandedDrawerForm />}
|
{expandedDrawerOpen && <ExpandedDrawerForm />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { BaseApiService } from '@/services/api/base';
|
import { BaseApiService } from '@/services/api/base';
|
||||||
import { BaseApiResponse } from '@/types/api/api-general';
|
import { BaseApiResponse } from '@/types/api/api-general';
|
||||||
import { Uniformity } from '@/types/api/uniformity/uniformity';
|
import {
|
||||||
|
CreateUniformityPayload,
|
||||||
|
Uniformity,
|
||||||
|
} from '@/types/api/uniformity/uniformity';
|
||||||
|
|
||||||
export class UniformityApiService extends BaseApiService<
|
export class UniformityApiService extends BaseApiService<
|
||||||
Uniformity,
|
Uniformity,
|
||||||
unknown,
|
CreateUniformityPayload,
|
||||||
unknown
|
unknown
|
||||||
> {
|
> {
|
||||||
constructor(basePath: string) {
|
constructor(basePath: string) {
|
||||||
@@ -14,6 +17,25 @@ export class UniformityApiService extends BaseApiService<
|
|||||||
async getUniformity(): Promise<BaseApiResponse<Uniformity> | undefined> {
|
async getUniformity(): Promise<BaseApiResponse<Uniformity> | undefined> {
|
||||||
return await this.customRequest<BaseApiResponse<Uniformity>>('');
|
return await this.customRequest<BaseApiResponse<Uniformity>>('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createUniformity(
|
||||||
|
payload: CreateUniformityPayload
|
||||||
|
): Promise<BaseApiResponse<Uniformity> | undefined> {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('date', payload.date);
|
||||||
|
formData.append('location_id', payload.location_id.toString());
|
||||||
|
formData.append(
|
||||||
|
'project_flock_kandang_id',
|
||||||
|
payload.project_flock_kandang_id.toString()
|
||||||
|
);
|
||||||
|
formData.append('kandang_id', payload.kandang_id.toString());
|
||||||
|
|
||||||
|
if (payload.files) {
|
||||||
|
formData.append('files[]', payload.files);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.create(formData as unknown as CreateUniformityPayload);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// export const UniformityApi = new UniformityApiService('uniformity');
|
// export const UniformityApi = new UniformityApiService('uniformity');
|
||||||
|
|||||||
+8
@@ -11,3 +11,11 @@ export type Uniformity = BaseMetadata & {
|
|||||||
status: 'CREATED' | 'APPROVED' | 'REJECTED';
|
status: 'CREATED' | 'APPROVED' | 'REJECTED';
|
||||||
uniformity: number;
|
uniformity: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CreateUniformityPayload = {
|
||||||
|
date: string;
|
||||||
|
location_id: number;
|
||||||
|
project_flock_kandang_id: number;
|
||||||
|
kandang_id: number;
|
||||||
|
files: File;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user