diff --git a/src/components/input/SelectInput.tsx b/src/components/input/SelectInput.tsx index 419ed314..2a3ff98c 100644 --- a/src/components/input/SelectInput.tsx +++ b/src/components/input/SelectInput.tsx @@ -54,6 +54,9 @@ interface SelectInputBaseProps { wrapper?: string; label?: string; select?: string; + inputPrefix?: string; + inputSuffix?: string; + inputPrefixSuffixWrapper?: string; }; isError?: boolean; errorMessage?: string; @@ -62,6 +65,8 @@ interface SelectInputBaseProps { delay?: number; onInputChange?: (search: string) => void; startAdornment?: ReactNode; + inputPrefix?: ReactNode; + inputSuffix?: ReactNode; menuPortalTarget?: HTMLElement | null; closeMenuOnSelect?: boolean; hideSelectedOptions?: boolean; @@ -153,6 +158,8 @@ const SelectInput = (props: SelectInputProps) => { createables = false, onInputChange, startAdornment, + inputPrefix, + inputSuffix, menuPortalTarget, closeMenuOnSelect, hideSelectedOptions, @@ -227,111 +234,261 @@ const SelectInput = (props: SelectInputProps) => { )} - > - instanceId='select' - value={value ?? (isMulti ? [] : null)} - onChange={onChange ? handleChange : undefined} - options={options} - menuIsOpen={openMenu} - inputValue={internalInputValue} - onInputChange={internalInputChangeHandler} - onMenuClose={() => setInternalInputValue('')} - isMulti={isMulti} - isDisabled={isDisabled || readOnly} - isLoading={isLoading} - isClearable={isClearable} - isRtl={isRtl} - isSearchable={isSearchable} - placeholder={placeholder} - closeMenuOnSelect={closeMenuOnSelect} - hideSelectedOptions={hideSelectedOptions} - className={cn('w-full', className?.select)} - classNames={{ - ...(!startAdornment && { - control: ({ isFocused, isDisabled }) => - cn('w-full rounded-lg! border bg-white transition-shadow', { - 'cursor-pointer!': !readOnly && !isDisabled, - 'border-red-500! ring-2 ring-red-200': isError, - 'border-indigo-500 ring-2 ring-indigo-200': isFocused, - 'border-base-content/10!': !isError && !isFocused, - 'bg-gray-100 text-gray-400 cursor-not-allowed': - isDisabled && !readOnly, - 'bg-transparent! cursor-not-allowed!': readOnly, + {inputPrefix || inputSuffix ? ( +
+ {inputPrefix && ( +
+ {inputPrefix} +
+ )} + + > + instanceId='select' + value={value ?? (isMulti ? [] : null)} + onChange={onChange ? handleChange : undefined} + options={options} + menuIsOpen={openMenu} + inputValue={internalInputValue} + onInputChange={internalInputChangeHandler} + onMenuClose={() => setInternalInputValue('')} + isMulti={isMulti} + isDisabled={isDisabled || readOnly} + isLoading={isLoading} + isClearable={isClearable} + isRtl={isRtl} + isSearchable={isSearchable} + placeholder={placeholder} + closeMenuOnSelect={closeMenuOnSelect} + hideSelectedOptions={hideSelectedOptions} + className={cn('w-full flex-1', className?.select)} + classNames={{ + ...(!startAdornment && { + control: ({ isFocused, isDisabled }) => + cn('w-full rounded-lg! border bg-white transition-shadow', { + 'cursor-pointer!': !readOnly && !isDisabled, + 'border-red-500! ring-2 ring-red-200': isError, + 'border-indigo-500 ring-2 ring-indigo-200': isFocused, + 'border-base-content/10!': !isError && !isFocused, + 'bg-gray-100 text-gray-400 cursor-not-allowed': + isDisabled && !readOnly, + 'bg-transparent! cursor-not-allowed!': readOnly, + 'rounded-l-none!': inputPrefix, + 'rounded-r-none!': inputSuffix, + }), + valueContainer: () => cn('flex-1 px-3! pr-2! py-2.5! gap-1'), }), - valueContainer: () => cn('flex-1 px-3! pr-2! py-2.5! gap-1'), - }), - placeholder: () => - cn({ - 'text-gray-400 text-sm leading-tight': !isError, - 'text-red-300!': isError, + placeholder: () => + cn({ + 'text-gray-400 text-sm leading-tight': !isError, + 'text-red-300!': isError, + }), + singleValue: () => + cn({ + 'm-0! text-gray-900 text-sm leading-tight': !isError, + 'text-error!': isError, + 'text-gray-900!': readOnly, + }), + input: () => cn('text-gray-900 m-0! p-0! text-sm leading-tight'), + indicatorsContainer: () => + cn('flex items-center gap-1 pr-3 py-2'), + dropdownIndicator: ({ isFocused }) => + cn('p-0! rounded hover:bg-gray-100', { + 'text-gray-900': isFocused, + 'text-gray-500': !isFocused, + 'text-error!': isError, + }), + clearIndicator: () => cn('p-0! rounded hover:bg-gray-100'), + menu: () => + cn( + 'border border-base-content/5 rounded-xl! bg-base-100 shadow-lg! my-1.5!' + ), + menuList: () => cn('p-0! max-h-60 overflow-auto'), + option: ({ isFocused, isSelected }) => + cn('px-3 py-2 rounded-md cursor-pointer!', { + 'bg-indigo-600 text-white': isFocused, + 'bg-blue-500!': isSelected, + 'text-gray-700': !isFocused && !isSelected, + }), + multiValue: ({ getValue, index }) => { + const selectedValues = getValue() as T[]; + return cn( + 'bg-base-200! rounded-lg! py-[3px] px-2.5 m-0! flex items-center gap-1! w-fit gap-2!', + selectedValues[index]?.className + ); + }, + multiValueRemove: () => cn('p-0! w-3 h-3'), + multiValueLabel: ({ getValue, index }) => { + const selectedValues = getValue() as T[]; + return cn( + 'p-0! text-base-content! text-xs!', + selectedValues[index]?.labelClassName + ); + }, + }} + components={{ + ...components, + ...(optionComponent ? { Option: optionComponent } : {}), + MenuList: CustomMenuList, + }} + {...(startAdornment && { + shouldShowAdornment, + startAdornment, + })} + menuPortalTarget={ + typeof document !== 'undefined' + ? (menuPortalTarget ?? document.body) + : undefined + } + styles={{ + menuPortal: (base) => ({ ...base, zIndex: 9999 }), + multiValue(base) { + return { + ...base, + borderRadius: '8px', + }; + }, + }} + onMenuScrollToBottom={onMenuScrollToBottom} + /> + + {inputSuffix && ( +
+ {inputSuffix} +
+ )} +
+ ) : ( + > + instanceId='select' + value={value ?? (isMulti ? [] : null)} + onChange={onChange ? handleChange : undefined} + options={options} + menuIsOpen={openMenu} + inputValue={internalInputValue} + onInputChange={internalInputChangeHandler} + onMenuClose={() => setInternalInputValue('')} + isMulti={isMulti} + isDisabled={isDisabled || readOnly} + isLoading={isLoading} + isClearable={isClearable} + isRtl={isRtl} + isSearchable={isSearchable} + placeholder={placeholder} + closeMenuOnSelect={closeMenuOnSelect} + hideSelectedOptions={hideSelectedOptions} + className={cn('w-full', className?.select)} + classNames={{ + ...(!startAdornment && { + control: ({ isFocused, isDisabled }) => + cn('w-full rounded-lg! border bg-white transition-shadow', { + 'cursor-pointer!': !readOnly && !isDisabled, + 'border-red-500! ring-2 ring-red-200': isError, + 'border-indigo-500 ring-2 ring-indigo-200': isFocused, + 'border-base-content/10!': !isError && !isFocused, + 'bg-gray-100 text-gray-400 cursor-not-allowed': + isDisabled && !readOnly, + 'bg-transparent! cursor-not-allowed!': readOnly, + }), + valueContainer: () => cn('flex-1 px-3! pr-2! py-2.5! gap-1'), }), - singleValue: () => - cn({ - 'm-0! text-gray-900 text-sm leading-tight': !isError, - 'text-error!': isError, - 'text-gray-900!': readOnly, - }), - input: () => cn('text-gray-900 m-0! p-0! text-sm leading-tight'), - indicatorsContainer: () => cn('flex items-center gap-1 pr-3 py-2'), - dropdownIndicator: ({ isFocused }) => - cn('p-0! rounded hover:bg-gray-100', { - 'text-gray-900': isFocused, - 'text-gray-500': !isFocused, - 'text-error!': isError, - }), - clearIndicator: () => cn('p-0! rounded hover:bg-gray-100'), - menu: () => - cn( - 'border border-base-content/5 rounded-xl! bg-base-100 shadow-lg! my-1.5!' - ), - menuList: () => cn('p-0! max-h-60 overflow-auto'), - option: ({ isFocused, isSelected }) => - cn('px-3 py-2 rounded-md cursor-pointer!', { - 'bg-indigo-600 text-white': isFocused, - 'bg-blue-500!': isSelected, - 'text-gray-700': !isFocused && !isSelected, - }), - multiValue: ({ getValue, index }) => { - const selectedValues = getValue() as T[]; - return cn( - 'bg-base-200! rounded-lg! py-[3px] px-2.5 m-0! flex items-center gap-1! w-fit gap-2!', - selectedValues[index]?.className - ); - }, - multiValueRemove: () => cn('p-0! w-3 h-3'), - multiValueLabel: ({ getValue, index }) => { - const selectedValues = getValue() as T[]; - return cn( - 'p-0! text-base-content! text-xs!', - selectedValues[index]?.labelClassName - ); - }, - }} - components={{ - ...components, - ...(optionComponent ? { Option: optionComponent } : {}), - MenuList: CustomMenuList, - }} - {...(startAdornment && { - shouldShowAdornment, - startAdornment, - })} - menuPortalTarget={ - typeof document !== 'undefined' - ? (menuPortalTarget ?? document.body) - : undefined - } - styles={{ - menuPortal: (base) => ({ ...base, zIndex: 9999 }), - multiValue(base) { - return { - ...base, - borderRadius: '8px', - }; - }, - }} - onMenuScrollToBottom={onMenuScrollToBottom} - /> + placeholder: () => + cn({ + 'text-gray-400 text-sm leading-tight': !isError, + 'text-red-300!': isError, + }), + singleValue: () => + cn({ + 'm-0! text-gray-900 text-sm leading-tight': !isError, + 'text-error!': isError, + 'text-gray-900!': readOnly, + }), + input: () => cn('text-gray-900 m-0! p-0! text-sm leading-tight'), + indicatorsContainer: () => cn('flex items-center gap-1 pr-3 py-2'), + dropdownIndicator: ({ isFocused }) => + cn('p-0! rounded hover:bg-gray-100', { + 'text-gray-900': isFocused, + 'text-gray-500': !isFocused, + 'text-error!': isError, + }), + clearIndicator: () => cn('p-0! rounded hover:bg-gray-100'), + menu: () => + cn( + 'border border-base-content/5 rounded-xl! bg-base-100 shadow-lg! my-1.5!' + ), + menuList: () => cn('p-0! max-h-60 overflow-auto'), + option: ({ isFocused, isSelected }) => + cn('px-3 py-2 rounded-md cursor-pointer!', { + 'bg-indigo-600 text-white': isFocused, + 'bg-blue-500!': isSelected, + 'text-gray-700': !isFocused && !isSelected, + }), + multiValue: ({ getValue, index }) => { + const selectedValues = getValue() as T[]; + return cn( + 'bg-base-200! rounded-lg! py-[3px] px-2.5 m-0! flex items-center gap-1! w-fit gap-2!', + selectedValues[index]?.className + ); + }, + multiValueRemove: () => cn('p-0! w-3 h-3'), + multiValueLabel: ({ getValue, index }) => { + const selectedValues = getValue() as T[]; + return cn( + 'p-0! text-base-content! text-xs!', + selectedValues[index]?.labelClassName + ); + }, + }} + components={{ + ...components, + ...(optionComponent ? { Option: optionComponent } : {}), + MenuList: CustomMenuList, + }} + {...(startAdornment && { + shouldShowAdornment, + startAdornment, + })} + menuPortalTarget={ + typeof document !== 'undefined' + ? (menuPortalTarget ?? document.body) + : undefined + } + styles={{ + menuPortal: (base) => ({ ...base, zIndex: 9999 }), + multiValue(base) { + return { + ...base, + borderRadius: '8px', + }; + }, + }} + onMenuScrollToBottom={onMenuScrollToBottom} + /> + )} {isError &&

{errorMessage}

} {!isError && bottomLabel && ( diff --git a/src/components/pages/inventory/movement/form/MovementForm.tsx b/src/components/pages/inventory/movement/form/MovementForm.tsx index a5a6cbf9..05d5b052 100644 --- a/src/components/pages/inventory/movement/form/MovementForm.tsx +++ b/src/components/pages/inventory/movement/form/MovementForm.tsx @@ -874,32 +874,15 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { (warehouseId: number) => { const stockInfo = warehouseStockMap.get(warehouseId); if (!stockInfo) { - return ( - - Kosong - - ); + return Kosong; } const { productCount } = stockInfo; - let color: 'neutral' | 'success' | 'warning' = 'neutral'; - if (productCount === 0) color = 'warning'; - else if (productCount > 0) color = 'success'; return ( - + Tersedia {productCount} produk - + ); }, [warehouseStockMap] @@ -1360,7 +1343,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { errorMessage={formik.errors.source_warehouse_id as string} isDisabled={type === 'detail'} isClearable - startAdornment={ + inputPrefix={ formik.values.source_warehouse_id ? getWarehouseStockAdornment( formik.values.source_warehouse_id @@ -1418,7 +1401,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { errorMessage={formik.errors.destination_warehouse_id as string} isDisabled={type === 'detail'} isClearable - startAdornment={ + inputPrefix={ formik.values.destination_warehouse_id ? getWarehouseStockAdornment( formik.values.destination_warehouse_id