mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
fix(FE): resolve merge conflict with branch development
This commit is contained in:
@@ -14,7 +14,7 @@ const RecordingEdit = () => {
|
|||||||
|
|
||||||
const { data: recording, isLoading: isLoadingRecording } = useSWR(
|
const { data: recording, isLoading: isLoadingRecording } = useSWR(
|
||||||
recordingId,
|
recordingId,
|
||||||
(id: number) => RecordingApi.getSingle(id) // Gunakan RecordingApi
|
(id: string) => RecordingApi.getSingle(parseInt(id))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!recordingId) {
|
if (!recordingId) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const RecordingDetail = () => {
|
|||||||
|
|
||||||
const { data: recording, isLoading: isLoadingRecording } = useSWR(
|
const { data: recording, isLoading: isLoadingRecording } = useSWR(
|
||||||
recordingId,
|
recordingId,
|
||||||
(id: number) => RecordingApi.getSingle(id)
|
(id: string) => RecordingApi.getSingle(parseInt(id))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!recordingId) {
|
if (!recordingId) {
|
||||||
|
|||||||
@@ -50,12 +50,17 @@ const RowOptionsMenu = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isRecordingRejected = (recording: Recording) => {
|
||||||
|
return recording.approval?.action === 'REJECTED';
|
||||||
|
};
|
||||||
|
|
||||||
const isApproved = isRecordingApproved(props.row.original);
|
const isApproved = isRecordingApproved(props.row.original);
|
||||||
|
const isRejected = isRecordingRejected(props.row.original);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RowOptionsMenuWrapper type={type}>
|
<RowOptionsMenuWrapper type={type}>
|
||||||
<Button
|
<Button
|
||||||
href={`recording/detail/?recordingId=${props.row.original.id}`}
|
href={`/production/recording/detail/?recordingId=${props.row.original.id}`}
|
||||||
variant='ghost'
|
variant='ghost'
|
||||||
color='primary'
|
color='primary'
|
||||||
className='justify-start text-sm'
|
className='justify-start text-sm'
|
||||||
@@ -64,7 +69,7 @@ const RowOptionsMenu = ({
|
|||||||
Detail
|
Detail
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
href={`recording/detail/edit/?recordingId=${props.row.original.id}`}
|
href={`/production/recording/detail/edit/?recordingId=${props.row.original.id}`}
|
||||||
variant='ghost'
|
variant='ghost'
|
||||||
color='warning'
|
color='warning'
|
||||||
className='justify-start text-sm'
|
className='justify-start text-sm'
|
||||||
@@ -72,7 +77,7 @@ const RowOptionsMenu = ({
|
|||||||
<Icon icon='mdi:pencil-outline' width={16} height={16} />
|
<Icon icon='mdi:pencil-outline' width={16} height={16} />
|
||||||
Edit
|
Edit
|
||||||
</Button>
|
</Button>
|
||||||
{!isApproved && (
|
{!isApproved && !isRejected && (
|
||||||
<Button
|
<Button
|
||||||
onClick={approveClickHandler}
|
onClick={approveClickHandler}
|
||||||
variant='ghost'
|
variant='ghost'
|
||||||
@@ -83,7 +88,7 @@ const RowOptionsMenu = ({
|
|||||||
Approve
|
Approve
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{!isApproved && (
|
{!isApproved && !isRejected && (
|
||||||
<Button
|
<Button
|
||||||
onClick={rejectClickHandler}
|
onClick={rejectClickHandler}
|
||||||
variant='ghost'
|
variant='ghost'
|
||||||
|
|||||||
@@ -112,6 +112,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const isRecordingRejected = useCallback((recording?: Recording) => {
|
||||||
|
return recording?.approval?.action === 'REJECTED';
|
||||||
|
}, []);
|
||||||
|
|
||||||
// ===== PAYLOAD CREATION HELPERS =====
|
// ===== PAYLOAD CREATION HELPERS =====
|
||||||
const createGrowingPayload = useCallback(
|
const createGrowingPayload = useCallback(
|
||||||
(values: RecordingGrowingFormValues) => {
|
(values: RecordingGrowingFormValues) => {
|
||||||
@@ -1483,37 +1487,48 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
Kembali
|
Kembali
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{type === 'detail' && !isRecordingApproved(initialValues) && (
|
{type === 'detail' &&
|
||||||
<div className='flex flex-row gap-2'>
|
initialValues?.approval &&
|
||||||
<Button
|
!isRecordingApproved(initialValues) &&
|
||||||
variant='outline'
|
!isRecordingRejected(initialValues) && (
|
||||||
color='success'
|
<div className='flex flex-row gap-2'>
|
||||||
onClick={() => {
|
<Button
|
||||||
setApprovalNotes('');
|
variant='outline'
|
||||||
approveModal.openModal();
|
color='success'
|
||||||
}}
|
onClick={() => {
|
||||||
isLoading={isApproveLoading}
|
setApprovalNotes('');
|
||||||
className='w-full sm:w-fit'
|
approveModal.openModal();
|
||||||
>
|
}}
|
||||||
<Icon icon='material-symbols:check' width={24} height={24} />
|
isLoading={isApproveLoading}
|
||||||
Approve
|
className='w-full sm:w-fit'
|
||||||
</Button>
|
>
|
||||||
|
<Icon
|
||||||
|
icon='material-symbols:check'
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
/>
|
||||||
|
Approve
|
||||||
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant='outline'
|
variant='outline'
|
||||||
color='error'
|
color='error'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setApprovalNotes('');
|
setApprovalNotes('');
|
||||||
rejectModal.openModal();
|
rejectModal.openModal();
|
||||||
}}
|
}}
|
||||||
isLoading={isRejectLoading}
|
isLoading={isRejectLoading}
|
||||||
className='w-full sm:w-fit'
|
className='w-full sm:w-fit'
|
||||||
>
|
>
|
||||||
<Icon icon='material-symbols:close' width={24} height={24} />
|
<Icon
|
||||||
Reject
|
icon='material-symbols:close'
|
||||||
</Button>
|
width={24}
|
||||||
</div>
|
height={24}
|
||||||
)}
|
/>
|
||||||
|
Reject
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 className='text-2xl font-bold text-center'>
|
<h1 className='text-2xl font-bold text-center'>
|
||||||
@@ -2803,7 +2818,8 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
|
|
||||||
{/* Approve Confirmation Modal */}
|
{/* Approve Confirmation Modal */}
|
||||||
{(type as 'add' | 'edit' | 'detail') === 'detail' &&
|
{(type as 'add' | 'edit' | 'detail') === 'detail' &&
|
||||||
!isRecordingApproved(initialValues) && (
|
!isRecordingApproved(initialValues) &&
|
||||||
|
!isRecordingRejected(initialValues) && (
|
||||||
<ConfirmationModalWithNotes
|
<ConfirmationModalWithNotes
|
||||||
ref={approveModal.ref}
|
ref={approveModal.ref}
|
||||||
type='success'
|
type='success'
|
||||||
|
|||||||
@@ -314,7 +314,9 @@ const PurchaseOrderStaffApprovalForm = ({
|
|||||||
const isNewItemForm =
|
const isNewItemForm =
|
||||||
!formItem.purchase_item_id || formItem.purchase_item_id === 0;
|
!formItem.purchase_item_id || formItem.purchase_item_id === 0;
|
||||||
|
|
||||||
let cleanPayload: UpdateStaffApprovalRequestPayload['items'][0];
|
let cleanPayload: NonNullable<
|
||||||
|
UpdateStaffApprovalRequestPayload['items']
|
||||||
|
>[0];
|
||||||
|
|
||||||
if (isNewItemForm) {
|
if (isNewItemForm) {
|
||||||
cleanPayload = {
|
cleanPayload = {
|
||||||
@@ -362,7 +364,9 @@ const PurchaseOrderStaffApprovalForm = ({
|
|||||||
const isNewItemForm =
|
const isNewItemForm =
|
||||||
!formItem.purchase_item_id || formItem.purchase_item_id === 0;
|
!formItem.purchase_item_id || formItem.purchase_item_id === 0;
|
||||||
|
|
||||||
let cleanPayload: UpdateStaffApprovalRequestPayload['items'][0];
|
let cleanPayload: NonNullable<
|
||||||
|
UpdateStaffApprovalRequestPayload['items']
|
||||||
|
>[0];
|
||||||
|
|
||||||
if (isNewItemForm) {
|
if (isNewItemForm) {
|
||||||
cleanPayload = {
|
cleanPayload = {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ type PurchaseRequestFormSchemaType = {
|
|||||||
label: string;
|
label: string;
|
||||||
} | null;
|
} | null;
|
||||||
supplier_id: number;
|
supplier_id: number;
|
||||||
|
credit_term: number;
|
||||||
area?: {
|
area?: {
|
||||||
value: number;
|
value: number;
|
||||||
label: string;
|
label: string;
|
||||||
@@ -81,6 +82,10 @@ export const PurchaseRequestFormSchema: Yup.ObjectSchema<PurchaseRequestFormSche
|
|||||||
.required('Supplier wajib dipilih!')
|
.required('Supplier wajib dipilih!')
|
||||||
.min(1, 'Supplier wajib dipilih!')
|
.min(1, 'Supplier wajib dipilih!')
|
||||||
.typeError('Supplier wajib dipilih!'),
|
.typeError('Supplier wajib dipilih!'),
|
||||||
|
credit_term: Yup.number()
|
||||||
|
.required('Jangka waktu kredit wajib diisi!')
|
||||||
|
.min(0, 'Jangka waktu kredit tidak boleh kurang dari 0!')
|
||||||
|
.typeError('Jangka waktu kredit wajib diisi!'),
|
||||||
area: Yup.object({
|
area: Yup.object({
|
||||||
value: Yup.number().min(1).required(),
|
value: Yup.number().min(1).required(),
|
||||||
label: Yup.string().required(),
|
label: Yup.string().required(),
|
||||||
@@ -119,6 +124,7 @@ export const getPurchaseRequestFormInitialValues = (
|
|||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
supplier_id: initialValues?.supplier?.id ?? 0,
|
supplier_id: initialValues?.supplier?.id ?? 0,
|
||||||
|
credit_term: initialValues?.credit_term ?? 0,
|
||||||
area: initialValues?.area
|
area: initialValues?.area
|
||||||
? {
|
? {
|
||||||
value: initialValues.area.id,
|
value: initialValues.area.id,
|
||||||
|
|||||||
@@ -185,6 +185,10 @@ const PurchaseRequestForm = ({
|
|||||||
typeof values.supplier_id === 'string'
|
typeof values.supplier_id === 'string'
|
||||||
? parseInt(values.supplier_id) || 0
|
? parseInt(values.supplier_id) || 0
|
||||||
: values.supplier_id || 0,
|
: values.supplier_id || 0,
|
||||||
|
credit_term:
|
||||||
|
typeof values.credit_term === 'string'
|
||||||
|
? parseInt(values.credit_term) || 0
|
||||||
|
: values.credit_term || 0,
|
||||||
notes: values.notes || '',
|
notes: values.notes || '',
|
||||||
items: (values.items || []).map((item) => ({
|
items: (values.items || []).map((item) => ({
|
||||||
warehouse_id: Number(item.warehouse_id) || 0,
|
warehouse_id: Number(item.warehouse_id) || 0,
|
||||||
@@ -338,6 +342,27 @@ const PurchaseRequestForm = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ===== UTILITY FUNCTIONS =====
|
// ===== UTILITY FUNCTIONS =====
|
||||||
|
const updateCreditTermBasedOnSupplier = useCallback(
|
||||||
|
(supplierId: number) => {
|
||||||
|
if (supplierId > 0 && isResponseSuccess(supplierRawData)) {
|
||||||
|
const supplierData = supplierRawData.data.find(
|
||||||
|
(s: Supplier) => s.id === supplierId
|
||||||
|
);
|
||||||
|
if (supplierData?.due_date) {
|
||||||
|
formik.setFieldTouched('credit_term', false);
|
||||||
|
formik.setFieldValue('credit_term', supplierData.due_date.toString());
|
||||||
|
} else {
|
||||||
|
formik.setFieldTouched('credit_term', false);
|
||||||
|
formik.setFieldValue('credit_term', '');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
formik.setFieldTouched('credit_term', false);
|
||||||
|
formik.setFieldValue('credit_term', '');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[supplierRawData]
|
||||||
|
);
|
||||||
|
|
||||||
const resetPurchaseItems = useCallback(() => {
|
const resetPurchaseItems = useCallback(() => {
|
||||||
if (formik.values.items) {
|
if (formik.values.items) {
|
||||||
formik.values.items.forEach((_, idx) => {
|
formik.values.items.forEach((_, idx) => {
|
||||||
@@ -352,6 +377,16 @@ const PurchaseRequestForm = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// ===== SIDE EFFECTS =====
|
// ===== SIDE EFFECTS =====
|
||||||
|
useEffect(() => {
|
||||||
|
if (formik.values.supplier_id && Number(formik.values.supplier_id) > 0) {
|
||||||
|
updateCreditTermBasedOnSupplier(Number(formik.values.supplier_id));
|
||||||
|
resetPurchaseItems();
|
||||||
|
} else {
|
||||||
|
formik.setFieldTouched('credit_term', false);
|
||||||
|
formik.setFieldValue('credit_term', '');
|
||||||
|
resetPurchaseItems();
|
||||||
|
}
|
||||||
|
}, [formik.values.supplier_id]);
|
||||||
|
|
||||||
// ===== FORM HANDLERS =====
|
// ===== FORM HANDLERS =====
|
||||||
const handleSupplierChange = useCallback(
|
const handleSupplierChange = useCallback(
|
||||||
@@ -367,6 +402,23 @@ const PurchaseRequestForm = ({
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleCreditTermChange = useCallback(
|
||||||
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
|
||||||
|
formik.setFieldTouched('credit_term', true);
|
||||||
|
formik.setFieldValue('credit_term', value);
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleCreditTermBlur = useCallback(
|
||||||
|
(e: React.FocusEvent<HTMLInputElement>) => {
|
||||||
|
formik.handleBlur(e);
|
||||||
|
},
|
||||||
|
[formik]
|
||||||
|
);
|
||||||
|
|
||||||
const handleAreaChange = useCallback(
|
const handleAreaChange = useCallback(
|
||||||
(val: OptionType | OptionType[] | null) => {
|
(val: OptionType | OptionType[] | null) => {
|
||||||
const area = val as OptionType | null;
|
const area = val as OptionType | null;
|
||||||
@@ -447,7 +499,7 @@ const PurchaseRequestForm = ({
|
|||||||
body: 'flex flex-col gap-6',
|
body: 'flex flex-col gap-6',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className={'grid grid-cols-1 md:grid-cols-3 gap-6'}>
|
<div className={'grid grid-cols-1 md:grid-cols-2 gap-6'}>
|
||||||
<SelectInput
|
<SelectInput
|
||||||
required
|
required
|
||||||
label='Vendor'
|
label='Vendor'
|
||||||
@@ -466,6 +518,29 @@ const PurchaseRequestForm = ({
|
|||||||
isClearable
|
isClearable
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<NumberInput
|
||||||
|
required={!!formik.values.supplier_id}
|
||||||
|
label='Jatuh tempo (hari)'
|
||||||
|
name='credit_term'
|
||||||
|
value={formik.values.credit_term || ''}
|
||||||
|
onChange={handleCreditTermChange}
|
||||||
|
onBlur={handleCreditTermBlur}
|
||||||
|
isError={
|
||||||
|
formik.touched.credit_term &&
|
||||||
|
Boolean(formik.errors.credit_term)
|
||||||
|
}
|
||||||
|
errorMessage={formik.errors.credit_term as string}
|
||||||
|
readOnly={type === 'detail' || !formik.values.supplier_id}
|
||||||
|
disabled={type === 'detail' || !formik.values.supplier_id}
|
||||||
|
allowNegative={false}
|
||||||
|
decimalScale={0}
|
||||||
|
placeholder={
|
||||||
|
!formik.values.supplier_id
|
||||||
|
? 'Pilih Vendor terlebih dahulu'
|
||||||
|
: 'Masukkan jumlah hari jatuh tempo'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<SelectInput
|
<SelectInput
|
||||||
label='Area'
|
label='Area'
|
||||||
placeholder='Pilih Area...'
|
placeholder='Pilih Area...'
|
||||||
@@ -490,7 +565,7 @@ const PurchaseRequestForm = ({
|
|||||||
isClearable={type !== 'detail'}
|
isClearable={type !== 'detail'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={'md:col-span-3'}>
|
<div className={'col-span-2'}>
|
||||||
<TextInput
|
<TextInput
|
||||||
label='Notes'
|
label='Notes'
|
||||||
name='notes'
|
name='notes'
|
||||||
|
|||||||
@@ -1052,7 +1052,6 @@ const PurchaseOrderDetail = ({
|
|||||||
const payload: CreateStaffApprovalRequestPayload = {
|
const payload: CreateStaffApprovalRequestPayload = {
|
||||||
action: 'REJECTED',
|
action: 'REJECTED',
|
||||||
notes: notes || null,
|
notes: notes || null,
|
||||||
items: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
await createStaffApprovalHandler(payload);
|
await createStaffApprovalHandler(payload);
|
||||||
@@ -1080,7 +1079,6 @@ const PurchaseOrderDetail = ({
|
|||||||
const payload: CreateAcceptApprovalRequestPayload = {
|
const payload: CreateAcceptApprovalRequestPayload = {
|
||||||
action: 'REJECTED',
|
action: 'REJECTED',
|
||||||
notes: notes || null,
|
notes: notes || null,
|
||||||
items: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
await createAcceptApprovalHandler(payload);
|
await createAcceptApprovalHandler(payload);
|
||||||
|
|||||||
@@ -309,6 +309,9 @@ const PurchaseOrderInvoice = ({ data }: PurchaseOrderInvoiceProps) => {
|
|||||||
{purchaseData?.supplier?.alias || ''})
|
{purchaseData?.supplier?.alias || ''})
|
||||||
</Text>
|
</Text>
|
||||||
<Text>{purchaseData?.supplier?.category || '-'}</Text>
|
<Text>{purchaseData?.supplier?.category || '-'}</Text>
|
||||||
|
<Text>
|
||||||
|
Credit Term: {purchaseData?.credit_term || 0} hari
|
||||||
|
</Text>
|
||||||
<Text>
|
<Text>
|
||||||
Due Date:{' '}
|
Due Date:{' '}
|
||||||
{purchaseData?.due_date
|
{purchaseData?.due_date
|
||||||
|
|||||||
Vendored
+6
-4
@@ -51,6 +51,7 @@ export type BasePurchase = {
|
|||||||
po_document_path?: string | null;
|
po_document_path?: string | null;
|
||||||
po_date: string;
|
po_date: string;
|
||||||
supplier: Supplier;
|
supplier: Supplier;
|
||||||
|
credit_term?: number;
|
||||||
due_date: string;
|
due_date: string;
|
||||||
notes?: string | null;
|
notes?: string | null;
|
||||||
deleted_at?: string | null;
|
deleted_at?: string | null;
|
||||||
@@ -66,8 +67,9 @@ export type Purchase = BaseMetadata & BasePurchase;
|
|||||||
|
|
||||||
export type CreatePurchaseRequestPayload = {
|
export type CreatePurchaseRequestPayload = {
|
||||||
supplier_id: number;
|
supplier_id: number;
|
||||||
|
credit_term: number;
|
||||||
notes?: string | null;
|
notes?: string | null;
|
||||||
items: {
|
items?: {
|
||||||
warehouse_id: number;
|
warehouse_id: number;
|
||||||
product_id: number;
|
product_id: number;
|
||||||
qty: number;
|
qty: number;
|
||||||
@@ -77,7 +79,7 @@ export type CreatePurchaseRequestPayload = {
|
|||||||
export type CreateStaffApprovalRequestPayload = {
|
export type CreateStaffApprovalRequestPayload = {
|
||||||
action: 'APPROVED' | 'REJECTED';
|
action: 'APPROVED' | 'REJECTED';
|
||||||
notes?: string | null;
|
notes?: string | null;
|
||||||
items: {
|
items?: {
|
||||||
purchase_item_id: number;
|
purchase_item_id: number;
|
||||||
qty: number;
|
qty: number;
|
||||||
price: number;
|
price: number;
|
||||||
@@ -88,7 +90,7 @@ export type CreateStaffApprovalRequestPayload = {
|
|||||||
export type UpdateStaffApprovalRequestPayload = {
|
export type UpdateStaffApprovalRequestPayload = {
|
||||||
action: 'APPROVED' | 'REJECTED';
|
action: 'APPROVED' | 'REJECTED';
|
||||||
notes?: string | null;
|
notes?: string | null;
|
||||||
items: Array<{
|
items?: Array<{
|
||||||
purchase_item_id?: number;
|
purchase_item_id?: number;
|
||||||
product_id?: number;
|
product_id?: number;
|
||||||
warehouse_id?: number;
|
warehouse_id?: number;
|
||||||
@@ -106,7 +108,7 @@ export type CreateManagerApprovalRequestPayload = {
|
|||||||
export type CreateAcceptApprovalRequestPayload = {
|
export type CreateAcceptApprovalRequestPayload = {
|
||||||
action: 'APPROVED' | 'REJECTED';
|
action: 'APPROVED' | 'REJECTED';
|
||||||
notes?: string | null;
|
notes?: string | null;
|
||||||
items: {
|
items?: {
|
||||||
purchase_item_id: number;
|
purchase_item_id: number;
|
||||||
received_date: string;
|
received_date: string;
|
||||||
travel_number: string;
|
travel_number: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user