From 3a7f1f48121aba5955c270ea29d4c7324ff1a978 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 8 Dec 2025 14:42:39 +0700 Subject: [PATCH 01/11] refactor(FE-311): remove transport_total field and update approval actions --- .gitignore | 3 + package-lock.json | 92 ++++++++++--------- package.json | 2 +- .../order/PurchaseOrderAcceptApprovalForm.tsx | 60 +----------- .../form/order/PurchaseOrderForm.schema.ts | 32 +++---- .../purchase/order/PurchaseOrderDetail.tsx | 1 + src/types/api/purchase/purchase.d.ts | 4 +- 7 files changed, 73 insertions(+), 121 deletions(-) diff --git a/.gitignore b/.gitignore index d86875dd..7d6264e6 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,6 @@ next-env.d.ts # idea .idea + +# claude +.claude \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ec1316ae..d73a1b22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "clsx": "^2.1.1", "formik": "^2.4.6", "moment": "^2.30.1", - "next": "15.5.3", + "next": "15.5.7", "react": "19.1.0", "react-day-picker": "^9.11.1", "react-dom": "19.1.0", @@ -1082,9 +1082,9 @@ } }, "node_modules/@next/env": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.3.tgz", - "integrity": "sha512-RSEDTRqyihYXygx/OJXwvVupfr9m04+0vH8vyy0HfZ7keRto6VX9BbEk0J2PUk0VGy6YhklJUSrgForov5F9pw==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.7.tgz", + "integrity": "sha512-4h6Y2NyEkIEN7Z8YxkA27pq6zTkS09bUSYC0xjd0NpwFxjnIKeZEeH591o5WECSmjpUhLn3H2QLJcDye3Uzcvg==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1098,9 +1098,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.3.tgz", - "integrity": "sha512-nzbHQo69+au9wJkGKTU9lP7PXv0d1J5ljFpvb+LnEomLtSbJkbZyEs6sbF3plQmiOB2l9OBtN2tNSvCH1nQ9Jg==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.7.tgz", + "integrity": "sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==", "cpu": [ "arm64" ], @@ -1114,9 +1114,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.3.tgz", - "integrity": "sha512-w83w4SkOOhekJOcA5HBvHyGzgV1W/XvOfpkrxIse4uPWhYTTRwtGEM4v/jiXwNSJvfRvah0H8/uTLBKRXlef8g==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.7.tgz", + "integrity": "sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==", "cpu": [ "x64" ], @@ -1130,9 +1130,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.3.tgz", - "integrity": "sha512-+m7pfIs0/yvgVu26ieaKrifV8C8yiLe7jVp9SpcIzg7XmyyNE7toC1fy5IOQozmr6kWl/JONC51osih2RyoXRw==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.7.tgz", + "integrity": "sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==", "cpu": [ "arm64" ], @@ -1146,9 +1146,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.3.tgz", - "integrity": "sha512-u3PEIzuguSenoZviZJahNLgCexGFhso5mxWCrrIMdvpZn6lkME5vc/ADZG8UUk5K1uWRy4hqSFECrON6UKQBbQ==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.7.tgz", + "integrity": "sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==", "cpu": [ "arm64" ], @@ -1162,9 +1162,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.3.tgz", - "integrity": "sha512-lDtOOScYDZxI2BENN9m0pfVPJDSuUkAD1YXSvlJF0DKwZt0WlA7T7o3wrcEr4Q+iHYGzEaVuZcsIbCps4K27sA==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.7.tgz", + "integrity": "sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==", "cpu": [ "x64" ], @@ -1178,9 +1178,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.3.tgz", - "integrity": "sha512-9vWVUnsx9PrY2NwdVRJ4dUURAQ8Su0sLRPqcCCxtX5zIQUBES12eRVHq6b70bbfaVaxIDGJN2afHui0eDm+cLg==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.7.tgz", + "integrity": "sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==", "cpu": [ "x64" ], @@ -1194,9 +1194,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.3.tgz", - "integrity": "sha512-1CU20FZzY9LFQigRi6jM45oJMU3KziA5/sSG+dXeVaTm661snQP6xu3ykGxxwU5sLG3sh14teO/IOEPVsQMRfA==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.7.tgz", + "integrity": "sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==", "cpu": [ "arm64" ], @@ -1210,9 +1210,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.3.tgz", - "integrity": "sha512-JMoLAq3n3y5tKXPQwCK5c+6tmwkuFDa2XAxz8Wm4+IVthdBZdZGh+lmiLUHg9f9IDwIQpUjp+ysd6OkYTyZRZw==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.7.tgz", + "integrity": "sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==", "cpu": [ "x64" ], @@ -1855,6 +1855,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -1924,6 +1925,7 @@ "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", @@ -2447,6 +2449,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3060,7 +3063,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/daisyui": { "version": "5.3.10", @@ -3516,6 +3520,7 @@ "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3689,6 +3694,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -5654,12 +5660,12 @@ "license": "MIT" }, "node_modules/next": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/next/-/next-15.5.3.tgz", - "integrity": "sha512-r/liNAx16SQj4D+XH/oI1dlpv9tdKJ6cONYPwwcCC46f2NjpaRWY+EKCzULfgQYV6YKXjHBchff2IZBSlZmJNw==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/next/-/next-15.5.7.tgz", + "integrity": "sha512-+t2/0jIJ48kUpGKkdlhgkv+zPTEOoXyr60qXe68eB/pl3CMJaLeIGjzp5D6Oqt25hCBiBTt8wEeeAzfJvUKnPQ==", "license": "MIT", "dependencies": { - "@next/env": "15.5.3", + "@next/env": "15.5.7", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", @@ -5672,14 +5678,14 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.5.3", - "@next/swc-darwin-x64": "15.5.3", - "@next/swc-linux-arm64-gnu": "15.5.3", - "@next/swc-linux-arm64-musl": "15.5.3", - "@next/swc-linux-x64-gnu": "15.5.3", - "@next/swc-linux-x64-musl": "15.5.3", - "@next/swc-win32-arm64-msvc": "15.5.3", - "@next/swc-win32-x64-msvc": "15.5.3", + "@next/swc-darwin-arm64": "15.5.7", + "@next/swc-darwin-x64": "15.5.7", + "@next/swc-linux-arm64-gnu": "15.5.7", + "@next/swc-linux-arm64-musl": "15.5.7", + "@next/swc-linux-x64-gnu": "15.5.7", + "@next/swc-linux-x64-musl": "15.5.7", + "@next/swc-win32-arm64-msvc": "15.5.7", + "@next/swc-win32-x64-msvc": "15.5.7", "sharp": "^0.34.3" }, "peerDependencies": { @@ -6167,6 +6173,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -6197,6 +6204,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -7083,6 +7091,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -7250,6 +7259,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 7396d49d..4b9fdac7 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "clsx": "^2.1.1", "formik": "^2.4.6", "moment": "^2.30.1", - "next": "15.5.3", + "next": "15.5.7", "react": "19.1.0", "react-day-picker": "^9.11.1", "react-dom": "19.1.0", diff --git a/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx b/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx index 79762da9..0a10b1cd 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx +++ b/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx @@ -64,7 +64,6 @@ const PurchaseOrderAcceptApprovalForm = ({ | 'expedition_vendor_id' | 'received_qty' | 'transport_per_item' - | 'transport_total' ): { isError: boolean; errorMessage: string } => { const touchedItem = formik.touched.items?.[idx]; const errorItem = formik.errors.items?.[idx] as @@ -163,6 +162,7 @@ const PurchaseOrderAcceptApprovalForm = ({ validateOnBlur: true, onSubmit: async (values) => { const payload: CreateAcceptApprovalRequestPayload = { + action: 'APPROVED', notes: values.notes || '', items: values.items?.map((formItem) => { @@ -181,10 +181,6 @@ const PurchaseOrderAcceptApprovalForm = ({ typeof formItem.transport_per_item === 'string' ? parseFloat(formItem.transport_per_item) || 0 : formItem.transport_per_item || 0, - transport_total: - typeof formItem.transport_total === 'string' - ? parseFloat(formItem.transport_total) || 0 - : formItem.transport_total || 0, }; }) || [], }; @@ -241,7 +237,6 @@ const PurchaseOrderAcceptApprovalForm = ({ expedition_vendor_id: 0, received_qty: '', transport_per_item: '', - transport_total: '', }; }); formik.setFieldValue('items', updatedItems); @@ -301,7 +296,7 @@ const PurchaseOrderAcceptApprovalForm = ({ // ===== PURCHASE ITEM OPERATIONS ===== const handlePurchaseItemChange = ( idx: number, - field: 'received_qty' | 'transport_per_item' | 'transport_total', + field: 'received_qty' | 'transport_per_item', value: string | number ) => { const numValue = typeof value === 'string' ? parseFloat(value) || 0 : value; @@ -318,26 +313,6 @@ const PurchaseOrderAcceptApprovalForm = ({ : parseFloat( formik.values.items?.[idx]?.transport_per_item as string ) || 0; - - if (receivedQty > 0 && transportPerItem >= 0) { - const calculatedTransportTotal = receivedQty * transportPerItem; - formik.setFieldValue( - `items.${idx}.transport_total`, - calculatedTransportTotal - ); - } - } - - if (field === 'transport_total') { - const receivedQty = - parseFloat(formik.values.items?.[idx]?.received_qty as string) || 0; - if (receivedQty > 0 && numValue >= 0) { - const calculatedTransportPerItem = numValue / receivedQty; - formik.setFieldValue( - `items.${idx}.transport_per_item`, - calculatedTransportPerItem - ); - } } }; @@ -657,37 +632,6 @@ const PurchaseOrderAcceptApprovalForm = ({ }} /> - - - handlePurchaseItemChange( - idx, - 'transport_total', - e.target.value - ) - } - onBlur={formik.handleBlur} - placeholder='Masukkan total transport' - allowNegative={false} - decimalScale={2} - thousandSeparator=',' - decimalSeparator='.' - inputPrefix={'Rp'} - isError={ - isRepeaterInputError(idx, 'transport_total').isError - } - errorMessage={ - isRepeaterInputError(idx, 'transport_total') - .errorMessage - } - className={{ - wrapper: 'min-w-40 md:min-w-52 lg:min-w-64', - }} - /> - ); })} diff --git a/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts b/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts index 96836bc6..c7da956d 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts +++ b/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts @@ -23,10 +23,12 @@ type PurchaseRequestStaffApprovalFormSchemaType = { }; type PurchaseRequestManagerApprovalFormSchemaType = { + action: 'APPROVED' | 'REJECTED'; notes: string | null; }; type PurchaseRequestAcceptApprovalFormSchemaType = { + action: 'APPROVED' | 'REJECTED'; notes: string | null; items: { purchase_item?: { @@ -45,7 +47,6 @@ type PurchaseRequestAcceptApprovalFormSchemaType = { expedition_vendor_id: number; received_qty: number | string; transport_per_item: number | string; - transport_total: number | string; }[]; }; @@ -83,7 +84,6 @@ export type PurchaseAcceptApprovalItemSchema = { expedition_vendor_id: number; received_qty: number | string; transport_per_item: number | string; - transport_total: number | string; }; export type PurchaseDeleteItemsSchema = { @@ -152,6 +152,10 @@ const PurchaseStaffApprovalItemObjectSchema: Yup.ObjectSchema = Yup.object({ + action: Yup.mixed<'APPROVED' | 'REJECTED'>() + .oneOf(['APPROVED', 'REJECTED'], 'Action harus APPROVED atau REJECTED') + .required('Action wajib diisi!') + .default('APPROVED'), notes: Yup.string().nullable().default(null), }); @@ -230,20 +234,6 @@ const PurchaseAcceptApprovalItemObjectSchema: Yup.ObjectSchema() - .required('Total biaya transport wajib diisi!') - .test( - 'is-valid-transport-total', - 'Total biaya transport harus berupa angka lebih dari atau sama dengan 0!', - function (value) { - if (value === '' || value === null || value === undefined) - return false; - const numValue = - typeof value === 'string' ? parseFloat(value) : value; - return !isNaN(numValue) && numValue >= 0; - } - ) - .typeError('Total biaya transport harus berupa angka!'), }); export const PurchaseRequestStaffApprovalFormSchema: Yup.ObjectSchema = @@ -368,6 +358,7 @@ export const PurchaseRequestManagerApprovalFormDefaultValues = ( purchase?: Purchase ): PurchaseRequestManagerApprovalFormSchemaType => { return { + action: 'APPROVED', notes: purchase?.notes ?? null, }; }; @@ -378,6 +369,10 @@ export type PurchaseRequestManagerApprovalFormValues = Yup.InferType< export const PurchaseRequestAcceptApprovalFormSchema: Yup.ObjectSchema = Yup.object({ + action: Yup.mixed<'APPROVED' | 'REJECTED'>() + .oneOf(['APPROVED', 'REJECTED'], 'Action harus APPROVED atau REJECTED') + .required('Action wajib diisi!') + .default('APPROVED'), notes: Yup.string().nullable().default(null), items: Yup.array() .of(PurchaseAcceptApprovalItemObjectSchema) @@ -388,6 +383,7 @@ export const PurchaseRequestAcceptApprovalFormSchema: Yup.ObjectSchema { return { + action: 'APPROVED', notes: purchase?.notes ?? null, items: purchase?.items ? purchase.items.map((item) => ({ @@ -419,7 +415,6 @@ export const PurchaseRequestAcceptApprovalFormDefaultValues = ( expedition_vendor_id: 0, received_qty: '', transport_per_item: '', - transport_total: '', })) : [ { @@ -431,7 +426,6 @@ export const PurchaseRequestAcceptApprovalFormDefaultValues = ( expedition_vendor_id: 0, received_qty: '', transport_per_item: '', - transport_total: '', }, ], }; diff --git a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx index 2f3bbfb0..194e9534 100644 --- a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx +++ b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx @@ -925,6 +925,7 @@ const PurchaseOrderDetail = ({ color: 'success', onClick: async (notes) => { const payload: CreateManagerApprovalRequestPayload = { + action: 'APPROVED', notes: notes || null, }; diff --git a/src/types/api/purchase/purchase.d.ts b/src/types/api/purchase/purchase.d.ts index 56cbd810..d075f6fe 100644 --- a/src/types/api/purchase/purchase.d.ts +++ b/src/types/api/purchase/purchase.d.ts @@ -42,7 +42,6 @@ export type PurchaseItem = { expedition_vendor_name?: string | null; received_qty?: number | null; transport_per_item?: number | null; - transport_total?: number | null; }; export type BasePurchase = { @@ -103,10 +102,12 @@ export type UpdateStaffApprovalRequestPayload = { }; export type CreateManagerApprovalRequestPayload = { + action: 'APPROVED' | 'REJECTED'; notes?: string | null; }; export type CreateAcceptApprovalRequestPayload = { + action: 'APPROVED' | 'REJECTED'; notes?: string; items: { purchase_item_id: number; @@ -117,7 +118,6 @@ export type CreateAcceptApprovalRequestPayload = { expedition_vendor_id: number; received_qty: number; transport_per_item: number; - transport_total: number; }[]; }; From f5663b82aae925b8b6e7225a28b3729a7fb5e335 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 8 Dec 2025 14:43:53 +0700 Subject: [PATCH 02/11] refactor(ci): clean up .gitlab-ci.yml by removing unnecessary whitespace --- .gitlab-ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 91da62b9..c37bfd35 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -140,7 +140,6 @@ deploy:dev: environment: name: development url: https://dev-lti-erp.mbugroup.id - # ====== PRODUCTION ====== # build:production: # <<: *build_template @@ -163,4 +162,3 @@ deploy:dev: # environment: # name: production - From 68874a1c14afb00dbef269b7e170edfc184a1ead Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 8 Dec 2025 17:42:23 +0700 Subject: [PATCH 03/11] feat(FE-311): Use latest_approval for purchase approvals --- .../purchase/order/PurchaseOrderDetail.tsx | 26 +++++++++---------- src/types/api/purchase/purchase.d.ts | 1 + 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx index 194e9534..c2310e42 100644 --- a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx +++ b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx @@ -156,9 +156,9 @@ const PurchaseOrderDetail = ({ }, [goodsReceiptItems]); const approvalStep = useMemo(() => { - if (!initialValues?.approval) return null; - return initialValues.approval.step_number; - }, [initialValues?.approval]); + if (!initialValues?.latest_approval) return null; + return initialValues.latest_approval.step_number; + }, [initialValues?.latest_approval]); const { approvals, @@ -166,7 +166,7 @@ const PurchaseOrderDetail = ({ rawDataApprovals, refresh: refreshApprovals, } = useApprovalSteps({ - latestApproval: initialValues?.approval, + latestApproval: initialValues?.latest_approval, approvalLines: PURCHASE_ORDER_APPROVAL_LINE, moduleName: 'PURCHASES', moduleId: initialValues?.id?.toString() ?? '', @@ -180,16 +180,16 @@ const PurchaseOrderDetail = ({ approvalStep !== null && approvalStep >= 1 && approvalStep <= 3; const canDeleteItems = useMemo(() => { - if (!initialValues?.approval) return false; + if (!initialValues?.latest_approval) return false; - const currentStep = initialValues.approval.step_number; + const currentStep = initialValues.latest_approval.step_number; const hasReachedStep5 = rawDataApprovals?.some( (approval) => approval.step_number === 5 ); return currentStep === 3 && !hasReachedStep5; - }, [initialValues?.approval, rawDataApprovals]); + }, [initialValues?.latest_approval, rawDataApprovals]); const handleApprovalClick = () => { if (!approvalStep) return; @@ -222,18 +222,18 @@ const PurchaseOrderDetail = ({ }; const canShowPurchaseOrderInvoice = useMemo(() => { - if (!initialValues?.approval) return false; + if (!initialValues?.latest_approval) return false; - const currentStep = initialValues.approval.step_number; + const currentStep = initialValues.latest_approval.step_number; return currentStep >= 3; - }, [initialValues?.approval]); + }, [initialValues?.latest_approval]); const canShowPenerimaanBarang = useMemo(() => { - if (!initialValues?.approval) return false; + if (!initialValues?.latest_approval) return false; - const currentStep = initialValues.approval.step_number; + const currentStep = initialValues.latest_approval.step_number; return currentStep === 5; - }, [initialValues?.approval]); + }, [initialValues?.latest_approval]); const totalBeforeTax = useMemo(() => { return purchaseOrderItems.reduce( diff --git a/src/types/api/purchase/purchase.d.ts b/src/types/api/purchase/purchase.d.ts index d075f6fe..94611eff 100644 --- a/src/types/api/purchase/purchase.d.ts +++ b/src/types/api/purchase/purchase.d.ts @@ -62,6 +62,7 @@ export type BasePurchase = { warehouse?: Warehouse; items?: PurchaseItem[]; approval?: BaseApproval; + latest_approval?: BaseApproval; }; export type Purchase = BaseMetadata & BasePurchase; From c7911f01f2f61c3fa8f50c9bbd0e43fd16f64b1d Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 8 Dec 2025 17:43:44 +0700 Subject: [PATCH 04/11] refactor(FE-311): Remove Total Transport header from approval form --- .../purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx b/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx index 0a10b1cd..d610acfe 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx +++ b/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx @@ -361,10 +361,6 @@ const PurchaseOrderAcceptApprovalForm = ({ Transport/Item * - - Total Transport - * - From ce75eb25d753a6836304f0341727ef23382931f0 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 8 Dec 2025 17:55:22 +0700 Subject: [PATCH 05/11] refactor(FE-311): Show previous values only in edit mode --- .../order/PurchaseOrderStaffApprovalForm.tsx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx b/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx index 791e2592..f0519381 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx +++ b/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx @@ -719,7 +719,10 @@ const PurchaseOrderStaffApprovalForm = ({ 'min-w-52 md:min-w-72 lg:min-w-80', }} bottomLabel={ - 'Previous: ' + purchaseItem.product.name + type === 'edit' + ? 'Previous: ' + + purchaseItem.product.name + : undefined } /> @@ -819,7 +822,11 @@ const PurchaseOrderStaffApprovalForm = ({ thousandSeparator=',' decimalSeparator='.' inputPrefix={'Rp'} - bottomLabel={`Previous: Rp${formatNumber(initialValues?.items?.find((item) => item.id === purchaseItem.id)?.price || 0, 'id-ID', 2, 2)}`} + bottomLabel={ + type === 'edit' + ? `Previous: Rp${formatNumber(initialValues?.items?.find((item) => item.id === purchaseItem.id)?.price || 0, 'id-ID', 2, 2)}` + : undefined + } isError={ isRepeaterInputError( formItemIndex, @@ -857,7 +864,11 @@ const PurchaseOrderStaffApprovalForm = ({ thousandSeparator=',' decimalSeparator='.' inputPrefix={'Rp'} - bottomLabel={`Previous: Rp${formatNumber(initialValues?.items?.find((item) => item.id === purchaseItem.id)?.total_price || 0, 'id-ID', 2, 2)}`} + bottomLabel={ + type === 'edit' + ? `Previous: Rp${formatNumber(initialValues?.items?.find((item) => item.id === purchaseItem.id)?.total_price || 0, 'id-ID', 2, 2)}` + : undefined + } isError={ isRepeaterInputError( formItemIndex, From a7d884b5f007e4d4ff29259ead7100cd79049fa3 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 8 Dec 2025 18:14:38 +0700 Subject: [PATCH 06/11] refactor(FE-311): Use latest_approval instead of approval --- .../order/PurchaseOrderStaffApprovalForm.tsx | 16 ++++++++-------- src/types/api/purchase/purchase.d.ts | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx b/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx index f0519381..bc718eb6 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx +++ b/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx @@ -61,7 +61,7 @@ const PurchaseOrderStaffApprovalForm = ({ return 'add'; } - const currentStep = initialValues?.approval?.step_number || 1; + const currentStep = initialValues?.latest_approval?.step_number || 1; switch (currentStep) { case 1: @@ -77,7 +77,7 @@ const PurchaseOrderStaffApprovalForm = ({ // Step 4+ (Penerimaan Barang dan selesai), tidak boleh edit kalau sudah disetujui return 'edit'; } - }, [rawDataApprovals, propType, initialValues?.approval?.step_number]); + }, [rawDataApprovals, propType, initialValues?.latest_approval?.step_number]); const router = useRouter(); const searchParams = useSearchParams(); @@ -93,16 +93,16 @@ const PurchaseOrderStaffApprovalForm = ({ // ===== UTILITY FUNCTIONS ===== const canUpdatePurchaseItems = useMemo(() => { - if (!initialValues?.approval) return false; + if (!initialValues?.latest_approval) return false; - const currentStep = initialValues.approval.step_number; + const currentStep = initialValues.latest_approval.step_number; return currentStep >= 3; - }, [initialValues?.approval]); + }, [initialValues?.latest_approval]); const canShowDeleteAddButtons = useMemo(() => { - if (!initialValues?.approval) return false; + if (!initialValues?.latest_approval) return false; - const currentStep = initialValues.approval.step_number; + const currentStep = initialValues.latest_approval.step_number; // Step 2 (Staff Purchase) dengan mode 'add' tidak boleh add/delete items // User hanya boleh input harga dan total harga untuk items yang sudah ada @@ -112,7 +112,7 @@ const PurchaseOrderStaffApprovalForm = ({ // Step 3 (Manager Purchase) boleh add/delete items return currentStep === 3; - }, [initialValues?.approval, type]); + }, [initialValues?.latest_approval, type]); const isRepeaterInputError = ( idx: number, diff --git a/src/types/api/purchase/purchase.d.ts b/src/types/api/purchase/purchase.d.ts index 94611eff..93d6e610 100644 --- a/src/types/api/purchase/purchase.d.ts +++ b/src/types/api/purchase/purchase.d.ts @@ -61,7 +61,6 @@ export type BasePurchase = { location?: Location; warehouse?: Warehouse; items?: PurchaseItem[]; - approval?: BaseApproval; latest_approval?: BaseApproval; }; From 512ad5175eb9d981d1400c74a10e7a19615754ff Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 8 Dec 2025 18:37:58 +0700 Subject: [PATCH 07/11] refactor(FE-311): Default received_qty and remove transport_total --- .../purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx | 2 +- src/components/pages/purchase/order/PurchaseOrderDetail.tsx | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx b/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx index d610acfe..ab2b373a 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx +++ b/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx @@ -235,7 +235,7 @@ const PurchaseOrderAcceptApprovalForm = ({ vehicle_number: item.vehicle_number || '', expedition_vendor: null, expedition_vendor_id: 0, - received_qty: '', + received_qty: item.total_qty || '', transport_per_item: '', }; }); diff --git a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx index c2310e42..2ca16480 100644 --- a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx +++ b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx @@ -544,11 +544,6 @@ const PurchaseOrderDetail = ({ accessorKey: 'transport_per_item', cell: (props) => formatCurrency(props.getValue() as number), }, - { - header: 'Transport Total', - accessorKey: 'transport_total', - cell: (props) => formatCurrency(props.getValue() as number), - }, ]; const summaryData = [ From a45de4fb131580d73be9725a83be50983129ed19 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Tue, 9 Dec 2025 09:58:15 +0700 Subject: [PATCH 08/11] refactor(FE-311): Remove grand_total and due_date from purchases --- .../pages/purchase/PurchaseTable.tsx | 15 +---------- .../purchase/order/PurchaseOrderDetail.tsx | 25 ++++++------------- src/types/api/purchase/purchase.d.ts | 3 +-- 3 files changed, 9 insertions(+), 34 deletions(-) diff --git a/src/components/pages/purchase/PurchaseTable.tsx b/src/components/pages/purchase/PurchaseTable.tsx index bf59d5ee..a77e1158 100644 --- a/src/components/pages/purchase/PurchaseTable.tsx +++ b/src/components/pages/purchase/PurchaseTable.tsx @@ -16,7 +16,7 @@ import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; -import { cn, formatDate, formatCurrency } from '@/lib/helper'; +import { cn, formatDate } from '@/lib/helper'; import { isResponseSuccess } from '@/lib/api-helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; @@ -136,14 +136,6 @@ const PurchaseTable = () => { ? formatDate(props.row.original.po_date, 'DD MMM YYYY') : '-', }, - { - accessorKey: 'due_date', - header: 'Jatuh Tempo', - cell: (props) => - props.row.original.due_date - ? formatDate(props.row.original.due_date, 'DD MMM YYYY') - : '-', - }, { header: 'Aging', cell: (props) => { @@ -156,11 +148,6 @@ const PurchaseTable = () => { return `${diffDays} hari`; }, }, - { - accessorKey: 'grand_total', - header: 'Total (Rp.)', - cell: (props) => formatCurrency(props.row.original.grand_total), - }, { header: 'Aksi', cell: (props) => { diff --git a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx index 2ca16480..cf7805fb 100644 --- a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx +++ b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx @@ -642,7 +642,7 @@ const PurchaseOrderDetail = ({
- + Area @@ -652,7 +652,7 @@ const PurchaseOrderDetail = ({
- + Lokasi @@ -666,7 +666,7 @@ const PurchaseOrderDetail = ({
- + Gudang @@ -680,7 +680,7 @@ const PurchaseOrderDetail = ({
- + Nama Vendor @@ -691,7 +691,7 @@ const PurchaseOrderDetail = ({
- + Kategori Vendor @@ -701,18 +701,7 @@ const PurchaseOrderDetail = ({
- - Tgl. Jatuh Tempo - - - : {formatDate(purchaseData.due_date, 'D MMM YYYY')} ( - {purchaseData.credit_term} hari) - -
-
-
-
- + Nomor @@ -722,7 +711,7 @@ const PurchaseOrderDetail = ({
- + Nomor PO
diff --git a/src/types/api/purchase/purchase.d.ts b/src/types/api/purchase/purchase.d.ts index 93d6e610..50221bfa 100644 --- a/src/types/api/purchase/purchase.d.ts +++ b/src/types/api/purchase/purchase.d.ts @@ -51,9 +51,8 @@ export type BasePurchase = { po_document_path?: string | null; po_date: string; supplier: Supplier; - credit_term: number; + credit_term?: number; due_date: string; - grand_total: number; notes?: string | null; deleted_at?: string | null; created_by: number; From 8e80d668fa178ceda849879ab67d334b5f4a186b Mon Sep 17 00:00:00 2001 From: rstubryan Date: Tue, 9 Dec 2025 10:13:48 +0700 Subject: [PATCH 09/11] refactor(FE-311): Remove credit_term from purchase request data and UI --- .../request/PurchaseRequestForm.schema.ts | 6 -- .../form/request/PurchaseRequestForm.tsx | 79 +------------------ .../purchase/order/PurchaseOrderInvoice.tsx | 3 - src/types/api/purchase/purchase.d.ts | 2 - 4 files changed, 2 insertions(+), 88 deletions(-) diff --git a/src/components/pages/purchase/form/request/PurchaseRequestForm.schema.ts b/src/components/pages/purchase/form/request/PurchaseRequestForm.schema.ts index 414371c3..05167715 100644 --- a/src/components/pages/purchase/form/request/PurchaseRequestForm.schema.ts +++ b/src/components/pages/purchase/form/request/PurchaseRequestForm.schema.ts @@ -7,7 +7,6 @@ type PurchaseRequestFormSchemaType = { label: string; } | null; supplier_id: number; - credit_term: number; area?: { value: number; label: string; @@ -78,10 +77,6 @@ export const PurchaseRequestFormSchema: Yup.ObjectSchema ({ warehouse_id: Number(item.warehouse_id) || 0, @@ -342,27 +338,6 @@ const PurchaseRequestForm = ({ }; // ===== 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(() => { if (formik.values.items) { formik.values.items.forEach((_, idx) => { @@ -377,16 +352,6 @@ const PurchaseRequestForm = ({ }, []); // ===== 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 ===== const handleSupplierChange = useCallback( @@ -402,23 +367,6 @@ const PurchaseRequestForm = ({ [] ); - const handleCreditTermChange = useCallback( - (e: React.ChangeEvent) => { - const value = e.target.value; - - formik.setFieldTouched('credit_term', true); - formik.setFieldValue('credit_term', value); - }, - [] - ); - - const handleCreditTermBlur = useCallback( - (e: React.FocusEvent) => { - formik.handleBlur(e); - }, - [formik] - ); - const handleAreaChange = useCallback( (val: OptionType | OptionType[] | null) => { const area = val as OptionType | null; @@ -499,7 +447,7 @@ const PurchaseRequestForm = ({ body: 'flex flex-col gap-6', }} > -
+
- - -
+
{ {purchaseData?.supplier?.alias || ''}) {purchaseData?.supplier?.category || '-'} - - Credit Term: {purchaseData?.credit_term || 0} hari - Due Date:{' '} {purchaseData?.due_date diff --git a/src/types/api/purchase/purchase.d.ts b/src/types/api/purchase/purchase.d.ts index 50221bfa..e596187a 100644 --- a/src/types/api/purchase/purchase.d.ts +++ b/src/types/api/purchase/purchase.d.ts @@ -51,7 +51,6 @@ export type BasePurchase = { po_document_path?: string | null; po_date: string; supplier: Supplier; - credit_term?: number; due_date: string; notes?: string | null; deleted_at?: string | null; @@ -67,7 +66,6 @@ export type Purchase = BaseMetadata & BasePurchase; export type CreatePurchaseRequestPayload = { supplier_id: number; - credit_term: number; notes?: string | null; items: { warehouse_id: number; From 429f5ffb629e36ceb44c02f5f01f092a2f400a1d Mon Sep 17 00:00:00 2001 From: rstubryan Date: Wed, 10 Dec 2025 13:30:40 +0700 Subject: [PATCH 10/11] feat(FE-311): Add rejection modals and accept handler --- .../purchase/order/PurchaseOrderDetail.tsx | 91 +++++++++++++++++++ src/types/api/purchase/purchase.d.ts | 2 +- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx index cf7805fb..eb01aec7 100644 --- a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx +++ b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx @@ -27,6 +27,7 @@ import PurchaseOrderInvoice from '@/components/pages/purchase/order/PurchaseOrde import Card from '@/components/Card'; import { + CreateAcceptApprovalRequestPayload, CreateManagerApprovalRequestPayload, CreateStaffApprovalRequestPayload, Purchase, @@ -88,6 +89,8 @@ const PurchaseOrderDetail = ({ const staffApprovalModal = useModal(); const staffRejectionModal = useModal(); const acceptApprovalModal = useModal(); + const acceptRejectionModal = useModal(); + const managerRejectionModal = useModal(); const editModal = useModal(); const penerimaanBarangModal = useModal(); const deleteModal = useModal(); @@ -216,6 +219,12 @@ const PurchaseOrderDetail = ({ case 1: staffRejectionModal.openModal(); break; + case 2: + managerRejectionModal.openModal(); + break; + case 3: + acceptRejectionModal.openModal(); + break; default: break; } @@ -296,6 +305,33 @@ const PurchaseOrderDetail = ({ [initialValues?.id, searchParams, refetchData] ); + const createAcceptApprovalHandler = useCallback( + async (payload: CreateAcceptApprovalRequestPayload) => { + const purchaseRequestId = searchParams.get('purchaseId') + ? parseInt(searchParams.get('purchaseId')!) + : initialValues?.id || 1; + + if (!purchaseRequestId) { + toast.error('Purchase Request ID is required'); + return; + } + + const res = await PurchaseApi.acceptApproval.create( + purchaseRequestId, + payload + ); + + if (isResponseError(res)) { + toast.error(res.message); + return; + } + toast.success(res?.message as string); + refreshApprovals(); + refetchData?.(); + }, + [initialValues?.id, searchParams, refreshApprovals, refetchData] + ); + // ===== MODAL HANDLERS ===== const handleStaffApprovalModalClose = useCallback(() => { refreshApprovals(); @@ -1026,6 +1062,61 @@ const PurchaseOrderDetail = ({ }} /> + {/* Accept Rejection Modal */} + { + const payload: CreateAcceptApprovalRequestPayload = { + action: 'REJECTED', + notes: notes || null, + items: [], + }; + + await createAcceptApprovalHandler(payload); + await refetchData?.(); + acceptRejectionModal.closeModal(); + }, + }} + secondaryButton={{ + text: 'Batal', + }} + /> + + {/* Manager Rejection Modal */} + { + const payload: CreateManagerApprovalRequestPayload = { + action: 'REJECTED', + notes: notes || null, + }; + + await createManagerApprovalHandler(payload); + await refetchData?.(); + managerRejectionModal.closeModal(); + }, + }} + secondaryButton={{ + text: 'Batal', + }} + /> + {/* Delete Confirmation Modal */} Date: Wed, 10 Dec 2025 13:56:13 +0700 Subject: [PATCH 11/11] feat(FE-311): Disable approval actions when rejected --- .../purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx | 5 ++++- .../purchase/form/order/PurchaseOrderStaffApprovalForm.tsx | 4 +++- src/components/pages/purchase/order/PurchaseOrderDetail.tsx | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx b/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx index ab2b373a..15106c5e 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx +++ b/src/components/pages/purchase/form/order/PurchaseOrderAcceptApprovalForm.tsx @@ -52,6 +52,8 @@ const PurchaseOrderAcceptApprovalForm = ({ const [purchaseOrderFormErrorMessage, setPurchaseOrderFormErrorMessage] = useState(''); + const isRejected = initialValues?.latest_approval?.action === 'REJECTED'; + // ===== UTILITY FUNCTIONS ===== const isRepeaterInputError = ( idx: number, @@ -672,7 +674,8 @@ const PurchaseOrderAcceptApprovalForm = ({ disabled={ !formik.isValid || formik.isSubmitting || - hasQuantityExceededErrors + hasQuantityExceededErrors || + isRejected } > Submit diff --git a/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx b/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx index bc718eb6..94998a37 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx +++ b/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx @@ -79,6 +79,8 @@ const PurchaseOrderStaffApprovalForm = ({ } }, [rawDataApprovals, propType, initialValues?.latest_approval?.step_number]); + const isRejected = initialValues?.latest_approval?.action === 'REJECTED'; + const router = useRouter(); const searchParams = useSearchParams(); const deleteModal = useModal(); @@ -1142,7 +1144,7 @@ const PurchaseOrderStaffApprovalForm = ({ color='primary' className='px-4' isLoading={formik.isSubmitting} - disabled={!formik.isValid || formik.isSubmitting} + disabled={!formik.isValid || formik.isSubmitting || isRejected} > Submit diff --git a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx index eb01aec7..859c6671 100644 --- a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx +++ b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx @@ -180,7 +180,10 @@ const PurchaseOrderDetail = ({ }); const showApprovalButton = - approvalStep !== null && approvalStep >= 1 && approvalStep <= 3; + approvalStep !== null && + approvalStep >= 1 && + approvalStep <= 3 && + initialValues?.latest_approval?.action !== 'REJECTED'; const canDeleteItems = useMemo(() => { if (!initialValues?.latest_approval) return false;