diff --git a/package-lock.json b/package-lock.json index 38844543..61da9724 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "cmdk": "^1.1.1", "embla-carousel-react": "^8.6.0", "formik": "^2.4.6", + "html-to-image": "^1.11.13", "input-otp": "^1.4.2", "jspdf": "^3.0.4", "jspdf-autotable": "^5.0.2", @@ -7380,6 +7381,12 @@ "integrity": "sha512-LgOWAkrN0rFaQpfdWBQlv/VhkOxb5AsBjk6NQVx4yEzWS923T07X0M1Y0VNko2H52HeSpZrZNNMJ0aFqsdVzQg==", "license": "ISC" }, + "node_modules/html-to-image": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.13.tgz", + "integrity": "sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==", + "license": "MIT" + }, "node_modules/html2canvas": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", diff --git a/package.json b/package.json index 3a775db2..981413b3 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "cmdk": "^1.1.1", "embla-carousel-react": "^8.6.0", "formik": "^2.4.6", + "html-to-image": "^1.11.13", "input-otp": "^1.4.2", "jspdf": "^3.0.4", "jspdf-autotable": "^5.0.2", diff --git a/src/app/expense/detail/edit/page.tsx b/src/app/expense/detail/edit/page.tsx index e254f01d..2fb33484 100644 --- a/src/app/expense/detail/edit/page.tsx +++ b/src/app/expense/detail/edit/page.tsx @@ -38,9 +38,11 @@ const ExpenseEditPage = () => { !isLoadingExpense && isResponseSuccess(expense) && expense.data.latest_approval.step_number !== 5 && + expense.data.latest_approval.step_number !== 6 && (expense.data.latest_approval.step_number === 1 || expense.data.latest_approval.step_number === 2 || - expense.data.latest_approval.step_number === 3); + expense.data.latest_approval.step_number === 3 || + expense.data.latest_approval.step_number === 4); if (!isLoadingExpense && !isExpenseCanBeEdited) { router.back(); diff --git a/src/app/finance/detail/page.tsx b/src/app/finance/detail/page.tsx index 1d20e9f5..b80e8acb 100644 --- a/src/app/finance/detail/page.tsx +++ b/src/app/finance/detail/page.tsx @@ -24,8 +24,6 @@ const FinanceDetailPage = () => { ); } - console.log(finance); - // if (!finance || isResponseError(finance)) { // router.replace('/404'); // return; diff --git a/src/components/Card.tsx b/src/components/Card.tsx index ff4c35f2..e04fa4c7 100644 --- a/src/components/Card.tsx +++ b/src/components/Card.tsx @@ -148,7 +148,11 @@ const Card = ({ const hasContent = children || actions || footer; const titleContent = ( -
+
{title &&

{title}

} {subtitle &&

{subtitle}

} @@ -156,7 +160,7 @@ const Card = ({ {collapsible && ( + ); +}; + +export default ButtonFilter; diff --git a/src/components/helper/form/FormErrors.tsx b/src/components/helper/form/FormErrors.tsx index 4b97d033..1fd7b58f 100644 --- a/src/components/helper/form/FormErrors.tsx +++ b/src/components/helper/form/FormErrors.tsx @@ -18,7 +18,7 @@ const AlertErrorList = ({ if (formErrorList.length === 0) return null; return ( - +
diff --git a/src/components/input/DateInput.tsx b/src/components/input/DateInput.tsx index 2d55fe6d..a424d723 100644 --- a/src/components/input/DateInput.tsx +++ b/src/components/input/DateInput.tsx @@ -113,7 +113,15 @@ const DateInput = ({ }; const handleSelectSingle = (selectedDate?: Date) => { - if (!selectedDate) return; + if (!selectedDate) { + setSelected(undefined); + setDisplayValue(''); + const syntheticEvent = { + target: { name, value: '' }, + } as unknown as React.ChangeEvent; + onChange?.(syntheticEvent); + return; + } if (minDate && selectedDate < minDate) { setInternalError(`Tanggal tidak boleh sebelum ${min}`); return; @@ -136,7 +144,15 @@ const DateInput = ({ }; const handleSelectRange = (range?: { from?: Date; to?: Date }) => { - if (!range) return; + if (!range) { + setSelectedRange({}); + setDisplayValue(''); + const syntheticEvent = { + target: { name, value: { from: '', to: '' } }, + } as unknown as React.ChangeEvent; + onChange?.(syntheticEvent); + return; + } setSelectedRange(range); const fromStr = range.from ? formatDate(range.from, 'DD/MM/YYYY') : ''; diff --git a/src/components/input/SelectInput.tsx b/src/components/input/SelectInput.tsx index d35e7589..9cc9fda5 100644 --- a/src/components/input/SelectInput.tsx +++ b/src/components/input/SelectInput.tsx @@ -9,15 +9,20 @@ import Select, { SingleValue, components as ReactSelectComponents, ControlProps, + MenuListProps, } from 'react-select'; import CreatableSelect from 'react-select/creatable'; import makeAnimated from 'react-select/animated'; import { useDebounce } from 'use-debounce'; import { cn, getByPath } from '@/lib/helper'; -import useSWR from 'swr'; +import useSWRInfinite from 'swr/infinite'; import { httpClientFetcher } from '@/services/http/client'; -import { BaseApiResponse } from '@/types/api/api-general'; -import { isResponseSuccess } from '@/lib/api-helper'; +import { + BaseApiResponse, + ErrorApiResponse, + SuccessApiResponse, +} from '@/types/api/api-general'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; export interface OptionType { value: string | number; @@ -35,6 +40,7 @@ interface SelectInputBaseProps { bottomLabel?: ReactNode; options: T[]; optionComponent?: OptionComponent; + components?: Partial; isDisabled?: boolean; isLoading?: boolean; isClearable?: boolean; @@ -56,9 +62,13 @@ interface SelectInputBaseProps { onInputChange?: (search: string) => void; startAdornment?: ReactNode; menuPortalTarget?: HTMLElement | null; + closeMenuOnSelect?: boolean; + hideSelectedOptions?: boolean; + onMenuScrollToBottom?: ((event: WheelEvent | TouchEvent) => void) | undefined; } -interface SelectInputProps extends SelectInputBaseProps { +export interface SelectInputProps + extends SelectInputBaseProps { createables?: boolean; value?: T | T[] | null; onChange?: (val: T | T[] | null) => void; @@ -93,6 +103,29 @@ const CustomControl = < ); }; +const CustomMenuList = < + Option, + IsMulti extends boolean, + Group extends GroupBase