fix(resolve): fix resolve merge

This commit is contained in:
rstubryan
2025-11-03 09:35:09 +07:00
82 changed files with 754 additions and 736 deletions
+13 -15
View File
@@ -1,14 +1,12 @@
'use client';
import {
HTMLAttributes,
ReactNode,
} from 'react';
import { HTMLAttributes, ReactNode } from 'react';
import { cn } from '@/lib/helper';
import Image from 'next/image';
export interface CardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'className'> {
export interface CardProps
extends Omit<HTMLAttributes<HTMLDivElement>, 'className'> {
title?: string;
subtitle?: string;
image?: string;
@@ -45,17 +43,17 @@ const Card = ({
const baseClasses = 'card bg-base-100';
const variantClasses = {
'default': '',
'compact': 'card-compact',
'bordered': 'border border-base-300',
'shadow': 'shadow-xl',
default: '',
compact: 'card-compact',
bordered: 'border border-base-300',
shadow: 'shadow-xl',
'image-full': 'card-side card-compact shadow-xl',
};
const sizeClasses = {
'sm': 'w-64',
'md': 'w-96',
'lg': 'w-[28rem]',
sm: 'w-64',
md: 'w-96',
lg: 'w-[28rem]',
};
return cn(
@@ -85,9 +83,9 @@ const Card = ({
const getTitleClasses = () => {
const sizeClasses = {
'sm': 'text-lg',
'md': 'text-xl',
'lg': 'text-2xl',
sm: 'text-lg',
md: 'text-xl',
lg: 'text-2xl',
};
return cn('card-title font-bold', sizeClasses[size], className?.title);
+10 -10
View File
@@ -185,17 +185,17 @@ const Pagination = ({
currentPage <= 2
? currentPage + 2
: currentPage === totalPages - 2
? 3
: currentPage >= totalPages - 1
? 4
: 1
? 3
: currentPage >= totalPages - 1
? 4
: 1
}
endPage={
currentPage <= 2 || currentPage >= totalPages - 1
? totalPages - 3
: currentPage === totalPages - 2
? totalPages - 4
: 2
? totalPages - 4
: 2
}
onPageItemClick={pageChangeHandler}
/>
@@ -242,15 +242,15 @@ const Pagination = ({
currentPage <= 3
? currentPage + 2
: currentPage >= 4
? currentPage + 2
: 1
? currentPage + 2
: 1
}
endPage={
currentPage <= 3
? totalPages - 2
: currentPage >= 4
? totalPages - 1
: 0
? totalPages - 1
: 0
}
onPageItemClick={pageChangeHandler}
/>
+2 -9
View File
@@ -1,10 +1,6 @@
'use client';
import {
ChangeEventHandler,
FocusEventHandler,
ReactNode,
} from 'react';
import { ChangeEventHandler, FocusEventHandler, ReactNode } from 'react';
import { cn } from '@/lib/helper';
@@ -109,10 +105,7 @@ const DateInput = ({
min={min}
max={max}
disabled={disabled}
className={cn(
'grow bg-transparent cursor-pointer',
className?.input
)}
className={cn('grow bg-transparent cursor-pointer', className?.input)}
readOnly={readOnly}
/>
+1 -4
View File
@@ -69,10 +69,7 @@ const FileInput = ({
onChange={onChange}
onBlur={onBlur}
disabled={disabled}
className={cn(
'grow file-input w-full h-12 rounded',
className?.input
)}
className={cn('grow file-input w-full h-12 rounded', className?.input)}
readOnly={readOnly}
/>
+6 -2
View File
@@ -49,14 +49,18 @@ const MenuItem = ({
);
return (
<li onClick={onClick}>
<li>
{href && (
<Link href={href} className={menuItemBaseClassName}>
{menuItemContent}
</Link>
)}
{!href && <a className={menuItemBaseClassName}>{menuItemContent}</a>}
{!href && (
<button className={menuItemBaseClassName} onClick={onClick}>
{menuItemContent}
</button>
)}
</li>
);
};
+10 -10
View File
@@ -31,21 +31,21 @@ const ApprovalSteps = ({ approvals }: ApprovalStepsProps) => {
approval.status === 'APPROVED'
? 'success'
: approval.status === 'REJECTED'
? 'error'
: approval.status === 'WAITING'
? 'warning'
: undefined;
? 'error'
: approval.status === 'WAITING'
? 'warning'
: undefined;
const stepItemIcon =
approval.status === 'APPROVED'
? 'material-symbols:check-rounded'
: approval.status === 'REJECTED'
? 'material-symbols:close-rounded'
: approval.status === 'WAITING'
? 'pajamas:dash-circle'
: approval.logs && approval.logs.length > 0
? 'material-symbols:info-outline-rounded'
: 'bxs:hourglass';
? 'material-symbols:close-rounded'
: approval.status === 'WAITING'
? 'pajamas:dash-circle'
: approval.logs && approval.logs.length > 0
? 'material-symbols:info-outline-rounded'
: 'bxs:hourglass';
return (
<StepItem
@@ -10,11 +10,7 @@ import { inventoryAdjustmentApi } from '@/services/api/inventory';
import { useTableFilter } from '@/services/hooks/useTableFilter';
import { InventoryAdjustment } from '@/types/api/inventory/adjustment';
import { Icon } from '@iconify/react';
import {
ColumnDef,
ColumnSort,
SortingState,
} from '@tanstack/react-table';
import { ColumnDef, ColumnSort, SortingState } from '@tanstack/react-table';
import { useCallback, useEffect, useState } from 'react';
import useSWR from 'swr';
@@ -44,10 +40,7 @@ const InventoryAdjustmentTable = () => {
});
// Fetch Data
const {
data: inventoryAdjustments,
isLoading,
} = useSWR(
const { data: inventoryAdjustments, isLoading } = useSWR(
`${inventoryAdjustmentApi.basePath}${getTableFilterQueryString()}`,
inventoryAdjustmentApi.getAllFetcher
);
@@ -113,8 +106,8 @@ const InventoryAdjustmentTable = () => {
type === 'INCREASE'
? 'Peningkatan'
: type === 'DECREASE'
? 'Penurunan'
: '-';
? 'Penurunan'
: '-';
return (
<div
@@ -187,8 +180,13 @@ const InventoryAdjustmentTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/inventory/adjustment/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/inventory/adjustment/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah
</Button>
@@ -211,7 +209,7 @@ const InventoryAdjustmentTable = () => {
value: tableFilterState.pageSize,
}}
onChange={pageSizeChangeHandler}
className={{ wrapper: 'max-w-28' }}
className={{ wrapper: 'min-w-28' }}
/>
</div>
</div>
@@ -4,24 +4,21 @@ export const InventoryAdjustmentFormSchema = Yup.object({
product_category: Yup.object({
value: Yup.number().required('ID Kategori Produk wajib diisi!'),
label: Yup.string().required('Nama Kategori Produk wajib diisi!'),
})
.nullable(),
}).nullable(),
product_category_id: Yup.number().nullable(),
product: Yup.object({
value: Yup.number().required('ID Produk wajib diisi!'),
label: Yup.string().required('Nama Produk wajib diisi!'),
})
.nullable(),
}).nullable(),
product_id: Yup.number().nullable(),
warehouse: Yup.object({
value: Yup.number().required('ID Gudang wajib diisi!'),
label: Yup.string().required('Nama Gudang wajib diisi!'),
})
.nullable(),
}).nullable(),
warehouse_id: Yup.number().nullable(),
@@ -51,9 +51,8 @@ const InventoryAdjustmentForm = ({
// Submit Handler
const createInventoryAdjustmentHandler = useCallback(
async (payload: CreateInventoryAdjustmentPayload) => {
const createInventoryAdjustmentRes = await inventoryAdjustmentApi.create(
payload
);
const createInventoryAdjustmentRes =
await inventoryAdjustmentApi.create(payload);
if (isResponseError(createInventoryAdjustmentRes)) {
setInventoryAdjustmentFormErrorMessage(
@@ -68,7 +67,9 @@ const InventoryAdjustmentForm = ({
[router]
);
const formikInitialValues = useMemo<Partial<InventoryAdjustmentFormValues>>(() => {
const formikInitialValues = useMemo<
Partial<InventoryAdjustmentFormValues>
>(() => {
return {
product_category_id: initialValues?.product_category?.id ?? 0,
product_id: initialValues?.product?.id ?? 0,
@@ -185,7 +186,6 @@ const InventoryAdjustmentForm = ({
warehouseChangeHandler(null);
};
const { setValues: formikSetValues } = formik;
// Effect
@@ -225,7 +225,13 @@ const InventoryAdjustmentForm = ({
const type = initialValues.transaction_type.toLowerCase();
setQuantityLabel(type === 'increase' ? 'Tambah Stok' : 'Kurangi Stok');
}
}, [formik, initialValues, setQuantityLabel, setDisabledProduct, setSelectedProductCategories]);
}, [
formik,
initialValues,
setQuantityLabel,
setDisabledProduct,
setSelectedProductCategories,
]);
useEffect(() => {
formikSetValues(formikInitialValues as InventoryAdjustmentFormValues);
}, [formikSetValues, formikInitialValues]);
@@ -364,15 +370,19 @@ const InventoryAdjustmentForm = ({
errorMessage={formik.errors.transaction_type as string}
variant='radio-primary'
required
bottomLabel={formik.values.transaction_type == undefined ? 'Pilih salah satu tipe transaksi' : undefined}
bottomLabel={
formik.values.transaction_type == undefined
? 'Pilih salah satu tipe transaksi'
: undefined
}
disabled={type === 'detail'}
/>
{/* Number Input Stock */}
<TextInput
className={{
wrapper: `${formik.values.transaction_type != undefined ? '' : 'hidden'}`,
}}
className={{
wrapper: `${formik.values.transaction_type != undefined ? '' : 'hidden'}`,
}}
required
label={quantityLabel}
name='quantity'
@@ -395,8 +405,6 @@ const InventoryAdjustmentForm = ({
readOnly={type === 'detail'}
/>
{/* Text Area Input Reason */}
<TextArea
required
@@ -413,14 +421,23 @@ const InventoryAdjustmentForm = ({
<div className='flex flex-row justify-between gap-2 flex-wrap'>
{type !== 'detail' && (
<div className='flex flex-row justify-end gap-2'>
<Button type='button' color='warning' className='px-4' onClick={resetHandler}>
<Button
type='button'
color='warning'
className='px-4'
onClick={resetHandler}
>
Reset
</Button>
<Button
type='submit'
color='primary'
isLoading={formik.isSubmitting}
disabled={!formik.isValid || formik.isSubmitting || formik.values.product == undefined}
disabled={
!formik.isValid ||
formik.isSubmitting ||
formik.values.product == undefined
}
className='px-4'
>
Submit
@@ -14,6 +14,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { Area } from '@/types/api/master-data/area';
import { AreaApi } from '@/services/api/master-data';
@@ -32,16 +33,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/area/detail/?areaId=${props.row.original.id}`}
variant='ghost'
@@ -76,7 +68,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -150,7 +142,7 @@ const AreasTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -199,10 +191,15 @@ const AreasTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/area/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/area/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Area
Tambah
</Button>
</div>
@@ -14,6 +14,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { Bank } from '@/types/api/master-data/bank';
import { BankApi } from '@/services/api/master-data';
@@ -32,16 +33,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/bank/detail/?bankId=${props.row.original.id}`}
variant='ghost'
@@ -66,7 +58,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -76,7 +68,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -163,7 +155,7 @@ const BanksTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -212,10 +204,15 @@ const BanksTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/bank/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/bank/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Bank
Tambah
</Button>
</div>
@@ -8,6 +8,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import Table from '@/components/Table';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { ROWS_OPTIONS } from '@/config/constant';
import { isResponseSuccess } from '@/lib/api-helper';
import { cn } from '@/lib/helper';
@@ -15,10 +16,7 @@ import { CustomerApi } from '@/services/api/master-data';
import { useTableFilter } from '@/services/hooks/useTableFilter';
import { Customer } from '@/types/api/master-data/customer';
import { Icon } from '@iconify/react';
import {
CellContext,
ColumnDef,
} from '@tanstack/react-table';
import { CellContext, ColumnDef } from '@tanstack/react-table';
import { useState } from 'react';
import toast from 'react-hot-toast';
import useSWR from 'swr';
@@ -33,16 +31,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type == 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/customer/detail/?customerId=${props.row.original.id}`}
variant='ghost'
@@ -53,10 +42,10 @@ const RowOptionsMenu = ({
Detail
</Button>
<Button
className='justify-start text-sm'
href={`/master-data/customer/detail/edit/?customerId=${props.row.original.id}`}
variant='ghost'
color='warning'
className='justify-start text-sm'
>
<Icon icon='material-symbols:edit-outline' width={16} height={16} />
Edit
@@ -65,7 +54,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -75,7 +64,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -174,7 +163,7 @@ const CustomersTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -210,10 +199,15 @@ const CustomersTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/customer/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/customer/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Customer
Tambah
</Button>
</div>
@@ -285,4 +279,4 @@ const CustomersTable = () => {
);
};
export default CustomersTable;
export default CustomersTable;
@@ -11,7 +11,11 @@ import {
import { useRouter } from 'next/navigation';
import { useCallback, useEffect, useMemo, useState } from 'react';
import toast from 'react-hot-toast';
import { CustomerFormSchema, CustomerFormValues, UpdateCustomerFormSchema } from '@/components/pages/master-data/customer/form/CustomerForm.schema';
import {
CustomerFormSchema,
CustomerFormValues,
UpdateCustomerFormSchema,
} from '@/components/pages/master-data/customer/form/CustomerForm.schema';
import { useFormik } from 'formik';
import Button from '@/components/Button';
import { Icon } from '@iconify/react';
@@ -150,7 +154,8 @@ const CustomerForm = ({
const formik = useFormik<CustomerFormValues>({
initialValues: formikInitialValues,
enableReinitialize: true,
validationSchema: formType === 'edit' ? UpdateCustomerFormSchema : CustomerFormSchema,
validationSchema:
formType === 'edit' ? UpdateCustomerFormSchema : CustomerFormSchema,
onSubmit: async (values) => {
// reset error message
setCustomerFormErrorMessage('');
@@ -14,6 +14,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { Fcr } from '@/types/api/master-data/fcr';
import { FcrApi } from '@/services/api/master-data';
@@ -32,16 +33,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/fcr/detail/?fcrId=${props.row.original.id}`}
variant='ghost'
@@ -66,7 +58,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -76,7 +68,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -150,7 +142,7 @@ const FcrsTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -199,10 +191,15 @@ const FcrsTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/fcr/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/fcr/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah FCR
Tambah
</Button>
</div>
@@ -12,6 +12,7 @@ import { FlockApi } from '@/services/api/master-data';
import { useModal } from '@/components/Modal';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import toast from 'react-hot-toast';
import DebouncedTextInput from '@/components/input/DebouncedTextInput';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
@@ -30,16 +31,7 @@ const RowsOptions = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type == 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/flock/detail/edit/?flockId=${props.row.original.id}`}
variant='ghost'
@@ -54,7 +46,7 @@ const RowsOptions = ({
/>
Edit
</Button>
<Button
<Button
href={`/master-data/flock/detail/?flockId=${props.row.original.id}`}
variant='ghost'
color='primary'
@@ -72,7 +64,7 @@ const RowsOptions = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -82,7 +74,7 @@ const RowsOptions = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -203,9 +195,15 @@ const FlockTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/flock/add' color='primary'>
Tambah Flock
<div className='w-full flex flex-row'>
<Button
href='/master-data/flock/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah
</Button>
</div>
@@ -275,4 +273,4 @@ const FlockTable = () => {
);
};
export default FlockTable;
export default FlockTable;
@@ -3,10 +3,7 @@ import * as Yup from 'yup';
export const FlockFormSchema = Yup.object({
name: Yup.string()
.required('Nama wajib diisi!')
.matches(
/^[\p{L}\p{N}\s]+$/u,
'Nama tidak boleh mengandung simbol'
),
.matches(/^[\p{L}\p{N}\s]+$/u, 'Nama tidak boleh mengandung simbol'),
});
export const UpdateFlockFormSchema = FlockFormSchema;
@@ -1,11 +1,15 @@
'use client'
'use client';
import { useModal } from '@/components/Modal';
import { FlockApi } from '@/services/api/master-data';
import { Flock } from '@/types/api/master-data/flock';
import { useRouter } from 'next/navigation';
import { useEffect, useMemo, useState } from 'react';
import { FlockFormSchema, FlockFormValues, UpdateFlockFormSchema } from '@/components/pages/master-data/flock/form/FlockForm.schema';
import {
FlockFormSchema,
FlockFormValues,
UpdateFlockFormSchema,
} from '@/components/pages/master-data/flock/form/FlockForm.schema';
import { useFormik } from 'formik';
import Button from '@/components/Button';
import { Icon } from '@iconify/react';
@@ -48,7 +52,8 @@ const FlockForm = ({ formType = 'add', initialValues }: FlockCustomProps) => {
const formik = useFormik<FlockFormValues>({
initialValues: formikInitialValue,
enableReinitialize: true,
validationSchema: formType === 'edit' ? UpdateFlockFormSchema : FlockFormSchema,
validationSchema:
formType === 'edit' ? UpdateFlockFormSchema : FlockFormSchema,
onSubmit: async (values) => {
// reset error message
setFlockFormErrorMessage('');
@@ -19,6 +19,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { Kandang } from '@/types/api/master-data/kandang';
import { KandangApi } from '@/services/api/master-data';
@@ -37,16 +38,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/kandang/detail/?kandangId=${props.row.original.id}`}
variant='ghost'
@@ -71,7 +63,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -81,7 +73,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -173,7 +165,7 @@ const KandangsTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -238,10 +230,15 @@ const KandangsTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/kandang/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/kandang/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Kandang
Tambah
</Button>
</div>
@@ -19,6 +19,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { Location } from '@/types/api/master-data/location';
import { LocationApi } from '@/services/api/master-data';
@@ -37,16 +38,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/location/detail/?locationId=${props.row.original.id}`}
variant='ghost'
@@ -71,7 +63,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -81,7 +73,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -172,7 +164,7 @@ const LocationsTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -237,10 +229,15 @@ const LocationsTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/location/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/location/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Location
Tambah
</Button>
</div>
@@ -19,6 +19,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { Nonstock } from '@/types/api/master-data/nonstock';
import { NonstockApi } from '@/services/api/master-data';
@@ -37,16 +38,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/nonstock/detail/?nonstockId=${props.row.original.id}`}
variant='ghost'
@@ -71,7 +63,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -81,7 +73,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -184,7 +176,7 @@ const NonstocksTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -249,10 +241,15 @@ const NonstocksTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/nonstock/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/nonstock/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Nonstock
Tambah
</Button>
</div>
@@ -14,6 +14,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { ProductCategory } from '@/types/api/master-data/product-category';
import { ProductCategoryApi } from '@/services/api/master-data';
@@ -32,16 +33,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/product-category/detail/?productCategoryId=${props.row.original.id}`}
variant='ghost'
@@ -64,7 +56,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='mdi:delete-outline'
@@ -74,7 +66,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -154,7 +146,7 @@ const ProductCategoryTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -200,10 +192,15 @@ const ProductCategoryTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/product-category/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/product-category/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Product Category
Tambah
</Button>
</div>
<DebouncedTextInput
@@ -19,6 +19,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { Product } from '@/types/api/master-data/product';
import { ProductApi } from '@/services/api/master-data';
@@ -36,16 +37,7 @@ const RowOptionsMenu = ({
props: CellContext<Product, unknown>;
deleteClickHandler: () => void;
}) => (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/product/detail/?productId=${props.row.original.id}`}
variant='ghost'
@@ -68,7 +60,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -78,7 +70,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
const ProductsTable = () => {
@@ -217,7 +209,7 @@ const ProductsTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -280,10 +272,15 @@ const ProductsTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/product/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/product/add'
variant='outline'
className='w-full sm:w-fit'
color='primary'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Produk
Tambah
</Button>
</div>
<DebouncedTextInput
@@ -8,6 +8,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import Table from '@/components/Table';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { ROWS_OPTIONS } from '@/config/constant';
import { isResponseSuccess } from '@/lib/api-helper';
import { cn } from '@/lib/helper';
@@ -30,16 +31,7 @@ const RowOptions = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type == 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/supplier/detail/?supplierId=${props.row.original.id}`}
variant='ghost'
@@ -72,7 +64,7 @@ const RowOptions = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -82,7 +74,7 @@ const RowOptions = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -226,10 +218,15 @@ const SuppliersTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/supplier/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/supplier/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Supplier
Tambah
</Button>
</div>
@@ -1,41 +1,44 @@
import * as Yup from 'yup';
export const SupplierFormSchema = Yup.object({
name: Yup.string().required('Nama wajib diisi!'),
alias: Yup.string()
.matches(/^[A-Za-z0-9]+$/, 'Alias hanya boleh berisi huruf dan angka tanpa spasi atau simbol!')
name: Yup.string().required('Nama wajib diisi!'),
alias: Yup.string()
.matches(
/^[A-Za-z0-9]+$/,
'Alias hanya boleh berisi huruf dan angka tanpa spasi atau simbol!'
)
.max(5, 'Alias maksimal 5 karakter!')
.required('Alias wajib diisi!'),
pic: Yup.string().required('PIC wajib diisi!'),
type: Yup.object({
value: Yup.string().required(),
label: Yup.string().required(),
})
.required('Tipe wajib diisi!'),
category: Yup.object({
value: Yup.string().required(),
label: Yup.string().required(),
})
.required('Tipe wajib diisi!'),
hatchery: Yup.string().required('Hatchery wajib diisi!'),
phone: Yup.string()
.matches(/^[0-9]+$/, 'Nomor telepon hanya boleh berisi angka!')
.min(10, 'Nomor telepon minimal 10 digit!')
.max(12, 'Nomor telepon maksimal 12 digit!')
.required('Nomor telepon wajib diisi!'),
email: Yup.string()
.email('Format email tidak valid!')
.required('Email wajib diisi!'),
address: Yup.string().required('Alamat wajib diisi!'),
npwp: Yup.string()
.matches(/^[0-9]+$/, 'Nomor NPWP hanya boleh berisi angka!')
.required('Nomor NPWP wajib diisi!'),
account_number: Yup.string()
.matches(/^[0-9]+$/, 'Nomor rekening hanya boleh berisi angka!')
.required('Nomor rekening wajib diisi!'),
due_date: Yup.number().min(1, 'Tanggal jatuh tempo wajib diisi!').required('Tanggal jatuh tempo wajib diisi!'),
pic: Yup.string().required('PIC wajib diisi!'),
type: Yup.object({
value: Yup.string().required(),
label: Yup.string().required(),
}).required('Tipe wajib diisi!'),
category: Yup.object({
value: Yup.string().required(),
label: Yup.string().required(),
}).required('Tipe wajib diisi!'),
hatchery: Yup.string().required('Hatchery wajib diisi!'),
phone: Yup.string()
.matches(/^[0-9]+$/, 'Nomor telepon hanya boleh berisi angka!')
.min(10, 'Nomor telepon minimal 10 digit!')
.max(12, 'Nomor telepon maksimal 12 digit!')
.required('Nomor telepon wajib diisi!'),
email: Yup.string()
.email('Format email tidak valid!')
.required('Email wajib diisi!'),
address: Yup.string().required('Alamat wajib diisi!'),
npwp: Yup.string()
.matches(/^[0-9]+$/, 'Nomor NPWP hanya boleh berisi angka!')
.required('Nomor NPWP wajib diisi!'),
account_number: Yup.string()
.matches(/^[0-9]+$/, 'Nomor rekening hanya boleh berisi angka!')
.required('Nomor rekening wajib diisi!'),
due_date: Yup.number()
.min(1, 'Tanggal jatuh tempo wajib diisi!')
.required('Tanggal jatuh tempo wajib diisi!'),
});
export const UpdateSupplierFormSchema = SupplierFormSchema;
export type SupplierFormValues = Yup.InferType<typeof SupplierFormSchema>;
export type SupplierFormValues = Yup.InferType<typeof SupplierFormSchema>;
@@ -41,7 +41,9 @@ const SupplierForm = ({
// Setup State
const [supplierFormErrorMessage, setSupplierFormErrorMessage] = useState('');
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [hatcheryOptionsValues, setHatcheryOptionValues] = useState<OptionType[]>([]);
const [hatcheryOptionsValues, setHatcheryOptionValues] = useState<
OptionType[]
>([]);
// -- Options data mapping
const typeOptions = TYPE_OPTIONS;
@@ -167,7 +169,7 @@ const SupplierForm = ({
// Initialize Formik
useEffect(() => {
formikSetValues(formikInitialValues);
if(formType != 'add'){
if (formType != 'add') {
const hatcheryArrays = formikInitialValues.hatchery.split(',');
const hatcheryCreatedOptions = hatcheryArrays.map((item) => ({
value: item,
@@ -177,11 +179,13 @@ const SupplierForm = ({
}
}, [formikSetValues, formikInitialValues, setHatcheryOptionValues]);
useEffect(() => {
const commaSeparatedValues = hatcheryOptionsValues.map((item) => item.value).join(',');
const commaSeparatedValues = hatcheryOptionsValues
.map((item) => item.value)
.join(',');
formikSetValues({
...formik.values,
hatchery: commaSeparatedValues,
})
});
}, [hatcheryOptionsValues, formikSetValues]);
// Option Handler
@@ -305,7 +309,9 @@ const SupplierForm = ({
console.log(val); // pastikan val = array of { value, label }
setHatcheryOptionValues(val as OptionType[]);
}}
isError={formik.touched.hatchery && Boolean(formik.errors.hatchery)}
isError={
formik.touched.hatchery && Boolean(formik.errors.hatchery)
}
errorMessage={formik.errors.hatchery as string}
isDisabled={formType === 'detail'}
isClearable
@@ -14,6 +14,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { Uom } from '@/types/api/master-data/uom';
import { UomApi } from '@/services/api/master-data';
@@ -32,16 +33,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/uom/detail/?uomId=${props.row.original.id}`}
variant='ghost'
@@ -66,7 +58,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -76,7 +68,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -150,7 +142,7 @@ const UomsTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -199,10 +191,15 @@ const UomsTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/uom/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/uom/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah UOM
Tambah
</Button>
</div>
@@ -19,6 +19,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { Warehouse } from '@/types/api/master-data/warehouse';
import { WarehouseApi } from '@/services/api/master-data';
@@ -37,16 +38,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/master-data/warehouse/detail/?warehouseId=${props.row.original.id}`}
variant='ghost'
@@ -81,7 +73,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -206,7 +198,7 @@ const WarehousesTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -277,10 +269,15 @@ const WarehousesTable = () => {
<div className='w-full p-0 sm:p-4'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<div className='flex flex-row'>
<Button href='/master-data/warehouse/add' color='primary'>
<div className='w-full flex flex-row'>
<Button
href='/master-data/warehouse/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Warehouse
Tambah
</Button>
</div>
@@ -8,6 +8,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import Table from '@/components/Table';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { TableRowSizeSelector } from '@/components/table/TableRowSizeSelector';
import { ROWS_OPTIONS } from '@/config/constant';
import { isResponseSuccess } from '@/lib/api-helper';
@@ -87,7 +88,9 @@ const ChickinTable = () => {
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
<Button
href='/production/chickin/add?projectFlockId=1'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='uil:plus' width={24} height={24} />
Tambah
@@ -130,20 +133,20 @@ const ChickinTable = () => {
} else {
return '-';
}
}
},
},
{
accessorFn: (row) => row.chick_in_date,
header: 'Tanggal Chickin',
cell: (props) => {
if (props.row.original.chick_in_date) {
return new Date(props.row.original.chick_in_date).toLocaleDateString(
'id-ID'
);
return new Date(
props.row.original.chick_in_date
).toLocaleDateString('id-ID');
} else {
return '-';
}
}
},
},
{
accessorFn: (row) => row.note,
@@ -166,7 +169,7 @@ const ChickinTable = () => {
deleteModal.openModal();
};
const editClickHandler = () => {
const editClickHandler = () => {
setSelectedChickin(props.row.original);
chickinModal.openModal();
};
@@ -240,7 +243,9 @@ const ChickinTable = () => {
<Modal ref={chickinModal.ref}>
<div className='flex flex-row justify-between items-center'>
<h1 className='text-xl font-semibold text-center mb-6'>
Chickin Kandang - { selectedChickin?.project_flock_kandang && selectedChickin?.project_flock_kandang.kandang?.name}
Chickin Kandang -{' '}
{selectedChickin?.project_flock_kandang &&
selectedChickin?.project_flock_kandang.kandang?.name}
</h1>
<Button
color='error'
@@ -255,10 +260,14 @@ const ChickinTable = () => {
/>
</Button>
</div>
<ChickinForm initialValues={selectedChickin} formType='edit' afterSubmit={() => {
refreshChickins()
chickinModal.closeModal()
}}/>
<ChickinForm
initialValues={selectedChickin}
formType='edit'
afterSubmit={() => {
refreshChickins();
chickinModal.closeModal();
}}
/>
</Modal>
</>
);
@@ -276,16 +285,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type == 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/production/chickin/detail?chickinId=${props.row.original.id}`}
variant='ghost'
@@ -308,7 +308,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -318,7 +318,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -3,9 +3,11 @@ import * as Yup from 'yup';
export const ChickinFormSchema = Yup.object({
chick_in_date: Yup.string().required('Tanggal masuk wajib diisi!'),
note: Yup.string().required('Catatan wajib diisi!'),
quantity: Yup.number().min(1, 'Jumlah wajib diisi!').required('Jumlah wajib diisi!'),
})
quantity: Yup.number()
.min(1, 'Jumlah wajib diisi!')
.required('Jumlah wajib diisi!'),
});
export type ChickinFormValues = Yup.InferType<typeof ChickinFormSchema>;
export const UpdateChickinFormSchema = ChickinFormSchema;
export const UpdateChickinFormSchema = ChickinFormSchema;
@@ -9,6 +9,7 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
import Table from '@/components/Table';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { ROWS_OPTIONS } from '@/config/constant';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { cn } from '@/lib/helper';
@@ -37,16 +38,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type == 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/production/project-flock/detail?projectFlockId=${props.row.original.id}`}
variant='ghost'
@@ -82,7 +74,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -92,7 +84,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -259,6 +251,7 @@ const ProjectFlockTable = () => {
<div className='flex flex-col sm:flex-row gap-3 w-full'>
<Button
href='/production/project-flock/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
@@ -371,10 +364,10 @@ const ProjectFlockTable = () => {
const selectableRows = allRows.filter(
(row) => row.original?.approval?.step_number == 1
);
const allSelected = selectableRows.every((row) =>
row.getIsSelected()
) && selectableRows.length != 0;
const allSelected =
selectableRows.every((row) => row.getIsSelected()) &&
selectableRows.length != 0;
const someSelected =
selectableRows.some((row) => row.getIsSelected()) &&
@@ -508,7 +501,7 @@ const ProjectFlockTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
deleteClickHandler={deleteClickHandler}
/>
@@ -24,7 +24,8 @@ export const ProjectFlockFormSchema = Yup.object({
value: Yup.string().required('Nilai Kategori wajib diisi!'),
label: Yup.string().required('Label Kategori wajib diisi!'),
}).nullable(),
category: Yup.string().oneOf(['GROWING', 'LAYING'], 'Kategori wajib diisi!')
category: Yup.string()
.oneOf(['GROWING', 'LAYING'], 'Kategori wajib diisi!')
.required('Kategori wajib diisi!'),
// FCR
@@ -79,9 +79,8 @@ const ProjectFlockForm = ({
const [isApprovedDisabled, setIsApprovedDisabled] = useState(
initialValues?.approval.step_name == 'Pengajuan' ? false : true
);
const [isRejectedDisabled, setIsRejectedDisabled] = useState(
!isApprovedDisabled
);
const [isRejectedDisabled, setIsRejectedDisabled] =
useState(!isApprovedDisabled);
const [approvalAction, setApprovalAction] = useState<'APPROVED' | 'REJECTED'>(
!isApprovedDisabled ? 'APPROVED' : 'REJECTED'
);
@@ -143,10 +142,11 @@ const ProjectFlockForm = ({
search: '',
location_id: selectedLocation == '' ? '0' : selectedLocation,
}).toString()}`;
const { data: kandang, isLoading: isLoadingKandang, mutate: refreshKandang} = useSWR(
kandangUrl,
KandangApi.getAllFetcher
);
const {
data: kandang,
isLoading: isLoadingKandang,
mutate: refreshKandang,
} = useSWR(kandangUrl, KandangApi.getAllFetcher);
const getPeriodFlocksUrl = `flocks/${selectedFlock}/periods`;
@@ -207,10 +207,7 @@ const ProjectFlockForm = ({
setOpenSelectKandangs(true);
const newRowSelection = Object.fromEntries(
initialValues.kandangs.map((k: Kandang) => [
k.id.toString(),
true,
])
initialValues.kandangs.map((k: Kandang) => [k.id.toString(), true])
);
setRowSelection(newRowSelection);
}
@@ -38,10 +38,13 @@ const ProjectFlockKandangTable = ({
const allSelected =
selectableRows.every((row) => row.getIsSelected()) &&
selectableRows.length != 0 && formType != 'detail';
selectableRows.length != 0 &&
formType != 'detail';
const someSelected =
selectableRows.some((row) => row.getIsSelected()) && !allSelected && formType != 'detail';
selectableRows.some((row) => row.getIsSelected()) &&
!allSelected &&
formType != 'detail';
const toggleSelectableRows = () => {
const shouldSelect = !allSelected;
@@ -17,6 +17,7 @@ import { TableRowSizeSelector } from '@/components/table/TableRowSizeSelector';
import Table from '@/components/Table';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { type CellContext } from '@tanstack/react-table';
import { type Recording } from '@/types/api/production/recording';
import { type BaseApiResponse } from '@/types/api/api-general';
@@ -38,16 +39,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`recording/detail/?recordingId=${props.row.original.id}`}
variant='ghost'
@@ -70,7 +62,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='mdi:delete-outline'
@@ -80,7 +72,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -286,7 +278,7 @@ const RecordingTable = () => {
<TableToolbar
addButton={{
href: 'recording/add',
label: 'Tambah Recording',
label: 'Tambah',
}}
search={{
value: tableFilterState.search,
@@ -19,6 +19,7 @@ import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import TextInput from '@/components/input/TextInput';
import CheckboxInput from '@/components/input/CheckboxInput';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { TransferToLaying } from '@/types/api/production/transfer-to-laying';
import { TransferToLayingApi } from '@/services/api/production/transfer-to-laying';
@@ -43,16 +44,7 @@ const RowOptionsMenu = ({
deleteClickHandler: () => void;
}) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`/production/transfer-to-laying/detail/?transferToLayingId=${props.row.original.id}`}
variant='ghost'
@@ -97,7 +89,7 @@ const RowOptionsMenu = ({
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
@@ -107,7 +99,7 @@ const RowOptionsMenu = ({
/>
Delete
</Button>
</div>
</RowOptionsMenuWrapper>
);
};
@@ -291,7 +283,7 @@ const TransferToLayingsTable = () => {
{currentPageSize <= 2 && (
<RowCollapseOptions>
<RowOptionsMenu
type='dropdown'
type='collapse'
props={props}
approveClickHandler={approveClickHandler}
rejectClickHandler={rejectClickHandler}
@@ -328,9 +320,8 @@ const TransferToLayingsTable = () => {
const confirmationModalApproveClickHandler = async () => {
setIsApproveLoading(true);
const bulkApproveResponse = await TransferToLayingApi.bulkApprove(
selectedRowIds
);
const bulkApproveResponse =
await TransferToLayingApi.bulkApprove(selectedRowIds);
if (isResponseSuccess(bulkApproveResponse)) {
refreshTransferToLayings();
@@ -358,9 +349,8 @@ const TransferToLayingsTable = () => {
const confirmationModalRejectClickHandler = async () => {
setIsRejectLoading(true);
const bulkRejectResponse = await TransferToLayingApi.bulkReject(
selectedRowIds
);
const bulkRejectResponse =
await TransferToLayingApi.bulkReject(selectedRowIds);
if (isResponseSuccess(bulkRejectResponse)) {
refreshTransferToLayings();
@@ -437,11 +427,12 @@ const TransferToLayingsTable = () => {
<div className='w-full sm:w-fit flex flex-col sm:flex-row self-start gap-2'>
<Button
href='/production/transfer-to-laying/add'
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
Tambah Transfer ke Laying
Tambah
</Button>
{selectedRowIds.length > 0 && (
@@ -484,7 +475,9 @@ const TransferToLayingsTable = () => {
placeholder='Cari TransferToLaying'
value={tableFilterState.search}
onChange={searchChangeHandler}
className={{ wrapper: 'sm:max-w-3xs' }}
className={{
wrapper: 'sm:max-w-3xs',
}}
/>
</div>
@@ -497,7 +490,9 @@ const TransferToLayingsTable = () => {
placeholder='Masukkan tanggal transfer'
value={tableFilterState.transferDate}
onChange={transferDateChangeHandler}
className={{ wrapper: 'col-span-12 sm:col-span-3' }}
className={{
wrapper: 'col-span-12 sm:col-span-3',
}}
/>
<SelectInput
+1 -1
View File
@@ -16,7 +16,7 @@ const RowCollapseOptions = ({ children }: RowCollapseOptionsProps) => {
<Icon icon='material-symbols:more-vert' width={16} height={16} />
</Button>
}
className='w-fit'
className='w-fit min-w-36'
titleClassName='p-0! justify-self-end'
>
{children}
@@ -0,0 +1,29 @@
import { ReactNode } from 'react';
import { cn } from '@/lib/helper';
interface RowOptionsMenuWrapperProps {
children?: ReactNode;
type: 'dropdown' | 'collapse';
}
const RowOptionsMenuWrapper = ({
children,
type,
}: RowOptionsMenuWrapperProps) => {
return (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content mr-2': type === 'dropdown',
'w-fit ml-auto mt-2': type === 'collapse',
},
'p-2.5 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<div className='flex flex-col gap-1'>{children}</div>
</div>
);
};
export default RowOptionsMenuWrapper;
+4 -13
View File
@@ -1,6 +1,6 @@
import { Icon } from '@iconify/react';
import Button from '../Button';
import { cn } from '@/lib/helper';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
interface TableRowOptionsProps {
type?: 'dropdown' | 'collapse';
@@ -21,16 +21,7 @@ export const TableRowOptions = ({
showEdit = true,
showDelete = true,
}: TableRowOptionsProps) => (
<div
tabIndex={type === 'dropdown' ? 0 : undefined}
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<RowOptionsMenuWrapper type={type}>
<Button
href={`${basePath}/detail/?${queryParam}=${recordId}`}
variant='ghost'
@@ -56,7 +47,7 @@ export const TableRowOptions = ({
onClick={onDelete}
variant='ghost'
color='error'
className='text-error hover:text-inherit justify-start text-sm'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='mdi:delete-outline'
@@ -67,5 +58,5 @@ export const TableRowOptions = ({
Delete
</Button>
)}
</div>
</RowOptionsMenuWrapper>
);
+7 -2
View File
@@ -18,8 +18,13 @@ export const TableToolbar = ({ addButton, search }: TableToolbarProps) => {
return (
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
{addButton && (
<div className='flex flex-row'>
<Button href={addButton.href} color='primary'>
<div className='w-full flex flex-row'>
<Button
href={addButton.href}
variant='outline'
color='primary'
className='w-full sm:w-fit'
>
<Icon icon='ic:round-plus' width={24} height={24} />
{addButton.label}
</Button>