mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE): Add checkbox multi-select and components prop
This commit is contained in:
@@ -35,6 +35,7 @@ interface SelectInputBaseProps<T = OptionType> {
|
||||
bottomLabel?: ReactNode;
|
||||
options: T[];
|
||||
optionComponent?: OptionComponent<T>;
|
||||
components?: Partial<typeof ReactSelectComponents>;
|
||||
isDisabled?: boolean;
|
||||
isLoading?: boolean;
|
||||
isClearable?: boolean;
|
||||
@@ -56,9 +57,12 @@ interface SelectInputBaseProps<T = OptionType> {
|
||||
onInputChange?: (search: string) => void;
|
||||
startAdornment?: ReactNode;
|
||||
menuPortalTarget?: HTMLElement | null;
|
||||
closeMenuOnSelect?: boolean;
|
||||
hideSelectedOptions?: boolean;
|
||||
}
|
||||
|
||||
interface SelectInputProps<T = OptionType> extends SelectInputBaseProps<T> {
|
||||
export interface SelectInputProps<T = OptionType>
|
||||
extends SelectInputBaseProps<T> {
|
||||
createables?: boolean;
|
||||
value?: T | T[] | null;
|
||||
onChange?: (val: T | T[] | null) => void;
|
||||
@@ -101,6 +105,7 @@ const SelectInput = <T extends OptionType>(props: SelectInputProps<T>) => {
|
||||
onChange,
|
||||
options,
|
||||
optionComponent,
|
||||
components: customComponents,
|
||||
isDisabled,
|
||||
isLoading,
|
||||
isClearable,
|
||||
@@ -119,6 +124,8 @@ const SelectInput = <T extends OptionType>(props: SelectInputProps<T>) => {
|
||||
onInputChange,
|
||||
startAdornment,
|
||||
menuPortalTarget,
|
||||
closeMenuOnSelect,
|
||||
hideSelectedOptions,
|
||||
} = props;
|
||||
|
||||
const [internalInputValue, setInternalInputValue] = useState('');
|
||||
@@ -128,14 +135,18 @@ const SelectInput = <T extends OptionType>(props: SelectInputProps<T>) => {
|
||||
|
||||
const components = useMemo(() => {
|
||||
const base = isAnimated ? animatedComponents : {};
|
||||
const customComponents = { ...base, IndicatorSeparator: () => null };
|
||||
const mergedComponents = { ...base, IndicatorSeparator: () => null };
|
||||
|
||||
if (startAdornment) {
|
||||
customComponents.Control = CustomControl;
|
||||
mergedComponents.Control = CustomControl;
|
||||
}
|
||||
|
||||
return customComponents;
|
||||
}, [isAnimated, startAdornment]);
|
||||
if (customComponents) {
|
||||
Object.assign(mergedComponents, customComponents);
|
||||
}
|
||||
|
||||
return mergedComponents;
|
||||
}, [isAnimated, startAdornment, customComponents]);
|
||||
|
||||
const internalInputChangeHandler = (val: string, meta: InputActionMeta) => {
|
||||
if (meta.action === 'input-change') setInternalInputValue(val);
|
||||
@@ -205,6 +216,8 @@ const SelectInput = <T extends OptionType>(props: SelectInputProps<T>) => {
|
||||
isRtl={isRtl}
|
||||
isSearchable={isSearchable}
|
||||
placeholder={placeholder}
|
||||
closeMenuOnSelect={closeMenuOnSelect}
|
||||
hideSelectedOptions={hideSelectedOptions}
|
||||
className={cn('w-full', className?.select)}
|
||||
classNames={{
|
||||
...(!startAdornment && {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
'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 SelectInputCheckboxProps<T = OptionType>
|
||||
extends Omit<
|
||||
SelectInputProps<T>,
|
||||
'closeMenuOnSelect' | 'hideSelectedOptions' | 'optionComponent'
|
||||
> {
|
||||
closeMenuOnSelect?: boolean;
|
||||
hideSelectedOptions?: boolean;
|
||||
}
|
||||
|
||||
const CheckboxOption = <
|
||||
T extends OptionType,
|
||||
IsMulti extends boolean,
|
||||
Group extends GroupBase<T>,
|
||||
>(
|
||||
props: OptionProps<T, IsMulti, Group>
|
||||
) => {
|
||||
const { isSelected, label, innerRef, innerProps, className } = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={innerRef}
|
||||
{...innerProps}
|
||||
className={cn(
|
||||
'flex items-center gap-2 px-3 py-2 cursor-pointer',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type='checkbox'
|
||||
checked={isSelected}
|
||||
onChange={() => null}
|
||||
className='checkbox checkbox-sm checkbox-primary pointer-events-none'
|
||||
/>
|
||||
<label className='cursor-pointer flex-1 select-none'>{label}</label>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const SelectInputCheckbox = <T extends OptionType>(
|
||||
props: SelectInputCheckboxProps<T>
|
||||
) => {
|
||||
const {
|
||||
closeMenuOnSelect = false,
|
||||
hideSelectedOptions = false,
|
||||
isMulti = true,
|
||||
className,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
const customComponents = useMemo(() => {
|
||||
return {
|
||||
Option: CheckboxOption as typeof ReactSelectComponents.Option,
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SelectInput<T>
|
||||
{...restProps}
|
||||
isMulti={isMulti}
|
||||
closeMenuOnSelect={closeMenuOnSelect}
|
||||
hideSelectedOptions={hideSelectedOptions}
|
||||
className={{
|
||||
...className,
|
||||
select: cn(className?.select, 'select-checkbox'),
|
||||
}}
|
||||
components={customComponents}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectInputCheckbox;
|
||||
@@ -7,6 +7,7 @@ import SelectInput, {
|
||||
useSelect,
|
||||
OptionType,
|
||||
} from '@/components/input/SelectInput';
|
||||
import SelectInputCheckbox from '@/components/input/SelectInputCheckbox';
|
||||
import DateInput from '@/components/input/DateInput';
|
||||
import { CustomerApi } from '@/services/api/master-data';
|
||||
import { FinanceApi } from '@/services/api/report/finance-report';
|
||||
@@ -608,10 +609,9 @@ const CustomerPaymentTab = () => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<SelectInput
|
||||
<SelectInputCheckbox
|
||||
label='Customer'
|
||||
placeholder='Pilih Customer'
|
||||
isMulti
|
||||
options={customerOptions}
|
||||
value={filterCustomer}
|
||||
onChange={(val) => {
|
||||
|
||||
Reference in New Issue
Block a user