diff --git a/package-lock.json b/package-lock.json index d108e6bb..c7a7af78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4463,7 +4463,6 @@ "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" } @@ -4474,7 +4473,6 @@ "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -4547,7 +4545,6 @@ "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", @@ -5071,7 +5068,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -6002,8 +5998,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/d3-array": { "version": "3.2.4", @@ -6430,8 +6425,7 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/embla-carousel-react": { "version": "8.6.0", @@ -6701,7 +6695,6 @@ "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -6875,7 +6868,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -8508,7 +8500,6 @@ "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.4.tgz", "integrity": "sha512-dc6oQ8y37rRcHn316s4ngz/nOjayLF/FFxBF4V9zamQKRqXxyiH1zagkCdktdWhtoQId5K20xt1lB90XzkB+hQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.28.4", "fast-png": "^6.2.0", @@ -9961,7 +9952,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -9992,7 +9982,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -10060,8 +10049,7 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/react-number-format": { "version": "5.4.4", @@ -10078,7 +10066,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -10291,8 +10278,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -11205,7 +11191,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -11391,7 +11376,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/src/components/input/SelectInput.tsx b/src/components/input/SelectInput.tsx index 9cc9fda5..2571efc5 100644 --- a/src/components/input/SelectInput.tsx +++ b/src/components/input/SelectInput.tsx @@ -312,6 +312,12 @@ const SelectInput = (props: SelectInputProps) => { } styles={{ menuPortal: (base) => ({ ...base, zIndex: 9999 }), + multiValue(base) { + return { + ...base, + borderRadius: '8px', + }; + }, }} onMenuScrollToBottom={onMenuScrollToBottom} /> diff --git a/src/components/input/SelectInputCheckbox.tsx b/src/components/input/SelectInputCheckbox.tsx index 0827a70a..24125204 100644 --- a/src/components/input/SelectInputCheckbox.tsx +++ b/src/components/input/SelectInputCheckbox.tsx @@ -40,7 +40,7 @@ const CheckboxOption = < type='checkbox' checked={isSelected} onChange={() => null} - className='checkbox checkbox-sm checkbox-primary pointer-events-none' + className='checkbox checkbox-sm rounded checkbox-primary pointer-events-none' /> diff --git a/src/components/input/SelectInputRadio.tsx b/src/components/input/SelectInputRadio.tsx new file mode 100644 index 00000000..73608931 --- /dev/null +++ b/src/components/input/SelectInputRadio.tsx @@ -0,0 +1,70 @@ +'use client'; + +import { useMemo } from 'react'; +import { + OptionProps, + GroupBase, + components as ReactSelectComponents, +} from 'react-select'; +import SelectInput, { OptionType, SelectInputProps } from './SelectInput'; +import { cn } from '@/lib/helper'; + +interface SelectInputRadioProps + extends Omit, 'closeMenuOnSelect' | 'optionComponent'> { + closeMenuOnSelect?: boolean; +} + +const RadioOption = < + T extends OptionType, + IsMulti extends boolean, + Group extends GroupBase, +>( + props: OptionProps +) => { + const { isSelected, label, innerRef, innerProps, className } = props; + + return ( +
+ null} + className='radio radio-sm radio-primary pointer-events-none' + /> + +
+ ); +}; + +const SelectInputRadio = ( + props: SelectInputRadioProps +) => { + const { closeMenuOnSelect = true, className, ...restProps } = props; + + const customComponents = useMemo(() => { + return { + Option: RadioOption as typeof ReactSelectComponents.Option, + }; + }, []); + + return ( + + {...restProps} + closeMenuOnSelect={closeMenuOnSelect} + className={{ + ...className, + select: cn(className?.select, 'select-radio'), + }} + components={customComponents} + /> + ); +}; + +export default SelectInputRadio; diff --git a/src/components/pages/closing/sale/SalesReportTable.tsx b/src/components/pages/closing/sale/SalesReportTable.tsx index 6ddd9e4f..99868984 100644 --- a/src/components/pages/closing/sale/SalesReportTable.tsx +++ b/src/components/pages/closing/sale/SalesReportTable.tsx @@ -112,12 +112,16 @@ const SalesReportTable = ({
Total Penjualan
), }, - // { - // id: 'age', - // accessorKey: 'age', - // header: 'Umur', - // cell: (props) => props.getValue() || '-', - // }, + { + id: 'age', + accessorKey: 'age', + header: 'Umur', + cell: (props) => { + const age = props.row.original.age; + const week = props.row.original.week; + return age && week ? `${age} hari (${week} minggu)` : '-'; + }, + }, { id: 'do_number', accessorKey: 'do_number', diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index 079b082c..c2b62473 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -8,7 +8,7 @@ import SelectInput, { OptionType, useSelect, } from '@/components/input/SelectInput'; -import { useState, useEffect, useRef } from 'react'; +import { useState, useEffect, useRef, useCallback } from 'react'; import useSWR from 'swr'; import { DashboardApi } from '@/services/api/dashboard'; import { useFormik } from 'formik'; @@ -38,6 +38,8 @@ import Dropdown from '@/components/Dropdown'; import Menu from '@/components/menu/Menu'; import MenuItem from '@/components/menu/MenuItem'; import { useDashboardStore } from '@/stores/dashboard'; +import SelectInputRadio from '@/components/input/SelectInputRadio'; +import SelectInputCheckbox from '@/components/input/SelectInputCheckbox'; // Helper function to normalize values to array const normalizeToArray = ( @@ -89,7 +91,6 @@ const DashboardProduction = () => { isLoadingOptions: isLoadingFlockOptions, loadMore: loadMoreFlock, } = useSelect(ProjectFlockApi.basePath, 'id', 'flock_name', '', { - limit: 'limit', location_id: selectedLocationIds ? selectedLocationIds.toString() : '', }); const { @@ -97,16 +98,13 @@ const DashboardProduction = () => { options: locationOptions, isLoadingOptions: isLoadingLocationOptions, loadMore: loadMoreLocation, - } = useSelect(LocationApi.basePath, 'id', 'name', '', { - limit: 'limit', - }); + } = useSelect(LocationApi.basePath, 'id', 'name'); const { setInputValue: setInputValueKandang, options: kandangOptions, isLoadingOptions: isLoadingKandangOptions, loadMore: loadMoreKandang, } = useSelect(KandangApi.basePath, 'id', 'name', '', { - limit: 'limit', location_id: selectedLocationIds ? selectedLocationIds.toString() : '', }); const comparisonTypeOptions = [ @@ -118,17 +116,18 @@ const DashboardProduction = () => { // ===== FORMIK ===== const formik = useFormik({ initialValues: { - startDate: filterValues.startDate || '', - endDate: filterValues.endDate || '', - flock: filterValues.flock || ([] as OptionType[]), - location: filterValues.location || ([] as OptionType[]), - kandang: filterValues.kandang || ([] as OptionType[]), - analysisMode: filterValues.analysisMode || analysisMode, - comparisonType: filterValues.comparisonType || '', - locationIds: filterValues.locationIds || [], - flockIds: filterValues.flockIds || [], - kandangIds: filterValues.kandangIds || [], + startDate: filterValues.startDate ?? '', + endDate: filterValues.endDate ?? '', + flock: filterValues.flock ?? ([] as OptionType[]), + location: filterValues.location ?? ([] as OptionType[]), + kandang: filterValues.kandang ?? ([] as OptionType[]), + analysisMode: filterValues.analysisMode ?? analysisMode, + comparisonType: filterValues.comparisonType ?? '', + locationIds: filterValues.locationIds ?? [], + flockIds: filterValues.flockIds ?? [], + kandangIds: filterValues.kandangIds ?? [], } as DashboardFilterType, + enableReinitialize: true, validationSchema: getDashboardFilterSchema(analysisMode), onSubmit: (values) => { // Save filter values to store @@ -146,13 +145,13 @@ const DashboardProduction = () => { }, }); - const handleResetFilter = () => { + const handleResetFilter = useCallback(() => { formik.resetForm(); resetFilterValues(); // Clear stored filter values setAnalysisMode('OVERVIEW'); setEndpointUrl('/dashboards'); setSelectedLocationIds([]); - }; + }, [resetFilterValues, filterValues, selectedLocationIds]); const handleApplyFilter = (values: DashboardFilter) => { // Build query params object, only include non-empty values @@ -413,7 +412,7 @@ const DashboardProduction = () => { {formik.values.analysisMode === 'COMPARISON' && (
- option.value === formik.values.comparisonType @@ -437,32 +436,65 @@ const DashboardProduction = () => { {/* Location */}
- { - formik.setFieldValue('location', selected); - // Update selectedLocationIds for kandang filter - setSelectedLocationIds(normalizeToArray(selected)); - // Reset dependent fields when location changes - formik.setFieldValue('flock', []); - formik.setFieldValue('kandang', []); - }} - errorMessage={formik.errors.location as string} - options={locationOptions} - isLoading={isLoadingLocationOptions} - isMulti={ - comparisonTypeOptions.find( - (option) => option.value === formik.values.comparisonType - )?.value === 'FARM' - } - isError={ - Boolean(formik.errors.location) && - Boolean(formik.touched.location) - } - /> + {comparisonTypeOptions.find( + (option) => option.value === formik.values.comparisonType + )?.value === 'FARM' ? ( + { + formik.setFieldValue('location', selected); + // Update selectedLocationIds for kandang filter + setSelectedLocationIds(normalizeToArray(selected)); + // Reset dependent fields when location changes + formik.setFieldValue('flock', []); + formik.setFieldValue('kandang', []); + }} + errorMessage={formik.errors.location as string} + options={locationOptions} + isLoading={isLoadingLocationOptions} + isError={ + Boolean(formik.errors.location) && + Boolean(formik.touched.location) + } + /> + ) : ( + { + formik.setFieldValue('location', selected); + // Update selectedLocationIds for kandang filter + setSelectedLocationIds(normalizeToArray(selected)); + // Reset dependent fields when location changes + formik.setFieldValue('flock', []); + formik.setFieldValue('kandang', []); + }} + errorMessage={formik.errors.location as string} + options={locationOptions} + isLoading={isLoadingLocationOptions} + isError={ + Boolean(formik.errors.location) && + Boolean(formik.touched.location) + } + /> + )}
{/* Flock */} @@ -474,27 +506,55 @@ const DashboardProduction = () => { ) ) && (
- - formik.setFieldValue('flock', selected) - } - errorMessage={formik.errors.flock as string} - onInputChange={setInputValueFlock} - onMenuScrollToBottom={loadMoreFlock} - options={flockOptions} - isLoading={isLoadingFlockOptions} - isMulti={ - comparisonTypeOptions.find( - (option) => option.value === formik.values.comparisonType - )?.value === 'FLOCK' - } - isError={ - Boolean(formik.errors.flock) && - Boolean(formik.touched.flock) - } - /> + {comparisonTypeOptions.find( + (option) => option.value === formik.values.comparisonType + )?.value === 'FLOCK' ? ( + + formik.setFieldValue('flock', selected) + } + errorMessage={formik.errors.flock as string} + onInputChange={setInputValueFlock} + onMenuScrollToBottom={loadMoreFlock} + options={flockOptions} + isLoading={isLoadingFlockOptions} + isError={ + Boolean(formik.errors.flock) && + Boolean(formik.touched.flock) + } + /> + ) : ( + + formik.setFieldValue('flock', selected) + } + errorMessage={formik.errors.flock as string} + onInputChange={setInputValueFlock} + onMenuScrollToBottom={loadMoreFlock} + options={flockOptions} + isLoading={isLoadingFlockOptions} + isError={ + Boolean(formik.errors.flock) && + Boolean(formik.touched.flock) + } + /> + )}
)} @@ -504,27 +564,55 @@ const DashboardProduction = () => { !(formik.values.comparisonType === 'KANDANG') ) && (
- - formik.setFieldValue('kandang', selected) - } - errorMessage={formik.errors.kandang as string} - onInputChange={setInputValueKandang} - onMenuScrollToBottom={loadMoreKandang} - options={kandangOptions} - isLoading={isLoadingKandangOptions} - isMulti={ - comparisonTypeOptions.find( - (option) => option.value === formik.values.comparisonType - )?.value === 'KANDANG' - } - isError={ - Boolean(formik.errors.kandang) && - Boolean(formik.touched.kandang) - } - /> + {comparisonTypeOptions.find( + (option) => option.value === formik.values.comparisonType + )?.value === 'KANDANG' ? ( + + formik.setFieldValue('kandang', selected) + } + errorMessage={formik.errors.kandang as string} + onInputChange={setInputValueKandang} + onMenuScrollToBottom={loadMoreKandang} + options={kandangOptions} + isLoading={isLoadingKandangOptions} + isError={ + Boolean(formik.errors.kandang) && + Boolean(formik.touched.kandang) + } + /> + ) : ( + + formik.setFieldValue('kandang', selected) + } + errorMessage={formik.errors.kandang as string} + onInputChange={setInputValueKandang} + onMenuScrollToBottom={loadMoreKandang} + options={kandangOptions} + isLoading={isLoadingKandangOptions} + isError={ + Boolean(formik.errors.kandang) && + Boolean(formik.touched.kandang) + } + /> + )}
)} diff --git a/src/components/pages/finance/add/FormFinanceAdd.tsx b/src/components/pages/finance/add/FormFinanceAdd.tsx index 168d306a..4189521e 100644 --- a/src/components/pages/finance/add/FormFinanceAdd.tsx +++ b/src/components/pages/finance/add/FormFinanceAdd.tsx @@ -54,9 +54,6 @@ const FormFinanceAdd = ({ }: FormFinanceAddProps) => { const router = useRouter(); const [serverErrorMessage, setServerErrorMessage] = useState(''); - const [isSupplier, setIsSupplier] = useState( - initialValues?.party?.type === 'SUPPLIER' - ); // ===== Formik ===== const formikInitialValues = useMemo((): FinanceFormValues => { @@ -215,7 +212,7 @@ const FormFinanceAdd = ({ ? formik.errors.party_type_option : '' } - isDisabled={type === 'edit' || isSupplier} + isDisabled={type === 'edit'} required isClearable /> @@ -254,7 +251,7 @@ const FormFinanceAdd = ({ } required isClearable - isDisabled={!formik.values.party_type_option?.value || isSupplier} + isDisabled={!formik.values.party_type_option?.value} />