첫 커밋

This commit is contained in:
focp212@naver.com
2025-09-05 15:36:48 +09:00
commit 05238b04c1
825 changed files with 176358 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
import clsx from 'clsx';
import { useEffect, useRef } from 'react';
export type ElementType<T> = T extends (infer U)[] ? U : never;
export interface RadioChangeProps<ValueType> {
event: React.ChangeEvent<HTMLInputElement>;
label?: string;
value: ValueType;
}
export interface SelectTemplateProps<ValueType> {
values?: ValueType[];
valueKey?: keyof ValueType;
labels?: string[];
selectedLabel?: string;
selectedValue?: string;
onRadioChange?: ({ event, label, value }: RadioChangeProps<ValueType>) => void;
}
export const SelectTemplate = ({
values = [],
valueKey,
labels = [],
selectedLabel,
selectedValue,
onRadioChange,
}: SelectTemplateProps<any>) => {
const refs = useRef<(HTMLLabelElement | null)[]>([]);
const handleRadioChange = ({ event, label, value }: RadioChangeProps<ElementType<typeof values>>) => {
onRadioChange?.({ event, label, value });
};
useEffect(() => {
const scrollIntoView = (array: any[], selected: string | undefined) => {
const index = array?.indexOf(selected ?? '');
if (index !== -1 && refs.current[index]) {
refs.current[index]?.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
};
scrollIntoView(labels, selectedLabel);
scrollIntoView(values, selectedValue);
}, [selectedLabel, labels, selectedValue, values]);
return (
<div
style={{ height: '100%', maxHeight: '50dvh', overflowY: 'auto' }}
className="show-scrollbar mx-[24px] pb-[30px] pt-[20px]"
>
{values?.map((value, index) => {
return (
<label
htmlFor={labels?.[index]}
key={labels?.[index]}
className={clsx('btm-sheet-btn block h-[52px] text-[15px]', {
'selected font-bold text-[#366FC4]':
selectedLabel === labels?.[index] ||
selectedValue === (valueKey ? values?.[index]?.[valueKey] : values?.[index]),
})}
>
<input
className="hidden"
type="radio"
id={labels?.[index]}
// name={name}
value={valueKey ? value?.[valueKey] : `${value}`}
onChange={(event) => handleRadioChange({
event,
label: labels?.[index],
value
})}
/>
{labels?.[index]}
<br />
</label>
);
})}
</div>
);
};

View File

@@ -0,0 +1,71 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { ElementType, Fragment, useEffect, useState } from 'react';
import { RegisterOptions, useFormContext, UseFormRegister } from 'react-hook-form';
import { BottomSheet } from '~/shared/ui/bottom-sheets/bottom-sheet';
import { SelectTemplate, RadioChangeProps } from '~/shared/ui/selects/select-template';
import { TextInput } from '~/shared/ui/text-input/text-input';
interface SelectProps {
placeholder: string;
labels: string[];
values: string[];
name: string;
option?: RegisterOptions<any>;
readOnly?: boolean;
onClick?: () => void;
register: UseFormRegister<any>;
classStr?: string;
}
export const Select = ({ placeholder, register, name, option, labels, values, classStr }: SelectProps) => {
const [isOpenBottomSheet, setIsOpenBottomSheet] = useState(false);
const handleCloseBottomSheet = () => {
setIsOpenBottomSheet(false);
if ((!value || value?.length < 0) && option?.required) {
setError(name, { type: 'required', message: option?.required.toString() ?? null });
}
};
const { setValue, clearErrors, watch, getValues, setError } = useFormContext();
const value = watch(name);
const defaultValue = getValues(name);
const selectedValue = watch(name, defaultValue);
const selectedLabel = labels[values.indexOf(selectedValue)];
const onInputClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
event.preventDefault();
setIsOpenBottomSheet(true);
};
const onRadioChange = ({ event }: RadioChangeProps<ElementType<typeof values>>) => {
setValue(name, event.target.value);
setIsOpenBottomSheet(false);
clearErrors(name);
};
useEffect(() => {
if (value?.length > 0) {
setValue(name, selectedValue);
}
}, []);
return (
<Fragment>
<TextInput
label={placeholder}
{...register(name)}
readOnly
onClick={onInputClick}
selectLabel={selectedLabel}
selectMode
classStr={classStr}
/>
<BottomSheet title={placeholder} open={isOpenBottomSheet} onClose={handleCloseBottomSheet}>
<SelectTemplate values={values} labels={labels} selectedLabel={selectedLabel} onRadioChange={onRadioChange} />
</BottomSheet>
</Fragment>
);
};