From 9f079c1e520006ad2f82e8b251840351254f815e Mon Sep 17 00:00:00 2001 From: kris Date: Wed, 31 Dec 2025 07:26:27 +0000 Subject: [PATCH 1/9] Update .gitlab-ci.yml file --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 46730fed..e24a8521 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -114,7 +114,7 @@ stages: curl -sS -H "Content-Type: application/json" -d @payload.json "$DISCORD_WEBHOOK_URL" -# ===== DEVELOPMENT (Branch development) ====== +# ==== DEVELOPMENT (Branch development) ====== build:dev: <<: *build_template rules: From 02c5cddc94b9d360398893cfc37683871780e56d Mon Sep 17 00:00:00 2001 From: kris Date: Wed, 31 Dec 2025 07:32:33 +0000 Subject: [PATCH 2/9] Update .gitlab-ci.yml file --- .gitlab-ci.yml | 99 ++++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e24a8521..ec449d5c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,27 +2,47 @@ stages: - build - deploy +# ========================================================== +# ✅ Global defaults +# ========================================================== +default: + tags: + - self-hosted + interruptible: true + +# ========================================================== +# 🏗️ Build Template +# ========================================================== .build_template: &build_template stage: build image: node:20-alpine cache: key: npm-cache paths: - - node_modules/ + - .npm/ variables: - NPM_CONFIG_PRODUCTION: 'false' - NODE_ENV: '' + NPM_CONFIG_PRODUCTION: "false" + NODE_ENV: "" + NPM_CONFIG_CACHE: "$CI_PROJECT_DIR/.npm" script: - echo "Installing dependencies..." - npm ci --no-audit --no-fund + - echo "Build env used:" - echo "NEXT_PUBLIC_LTI_URL=$NEXT_PUBLIC_LTI_URL" - echo "NEXT_PUBLIC_SSO_LOGIN_URL=$NEXT_PUBLIC_SSO_LOGIN_URL" - echo "NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL" - - echo "Building Next.js static export..." + + # Build + export (untuk static hosting di S3) + - echo "Building Next.js..." - npx next build + + # Kalau project kamu pakai static export: + - echo "Exporting static site..." + - npx next export + + # Build metadata - | - mkdir -p out cat < out/build-info.json { "commit": "$CI_COMMIT_SHORT_SHA", @@ -34,11 +54,14 @@ stages: } EOF artifacts: - name: 'out-$CI_COMMIT_SHORT_SHA' + name: "out-$CI_COMMIT_SHORT_SHA" paths: - out/ expire_in: 1 week +# ========================================================== +# 🚀 Deploy Template +# ========================================================== .deploy_template: &deploy_template stage: deploy image: @@ -82,11 +105,11 @@ stages: if [ "$STATUS" = "success" ]; then COLOR=3066993 TITLE="✅ Deployment ${ENVIRONMENT_NAME} Succeeded" - DESC="Deployment job on branch \`${CI_COMMIT_REF_NAME}\` completed successfully." + DESC="Deployment job on branch \${CI_COMMIT_REF_NAME}\ completed successfully." else COLOR=15158332 TITLE="❌ Deployment ${ENVIRONMENT_NAME} Failed" - DESC="Deployment job on branch \`${CI_COMMIT_REF_NAME}\` encountered issues." + DESC="Deployment job on branch \${CI_COMMIT_REF_NAME}\ encountered issues." fi jq -n \ @@ -114,7 +137,9 @@ stages: curl -sS -H "Content-Type: application/json" -d @payload.json "$DISCORD_WEBHOOK_URL" +# ========================================================== # ==== DEVELOPMENT (Branch development) ====== +# ========================================================== build:dev: <<: *build_template rules: @@ -122,25 +147,27 @@ build:dev: environment: name: development variables: - NEXT_PUBLIC_LTI_URL: 'https://dev-lti-erp.mbugroup.id' - NEXT_PUBLIC_SSO_LOGIN_URL: 'https://dev-auth-erp.mbugroup.id' - NEXT_PUBLIC_API_BASE_URL: 'https://dev-api-lti.mbugroup.id/api' - NEXT_PUBLIC_CLIENT_ID: 'Lumbung-Telur-Indonesia' + NEXT_PUBLIC_LTI_URL: "https://dev-lti-erp.mbugroup.id" + NEXT_PUBLIC_SSO_LOGIN_URL: "https://dev-auth-erp.mbugroup.id" + NEXT_PUBLIC_API_BASE_URL: "https://dev-api-lti.mbugroup.id/api" + NEXT_PUBLIC_CLIENT_ID: "Lumbung-Telur-Indonesia" deploy:dev: <<: *deploy_template - needs: ['build:dev'] + needs: ["build:dev"] rules: - if: '$CI_COMMIT_BRANCH == "development"' variables: - S3_BUCKET: 'dev-lti-erp.mbugroup.id' - AWS_REGION: 'ap-southeast-3' - CLOUDFRONT_DISTRIBUTION_ID: 'E1Z8XTA8XF1GIV' + S3_BUCKET: "dev-lti-erp.mbugroup.id" + AWS_REGION: "ap-southeast-3" + CLOUDFRONT_DISTRIBUTION_ID: "E1Z8XTA8XF1GIV" environment: name: development url: https://dev-lti-erp.mbugroup.id +# ========================================================== # ====== STAGING (Branch staging) ====== +# ========================================================== build:staging: <<: *build_template rules: @@ -148,42 +175,20 @@ build:staging: environment: name: staging variables: - NEXT_PUBLIC_LTI_URL: 'https://stg-lti-erp.mbugroup.id' - NEXT_PUBLIC_SSO_LOGIN_URL: 'https://stg-auth-erp.mbugroup.id' - NEXT_PUBLIC_API_BASE_URL: 'https://stg-api-lti.mbugroup.id/api' - NEXT_PUBLIC_CLIENT_ID: 'Lumbung-Telur-Indonesia' + NEXT_PUBLIC_LTI_URL: "https://stg-lti-erp.mbugroup.id" + NEXT_PUBLIC_SSO_LOGIN_URL: "https://stg-auth-erp.mbugroup.id" + NEXT_PUBLIC_API_BASE_URL: "https://stg-api-lti.mbugroup.id/api" + NEXT_PUBLIC_CLIENT_ID: "Lumbung-Telur-Indonesia" deploy:staging: <<: *deploy_template - needs: ['build:staging'] + needs: ["build:staging"] rules: - if: '$CI_COMMIT_BRANCH == "staging"' variables: - S3_BUCKET: 'stg-lti-erp.mbugroup.id' - AWS_REGION: 'ap-southeast-3' - CLOUDFRONT_DISTRIBUTION_ID: 'E2V6PPO1AUIU7H' + S3_BUCKET: "stg-lti-erp.mbugroup.id" + AWS_REGION: "ap-southeast-3" + CLOUDFRONT_DISTRIBUTION_ID: "E2V6PPO1AUIU7H" environment: name: staging - url: https://stg-lti-erp.mbugroup.id -# ====== PRODUCTION ====== -# build:production: -# <<: *build_template -# rules: -# # pilih salah satu: pakai branch master ATAU pakai tags rilis -# - if: '$CI_COMMIT_BRANCH == "master"' -# # - if: '$CI_COMMIT_TAG' # kalau mau rilis via tag, uncomment ini dan hapus baris di atas -# environment: -# name: production - -# deploy:production: -# <<: *deploy_template -# needs: ["build:production"] -# rules: -# - if: '$CI_COMMIT_BRANCH == "master"' -# # - if: '$CI_COMMIT_TAG' # selaras dengan rule di build:production -# variables: -# S3_BUCKET: "lti-erp.mbugroup.id" -# CLOUDFRONT_DISTRIBUTION_ID: "ddfd" -# environment: -# name: production - + url: https://stg-lti-erp.mbugroup.id \ No newline at end of file From 00f09364b1f0bde2e4a5a930baef68691551e529 Mon Sep 17 00:00:00 2001 From: kris Date: Wed, 31 Dec 2025 07:44:43 +0000 Subject: [PATCH 3/9] Update .gitlab-ci.yml file --- .gitlab-ci.yml | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ec449d5c..2f4b1587 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,30 +19,21 @@ default: cache: key: npm-cache paths: - - .npm/ + - node_modules/ variables: - NPM_CONFIG_PRODUCTION: "false" - NODE_ENV: "" - NPM_CONFIG_CACHE: "$CI_PROJECT_DIR/.npm" + NPM_CONFIG_PRODUCTION: 'false' + NODE_ENV: '' script: - echo "Installing dependencies..." - npm ci --no-audit --no-fund - - echo "Build env used:" - echo "NEXT_PUBLIC_LTI_URL=$NEXT_PUBLIC_LTI_URL" - echo "NEXT_PUBLIC_SSO_LOGIN_URL=$NEXT_PUBLIC_SSO_LOGIN_URL" - echo "NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL" - - # Build + export (untuk static hosting di S3) - - echo "Building Next.js..." + - echo "Building Next.js static export..." - npx next build - - # Kalau project kamu pakai static export: - - echo "Exporting static site..." - - npx next export - - # Build metadata - | + mkdir -p out cat < out/build-info.json { "commit": "$CI_COMMIT_SHORT_SHA", @@ -54,7 +45,7 @@ default: } EOF artifacts: - name: "out-$CI_COMMIT_SHORT_SHA" + name: 'out-$CI_COMMIT_SHORT_SHA' paths: - out/ expire_in: 1 week From 046fb74caba33d0a0db29f4f5908229d5a9f5092 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Wed, 31 Dec 2025 15:18:17 +0700 Subject: [PATCH 4/9] fix(FE-284): adjust data types for sapronak calculation --- .../ClosingSapronakCalculationTable.tsx | 105 ++++++++++++------ src/types/api/closing.d.ts | 33 +++--- 2 files changed, 85 insertions(+), 53 deletions(-) diff --git a/src/components/pages/closing/ClosingSapronakCalculationTable.tsx b/src/components/pages/closing/ClosingSapronakCalculationTable.tsx index 1ec3c971..22b4d2e2 100644 --- a/src/components/pages/closing/ClosingSapronakCalculationTable.tsx +++ b/src/components/pages/closing/ClosingSapronakCalculationTable.tsx @@ -37,88 +37,88 @@ const ClosingSapronakCalculationTable = ({ ): ColumnDef[] => [ { header: 'Tanggal', - accessorKey: 'tanggal', + accessorKey: 'date', cell: (props) => - props.row.original.tanggal - ? formatDate(props.row.original.tanggal, 'DD MMM YYYY') + props.row.original.date + ? formatDate(props.row.original.date, 'DD MMM YYYY') : '-', footer: 'Total', }, { header: 'No. Referensi', - accessorKey: 'no_referensi', - cell: (props) => (props.row.original.no_referensi as string) || '-', + accessorKey: 'reference_number', + cell: (props) => (props.row.original.reference_number as string) || '-', footer: '', }, { header: 'QTY Masuk', - accessorKey: 'qty_masuk', + accessorKey: 'qty_in', cell: (props) => - props.row.original.qty_masuk - ? formatNumber(props.row.original.qty_masuk as number) + props.row.original.qty_in + ? formatNumber(props.row.original.qty_in as number) : '-', footer: total ? () => (
- {total?.qty_masuk ? formatNumber(total?.qty_masuk) : '-'} + {total?.qty_in ? formatNumber(total?.qty_in) : '-'}
) : '', }, { header: 'QTY Keluar', - accessorKey: 'qty_keluar', + accessorKey: 'qty_out', cell: (props) => - props.row.original.qty_keluar - ? formatNumber(props.row.original.qty_keluar as number) + props.row.original.qty_out + ? formatNumber(props.row.original.qty_out as number) : '-', footer: total ? () => (
- {total?.qty_keluar ? formatNumber(total?.qty_keluar) : '-'} + {total?.qty_out ? formatNumber(total?.qty_out) : '-'}
) : '', }, { header: 'QTY Pakai', - accessorKey: 'qty_pakai', + accessorKey: 'qty_used', cell: (props) => - props.row.original.qty_pakai - ? formatNumber(props.row.original.qty_pakai as number) + props.row.original.qty_used + ? formatNumber(props.row.original.qty_used as number) : '-', footer: total ? () => (
- {total?.qty_pakai ? formatNumber(total?.qty_pakai) : '-'} + {total?.qty_used ? formatNumber(total?.qty_used) : '-'}
) : '', }, { header: 'Uraian', - accessorKey: 'uraian', - cell: (props) => (props.row.original.uraian as string) || '-', + accessorKey: 'description', + cell: (props) => (props.row.original.description as string) || '-', footer: '', }, { header: 'Kategori Produk', - accessorKey: 'kategori_produk', - cell: (props) => (props.row.original.kategori_produk as string) || '-', + accessorKey: 'product_category', + cell: (props) => (props.row.original.product_category as string) || '-', footer: '', }, { header: 'Harga Beli/Qty (Rp)', - accessorKey: 'harga_beli_per_qty', + accessorKey: 'unit_price', cell: (props) => - props.row.original.harga_beli_per_qty - ? formatCurrency(props.row.original.harga_beli_per_qty as number) + props.row.original.unit_price + ? formatCurrency(props.row.original.unit_price as number) : '-', footer: total ? () => (
- {total?.harga_beli_per_qty - ? formatCurrency(total?.harga_beli_per_qty) + {total?.avg_unit_price + ? formatCurrency(total?.avg_unit_price) : '-'}
) @@ -126,32 +126,32 @@ const ClosingSapronakCalculationTable = ({ }, { header: 'Total Harga (Rp)', - accessorKey: 'total_harga', + accessorKey: 'total_amount', cell: (props) => - props.row.original.total_harga - ? formatCurrency(props.row.original.total_harga as number) + props.row.original.total_amount + ? formatCurrency(props.row.original.total_amount as number) : '-', footer: total ? () => (
- {total?.total_harga ? formatCurrency(total?.total_harga) : '-'} + {total?.total_amount ? formatCurrency(total?.total_amount) : '-'}
) : '', }, { header: 'Keterangan', - accessorKey: 'keterangan', - cell: (props) => (props.row.original.keterangan as string) || '-', + accessorKey: 'notes', + cell: (props) => (props.row.original.notes as string) || '-', footer: '', }, ]; // Memoize columns untuk setiap kategori - const docBroilerColumns = useMemo( + const docColumns = useMemo( () => isResponseSuccess(sapronakCalculation) - ? createColumns(sapronakCalculation.data?.doc_broiler?.total) + ? createColumns(sapronakCalculation.data?.doc?.total) : createColumns(), [sapronakCalculation] ); @@ -172,10 +172,18 @@ const ClosingSapronakCalculationTable = ({ [sapronakCalculation] ); + const pulletColumns = useMemo( + () => + isResponseSuccess(sapronakCalculation) + ? createColumns(sapronakCalculation.data?.pullet?.total) + : createColumns(), + [sapronakCalculation] + ); + return (
data={ isResponseSuccess(sapronakCalculation) - ? (sapronakCalculation.data?.doc_broiler?.rows ?? []) + ? (sapronakCalculation.data?.doc?.rows ?? []) : [] } - columns={docBroilerColumns} + columns={docColumns} className={{ containerClassName: 'my-4', }} @@ -242,6 +250,29 @@ const ClosingSapronakCalculationTable = ({ renderFooter={isResponseSuccess(sapronakCalculation)} /> + + + + data={ + isResponseSuccess(sapronakCalculation) + ? (sapronakCalculation.data?.pullet?.rows ?? []) + : [] + } + columns={pulletColumns} + className={{ + containerClassName: 'my-4', + }} + renderFooter={isResponseSuccess(sapronakCalculation)} + /> +
); }; diff --git a/src/types/api/closing.d.ts b/src/types/api/closing.d.ts index ecdaebb9..f96f1149 100644 --- a/src/types/api/closing.d.ts +++ b/src/types/api/closing.d.ts @@ -147,25 +147,25 @@ export type ClosingProductionData = { export type RowSapronakCalculation = { id: number; - tanggal: string; - no_referensi: string; - qty_masuk: number; - qty_keluar: number; - qty_pakai: number; - uraian: string; - kategori_produk: string; - harga_beli_per_qty: number; - total_harga: number; - keterangan: string; + date: string; + reference_number: string; + qty_in: number; + qty_out: number; + qty_used: number; + description: string; + product_category: string; + unit_price: number; + total_amount: number; + notes: string; }; export type TotalSapronakCalculation = { label: string; - qty_masuk: number; - qty_keluar: number; - qty_pakai: number; - harga_beli_per_qty: number; - total_harga: number; + qty_in: number; + qty_out: number; + qty_used: number; + avg_unit_price: number; + total_amount: number; }; export type ClosingSapronakCalculationItem = { @@ -174,9 +174,10 @@ export type ClosingSapronakCalculationItem = { }; export type ClosingSapronakCalculation = { - doc_broiler: ClosingSapronakCalculationItem; + doc: ClosingSapronakCalculationItem; ovk: ClosingSapronakCalculationItem; pakan: ClosingSapronakCalculationItem; + pullet: ClosingSapronakCalculationItem; }; // ====== OVERHEAD ====== From d6b8b1018301df698f35f5264015c6adf6c86715 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Fri, 2 Jan 2026 10:04:56 +0700 Subject: [PATCH 5/9] fix(FE): remove bypass permission and integrate table filter --- .../pages/marketing/MarketingTable.tsx | 238 ++++++++++-------- src/config/route-permission.ts | 49 +--- 2 files changed, 141 insertions(+), 146 deletions(-) diff --git a/src/components/pages/marketing/MarketingTable.tsx b/src/components/pages/marketing/MarketingTable.tsx index 0247fc75..36d54381 100644 --- a/src/components/pages/marketing/MarketingTable.tsx +++ b/src/components/pages/marketing/MarketingTable.tsx @@ -2,7 +2,10 @@ import Button from '@/components/Button'; import CheckboxInput from '@/components/input/CheckboxInput'; -import SelectInput, { OptionType } from '@/components/input/SelectInput'; +import SelectInput, { + OptionType, + useSelect, +} from '@/components/input/SelectInput'; import Modal, { useModal } from '@/components/Modal'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes'; @@ -28,6 +31,8 @@ import toast from 'react-hot-toast'; import useSWR from 'swr'; import RequirePermission from '@/components/helper/RequirePermission'; import { useAuth } from '@/services/hooks/useAuth'; +import { CustomerApi, ProductApi } from '@/services/api/master-data'; +import { MARKETING_APPROVAL_LINE } from '@/config/approval-line'; const RowsOptionsMenu = ({ type = 'dropdown', @@ -52,7 +57,7 @@ const RowsOptionsMenu = ({ )} >
- {/* + - */} - + {props.row.original.latest_approval.step_number != 1 && ( <> - {/* Deliver - */} - + )} {props.row.original.latest_approval.step_number != 3 && ( <> - {/* + - */} - + )} - {/* + - */} - +
); @@ -175,8 +133,6 @@ const RowsOptionsMenu = ({ const MarketingTable = () => { const [search, setSearch] = useState(''); - const [page, setPage] = useState(1); - const [pageSize, setPageSize] = useState(10); const [approveAction, setApproveAction] = useState<'APPROVED' | 'REJECTED'>( 'APPROVED' @@ -186,18 +142,64 @@ const MarketingTable = () => { const { permissionCheck } = useAuth(); const router = useRouter(); - - const { - data: marketing, - isLoading: isLoadingMarketing, - mutate: refreshMarketing, - } = useSWR(MarketingApi.basePath, MarketingApi.getAllFetcher); - const deleteModal = useModal(); const confirmationModal = useModal(); const productsModal = useModal(); const deliveryModal = useModal(); + const { + state: tableFilterState, + updateFilter, + setPage, + setPageSize, + toQueryString: getTableFilterToQueryString, + } = useTableFilter({ + initial: { + search: '', + product_ids: '', + status: '', + customer_id: '', + page: 1, + limit: 10, + }, + paramMap: { + page: 'page', + pageSize: 'limit', + product_ids: 'product_ids', + status: 'status', + customer_id: 'customer_id', + }, + }); + // ===== FETCH DATA ===== + const { + data: marketing, + isLoading: isLoadingMarketing, + mutate: refreshMarketing, + } = useSWR( + `${MarketingApi.basePath}${getTableFilterToQueryString()}`, + MarketingApi.getAllFetcher + ); + + // ===== OPTIONS ===== + const { + options: productsOptions, + isLoadingOptions: isLoadingProductsOptions, + } = useSelect(ProductApi.basePath, 'id', 'name', '', { + limit: 'limit', + }); + + const { + options: customersOptions, + isLoadingOptions: isLoadingCustomersOptions, + } = useSelect(CustomerApi.basePath, 'id', 'name', '', { + limit: 'limit', + }); + const statusOptions = MARKETING_APPROVAL_LINE.map((item) => ({ + value: item.step_number, + label: item.step_name, + })); + + // ===== HANDLER ===== const searchChangeHandler = useCallback( (e: React.ChangeEvent) => { setSearch(e.target.value); @@ -209,7 +211,8 @@ const MarketingTable = () => { (val: OptionType | OptionType[] | null) => { const newVal = val as OptionType; setPageSize(newVal.value as number); - setPage(1); + updateFilter('page', 1); + updateFilter('limit', newVal.value as number); }, [] ); @@ -314,20 +317,6 @@ const MarketingTable = () => { ); }; - const { - state: tableFilterState, - updateFilter, - toQueryString: getTableFilterToQueryString, - } = useTableFilter({ - initial: { - search: '', - }, - paramMap: { - page: 'page', - pageSize: 'limit', - }, - }); - const getRowCanSelect = (row: Row): boolean => { const approval = row.original.latest_approval; return approval?.step_number === 1 && approval?.action !== 'REJECTED'; @@ -353,7 +342,7 @@ const MarketingTable = () => { }} />
- {/* + - */} - + - {/* + - */} - +
{ label='Product' isClearable placeholder='Pilih product' - options={[]} + options={productsOptions} + isLoading={isLoadingProductsOptions} + value={ + tableFilterState.product_ids + ?.split(',') + .map((id) => + productsOptions.find( + (option) => option.value === Number(id) + ) + ) + .filter( + (option): option is { value: number; label: string } => + option !== undefined + ) ?? null + } + onChange={(value: OptionType | OptionType[] | null) => + updateFilter( + 'product_ids', + (value as OptionType[]) + ?.map((item: OptionType) => item.value.toString()) + .join(',') || '' + ) + } isMulti /> {/* select status */} @@ -414,14 +407,43 @@ const MarketingTable = () => { label='Status' isClearable placeholder='Pilih status' - options={[]} + options={statusOptions} + value={ + tableFilterState.status + ? statusOptions.find( + (option) => + option.value === Number(tableFilterState.status) + ) + : null + } + onChange={(value: OptionType | OptionType[] | null) => + updateFilter( + 'status', + (value as OptionType)?.value.toString() || '' + ) + } /> {/* select customer */} + option.value === Number(tableFilterState.customer_id) + ) + : null + } + onChange={(value: OptionType | OptionType[] | null) => + updateFilter( + 'customer_id', + (value as OptionType)?.value.toString() || '' + ) + } /> @@ -587,8 +609,8 @@ const MarketingTable = () => { }, }, ]} - pageSize={pageSize} - page={page} + pageSize={tableFilterState.pageSize} + page={tableFilterState.page} onPageChange={setPage} className={{ tableWrapperClassName: 'overflow-x-auto min-h-full!', diff --git a/src/config/route-permission.ts b/src/config/route-permission.ts index 7c7ab0ac..101dbb6d 100644 --- a/src/config/route-permission.ts +++ b/src/config/route-permission.ts @@ -3,7 +3,6 @@ export const ROUTE_PERMISSIONS: Record = { // Dashboard '/dashboard/': ['lti.dashboard.list'], - '/dashboard': ['lti.dashboard.list'], // Production // Production - Project Flock @@ -58,27 +57,14 @@ export const ROUTE_PERMISSIONS: Record = { '/purchase/detail/edit/': ['lti.purchase.update'], // Marketing - '/marketing/': ['lti.dashboard.list', 'lti.marketing.delivery_order.list'], - '/marketing/add/delivery-orders/': [ - 'lti.dashboard.list', - 'lti.marketing.delivery_order.create', - ], - '/marketing/add/sales-orders/': [ - 'lti.dashboard.list', - 'lti.marketing.sales_order.create', - ], - '/marketing/detail/': [ - 'lti.dashboard.list', - 'lti.marketing.delivery_order.detail', - ], + '/marketing/': ['lti.marketing.delivery_order.list'], + '/marketing/add/delivery-orders/': ['lti.marketing.delivery_order.create'], + '/marketing/add/sales-orders/': ['lti.marketing.sales_order.create'], + '/marketing/detail/': ['lti.marketing.delivery_order.detail'], '/marketing/detail/delivery-orders/edit/': [ - 'lti.dashboard.list', 'lti.marketing.delivery_order.update', ], - '/marketing/detail/sales-orders/edit/': [ - 'lti.dashboard.list', - 'lti.marketing.sales_order.update', - ], + '/marketing/detail/sales-orders/edit/': ['lti.marketing.sales_order.update'], // Expense '/expense/': ['lti.expense.list'], @@ -89,19 +75,12 @@ export const ROUTE_PERMISSIONS: Record = { '/expense/realization/edit/': ['lti.expense.update.realization'], // Finance - '/finance/': ['lti.dashboard.list', 'lti.finance.transaction.list'], - '/finance/detail/': ['lti.dashboard.list', 'lti.finance.transaction.detail'], - '/finance/add/': ['lti.dashboard.list', 'lti.finance.payments.create'], - '/finance/detail/edit/': [ - 'lti.dashboard.list', - 'lti.finance.payments.update', - ], - '/finance/add/initial-balance/': [ - 'lti.dashboard.list', - 'lti.finance.initial_balances.create', - ], + '/finance/': ['lti.finance.transaction.list'], + '/finance/detail/': ['lti.finance.transaction.detail'], + '/finance/add/': ['lti.finance.payments.create'], + '/finance/detail/edit/': ['lti.finance.payments.update'], + '/finance/add/initial-balance/': ['lti.finance.initial_balances.create'], '/finance/detail/edit/initial-balance/': [ - 'lti.dashboard.list', 'lti.finance.initial_balances.update', ], '/finance/add/injection/': ['lti.finance.injections.create'], @@ -203,20 +182,14 @@ export const ROUTE_PERMISSIONS: Record = { '/master-data/flock/detail/': ['lti.master.flocks.detail'], '/master-data/flock/detail/edit/': ['lti.master.flocks.update'], - '/master-data/production-standard/': [ - 'lti.dashboard.list', - 'lti.master.production_standards.list', - ], + '/master-data/production-standard/': ['lti.master.production_standards.list'], '/master-data/production-standard/add/': [ - 'lti.dashboard.list', 'lti.master.production_standards.create', ], '/master-data/production-standard/detail/': [ - 'lti.dashboard.list', 'lti.master.production_standards.detail', ], '/master-data/production-standard/detail/edit/': [ - 'lti.dashboard.list', 'lti.master.production_standards.update', ], }; From f23d369e027c87aeaeb46c9814d4b7d4ec776e64 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Fri, 2 Jan 2026 10:15:50 +0700 Subject: [PATCH 6/9] fix(FE): integrate search filter marketing --- src/components/pages/marketing/MarketingTable.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/pages/marketing/MarketingTable.tsx b/src/components/pages/marketing/MarketingTable.tsx index 36d54381..507819e3 100644 --- a/src/components/pages/marketing/MarketingTable.tsx +++ b/src/components/pages/marketing/MarketingTable.tsx @@ -187,7 +187,6 @@ const MarketingTable = () => { } = useSelect(ProductApi.basePath, 'id', 'name', '', { limit: 'limit', }); - const { options: customersOptions, isLoadingOptions: isLoadingCustomersOptions, @@ -203,7 +202,8 @@ const MarketingTable = () => { const searchChangeHandler = useCallback( (e: React.ChangeEvent) => { setSearch(e.target.value); - setPage(1); + updateFilter('page', 1); + updateFilter('search', e.target.value); }, [] ); @@ -734,6 +734,7 @@ const MarketingTable = () => { 'px-6 py-3 last:flex last:flex-row last:justify-end', paginationClassName: 'hidden', }} + isLoading={isLoadingMarketing} /> From b53c8b99a00d6b5d70557c1bab02251b6969b649 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Fri, 2 Jan 2026 12:40:07 +0700 Subject: [PATCH 7/9] chore: refresh user session when user first enter the web --- src/components/helper/RequireAuth.tsx | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/components/helper/RequireAuth.tsx b/src/components/helper/RequireAuth.tsx index aa7f81b2..a4c9f5e0 100644 --- a/src/components/helper/RequireAuth.tsx +++ b/src/components/helper/RequireAuth.tsx @@ -29,8 +29,8 @@ const RequireAuth = ({ children }: RequireAuthProps) => { >('/sso/userinfo', httpClientFetcher, { shouldRetryOnError: false, - // refresh every 13 minutes - refreshInterval: 13 * 60 * 1000, + // refresh every 12 minutes + refreshInterval: 12 * 60 * 1000, }); useEffect(() => { @@ -61,12 +61,20 @@ const RequireAuth = ({ children }: RequireAuthProps) => { async () => { await AuthApi.refresh(); }, - 13 * 60 * 1000 + 12 * 60 * 1000 ); return () => clearInterval(interval); }, []); + useEffect(() => { + const refreshUserSession = async () => { + await AuthApi.refresh(); + }; + + refreshUserSession(); + }, []); + if ( (isLoadingUserResponse && !userResponse && !userErrorResponse) || (!userResponse && !userErrorResponse) @@ -78,7 +86,7 @@ const RequireAuth = ({ children }: RequireAuthProps) => { ); } - if (userErrorResponse) { + if (!isLoadingUserResponse && userErrorResponse) { return (

Authentication Failed

@@ -86,10 +94,7 @@ const RequireAuth = ({ children }: RequireAuthProps) => { Please try refreshing the page or contact support if the problem persists.

-
From 045913d05fb8958abff064c4252515c026d5dc1c Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Fri, 2 Jan 2026 13:28:46 +0700 Subject: [PATCH 8/9] chore: lint --- .gitlab-ci.yml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2f4b1587..e02ea8ee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -138,20 +138,20 @@ build:dev: environment: name: development variables: - NEXT_PUBLIC_LTI_URL: "https://dev-lti-erp.mbugroup.id" - NEXT_PUBLIC_SSO_LOGIN_URL: "https://dev-auth-erp.mbugroup.id" - NEXT_PUBLIC_API_BASE_URL: "https://dev-api-lti.mbugroup.id/api" - NEXT_PUBLIC_CLIENT_ID: "Lumbung-Telur-Indonesia" + NEXT_PUBLIC_LTI_URL: 'https://dev-lti-erp.mbugroup.id' + NEXT_PUBLIC_SSO_LOGIN_URL: 'https://dev-auth-erp.mbugroup.id' + NEXT_PUBLIC_API_BASE_URL: 'https://dev-api-lti.mbugroup.id/api' + NEXT_PUBLIC_CLIENT_ID: 'Lumbung-Telur-Indonesia' deploy:dev: <<: *deploy_template - needs: ["build:dev"] + needs: ['build:dev'] rules: - if: '$CI_COMMIT_BRANCH == "development"' variables: - S3_BUCKET: "dev-lti-erp.mbugroup.id" - AWS_REGION: "ap-southeast-3" - CLOUDFRONT_DISTRIBUTION_ID: "E1Z8XTA8XF1GIV" + S3_BUCKET: 'dev-lti-erp.mbugroup.id' + AWS_REGION: 'ap-southeast-3' + CLOUDFRONT_DISTRIBUTION_ID: 'E1Z8XTA8XF1GIV' environment: name: development url: https://dev-lti-erp.mbugroup.id @@ -166,20 +166,20 @@ build:staging: environment: name: staging variables: - NEXT_PUBLIC_LTI_URL: "https://stg-lti-erp.mbugroup.id" - NEXT_PUBLIC_SSO_LOGIN_URL: "https://stg-auth-erp.mbugroup.id" - NEXT_PUBLIC_API_BASE_URL: "https://stg-api-lti.mbugroup.id/api" - NEXT_PUBLIC_CLIENT_ID: "Lumbung-Telur-Indonesia" + NEXT_PUBLIC_LTI_URL: 'https://stg-lti-erp.mbugroup.id' + NEXT_PUBLIC_SSO_LOGIN_URL: 'https://stg-auth-erp.mbugroup.id' + NEXT_PUBLIC_API_BASE_URL: 'https://stg-api-lti.mbugroup.id/api' + NEXT_PUBLIC_CLIENT_ID: 'Lumbung-Telur-Indonesia' deploy:staging: <<: *deploy_template - needs: ["build:staging"] + needs: ['build:staging'] rules: - if: '$CI_COMMIT_BRANCH == "staging"' variables: - S3_BUCKET: "stg-lti-erp.mbugroup.id" - AWS_REGION: "ap-southeast-3" - CLOUDFRONT_DISTRIBUTION_ID: "E2V6PPO1AUIU7H" + S3_BUCKET: 'stg-lti-erp.mbugroup.id' + AWS_REGION: 'ap-southeast-3' + CLOUDFRONT_DISTRIBUTION_ID: 'E2V6PPO1AUIU7H' environment: name: staging - url: https://stg-lti-erp.mbugroup.id \ No newline at end of file + url: https://stg-lti-erp.mbugroup.id From c6e9e98ce182658c56fbcbf0706482ba11576823 Mon Sep 17 00:00:00 2001 From: kris Date: Sat, 3 Jan 2026 12:42:09 +0000 Subject: [PATCH 9/9] Update .gitlab-ci.yml file --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e02ea8ee..e80a7e02 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,7 +7,7 @@ stages: # ========================================================== default: tags: - - self-hosted + - server-development-biznet interruptible: true # ==========================================================