File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
'use client';
import { FoxChip } from '@fox/core/components/fox-chip';
import { FoxChipArea } from '@fox/core/components/fox-chip-area';
import { FoxFormLabel } from '@fox/core/components/fox-form-label';
import { FoxHelperText } from '@fox/core/components/fox-helper-text';
import styles from './merchant-choice-chips.module.scss';
interface ChoiceOption {
value: string;
label: string;
}
interface MerchantChoiceChipsProps {
label: string;
/** 폼에 실릴 이름. 단일 선택은 값 하나, 복수 선택은 고른 순서대로 같은 이름이 반복된다. */
name: string;
options: readonly ChoiceOption[];
values: readonly string[];
onChange: (values: string[]) => void;
/** 넘기면 복수 선택이 되고 이 개수까지만 고를 수 있다. 없으면 단일 선택이다. */
maxSelected?: number;
required?: boolean;
optionalText?: string;
error?: string;
}
/**
* 기획 BO-MAL-002 ② · BO-MAL-004 ③ — 칩으로 고르는 선택지. 노출 상태·바우처 사용은 단일,
* 배지는 복수(잠정 최대 2)다.
*
* `FoxChip`의 check형은 `aria-pressed` 버튼이라 폼에 실리지 않는다 — 고른 값은 숨은 입력이
* 나른다. 복수 선택은 고른 순서를 지켜 싣는다(배지는 그 순서로 앱에 노출된다).
*/
export function MerchantChoiceChips({
label,
name,
options,
values,
onChange,
maxSelected,
required,
optionalText,
error,
}: MerchantChoiceChipsProps) {
const isMultiple = maxSelected !== undefined;
function toggle(value: string, checked: boolean) {
if (!isMultiple) {
if (checked) onChange([value]);
return;
}
if (!checked) {
onChange(values.filter((item) => item !== value));
return;
}
if (values.includes(value) || values.length >= maxSelected) {
return;
}
onChange([...values, value]);
}
return (
<div className={styles.field}>
<FoxFormLabel
as="span"
requirement={required ? 'required' : optionalText ? 'optional' : undefined}
optionalText={optionalText}
>
{label}
</FoxFormLabel>
<FoxChipArea size="md" label={label}>
{options.map((option) => {
const checked = values.includes(option.value);
const isFull = isMultiple && !checked && values.length >= maxSelected;
return (
<FoxChip
key={option.value}
type="check"
size="md"
label={option.label}
checked={checked}
disabled={isFull}
onCheckedChange={(next) => toggle(option.value, next)}
/>
);
})}
</FoxChipArea>
{values.map((value) => (
<input key={value} type="hidden" name={name} value={value} />
))}
{error && <FoxHelperText type="danger" message={error} />}
</div>
);
}