-
-
- {isError ? (
-
- ) : !isReady ? (
-
- ) : (
-
-
-
-
-
- options={activityOptionsData.activities}
- selectedValues={activitySelection.selectedValues}
- onSelectionChange={activitySelection.handleActivityChange}
- keyExtractor={(option) => option.code}
- selectionMode="single"
- buttonSize="large"
- layout="grid-2"
- />
-
- {selectedActivityLabel && (
-
-
-
- )}
-
+
+
+
+
+
+
+
-
-
+
-
- title={activityOptionsData.categories[0].nameKr}
- titleSize="small"
- hasBorder={true}
- options={activityOptionsData.categories[0].furnitures}
- selectedValues={categorySelections.bed.selectedValues}
- onSelectionChange={categorySelections.bed.handleChange}
- keyExtractor={(option) => option.id!}
- selectionMode="single"
- buttonSize="xsmall"
- layout="grid-4"
- buttonStatuses={categorySelections.bed.furnitureStatus}
- />
-
-
- title={activityOptionsData.categories[1].nameKr}
- titleSize="small"
- hasBorder={true}
- options={activityOptionsData.categories[1].furnitures}
- selectedValues={categorySelections.sofa.selectedValues}
- onSelectionChange={categorySelections.sofa.handleChange}
- keyExtractor={(option) => option.id!}
- selectionMode="single"
- buttonSize="medium"
- layout="grid-2"
- buttonStatuses={categorySelections.sofa.furnitureStatus}
- />
-
-
- title={activityOptionsData.categories[2].nameKr}
- titleSize="small"
- options={activityOptionsData.categories[2].furnitures}
- selectedValues={categorySelections.storage.selectedValues}
- onSelectionChange={categorySelections.storage.handleChange}
- keyExtractor={(option) => option.id!}
- selectionMode="multiple"
- buttonSize="large"
- layout="grid-2"
- buttonStatuses={categorySelections.storage.furnitureStatus}
+ caption="선택한 가구들로 이미지를 생성해드려요. (최대 6개)"
/>
-
-
- title={activityOptionsData.categories[3].nameKr}
- titleSize="small"
- options={activityOptionsData.categories[3].furnitures}
- selectedValues={categorySelections.table.selectedValues}
- onSelectionChange={categorySelections.table.handleChange}
- keyExtractor={(option) => option.id!}
- selectionMode="multiple"
- buttonSize="small"
- layout="grid-3"
- buttonStatuses={categorySelections.table.furnitureStatus}
- />
-
-
- title={activityOptionsData.categories[4].nameKr}
- titleSize="small"
- options={activityOptionsData.categories[4].furnitures}
- selectedValues={categorySelections.selective.selectedValues}
- onSelectionChange={categorySelections.selective.handleChange}
- keyExtractor={(option) => option.id!}
- selectionMode="multiple"
- buttonSize="large"
- layout="grid-2"
- buttonStatuses={categorySelections.selective.furnitureStatus}
- />
-
-
-
-
- 이미지 생성하기
-
+
+ {/* TODO: 추후 Chip 최신화하기 (아이콘 포함 Chip 반영) */}
+ {categories.map((category) => {
+ const selection = selectionByNameEng[category.nameEng];
+ if (!selection) return null;
+
+ return (
+
+
{category.nameKr}
+
+ {category.furnitures.map((furniture) => {
+ const isSelected = selection.selectedValues.includes(
+ furniture.id
+ );
+ const status = selection.furnitureStatus.find(
+ (s) => s.id === furniture.id
+ );
+ const isRequired =
+ globalConstraints.isRequiredFurniture(furniture.id);
+
+ return (
+
+ ) : undefined
+ }
+ onClick={() =>
+ selection.toggleFurniture(furniture.id)
+ }
+ >
+ {furniture.label}
+
+ );
+ })}
+
+
+ );
+ })}
+
+ )}
+
+
+ {selectedActivityLabel && (
+
)}
diff --git a/src/pages/imageSetup/steps/activityInfo/ActivityTypeSheet.css.ts b/src/pages/imageSetup/steps/activityInfo/ActivityTypeSheet.css.ts
new file mode 100644
index 000000000..8daf8cb13
--- /dev/null
+++ b/src/pages/imageSetup/steps/activityInfo/ActivityTypeSheet.css.ts
@@ -0,0 +1,96 @@
+import { style } from '@vanilla-extract/css';
+import { recipe } from '@vanilla-extract/recipes';
+
+import { colorVars } from '@styles/tokensV2/color.css';
+import { fontVars } from '@styles/tokensV2/font.css';
+import { unitVars } from '@styles/tokensV2/unit.css';
+
+export const contents = style({
+ display: 'flex',
+ flexDirection: 'column',
+ gap: unitVars.unit.gapPadding['500'],
+ width: '100%',
+});
+
+export const radioList = style({
+ display: 'flex',
+ flexDirection: 'column',
+ gap: unitVars.unit.gapPadding['100'],
+ width: '100%',
+});
+
+export const radioItem = recipe({
+ base: {
+ display: 'flex',
+ alignItems: 'center',
+ transition: 'transform 120ms ease, background-color 120ms ease',
+ border: 'none',
+ borderRadius: unitVars.unit.radius.full,
+ cursor: 'pointer',
+ padding: `${unitVars.unit.gapPadding['200']} ${unitVars.unit.gapPadding['400']}`,
+ width: '100%',
+ minWidth: '6.4rem',
+ height: '4.4rem',
+ font: 'inherit',
+ selectors: {
+ '&:active': {
+ transform: 'scale(0.95)',
+ },
+ },
+ },
+ variants: {
+ selected: {
+ false: {
+ backgroundColor: colorVars.color.fill.inverse,
+ },
+ true: {
+ backgroundColor: colorVars.color.fill.weak,
+ },
+ },
+ },
+});
+
+export const radioContents = style({
+ display: 'flex',
+ alignItems: 'center',
+ gap: unitVars.unit.gapPadding['100'],
+});
+
+export const radioLabel = style({
+ ...fontVars.font.body_r_14,
+ color: colorVars.color.text.primary,
+});
+
+export const divider = recipe({
+ base: {
+ borderRadius: '50%',
+ width: '0.3rem',
+ height: '0.3rem',
+ },
+ variants: {
+ selected: {
+ false: {
+ backgroundColor: colorVars.color.text.tertiary,
+ },
+ true: {
+ backgroundColor: colorVars.color.text.secondary,
+ },
+ },
+ },
+});
+
+export const requiredLabel = recipe({
+ base: {
+ ...fontVars.font.body_r_14,
+ },
+ variants: {
+ selected: {
+ false: {
+ color: colorVars.color.text.tertiary,
+ },
+ true: {
+ color: colorVars.color.text.secondary,
+ },
+ },
+ },
+});
diff --git a/src/pages/imageSetup/steps/activityInfo/ActivityTypeSheet.tsx b/src/pages/imageSetup/steps/activityInfo/ActivityTypeSheet.tsx
new file mode 100644
index 000000000..6811a1dd3
--- /dev/null
+++ b/src/pages/imageSetup/steps/activityInfo/ActivityTypeSheet.tsx
@@ -0,0 +1,103 @@
+import { useState } from 'react';
+
+import DragHandleBottomSheet from '@components/v2/bottomSheet/DragHandleBottomSheet';
+import ActionButton from '@components/v2/button/actionButton/ActionButton';
+import Icon from '@components/v2/icon/Icon';
+import TextHeading from '@components/v2/textHeading/TextHeading';
+
+import { getActivityIconName } from './activityIcons';
+import * as styles from './ActivityTypeSheet.css';
+
+import type { ActivityItem } from '../../types/apis/activityInfo';
+
+interface ActivityTypeSheetProps {
+ open: boolean;
+ activities: ActivityItem[];
+ selectedActivityCode?: string;
+ onConfirm: (activityCode: string) => void;
+ onClose: () => void;
+}
+
+const ActivityTypeSheet = ({
+ open,
+ activities,
+ selectedActivityCode,
+ onConfirm,
+ onClose,
+}: ActivityTypeSheetProps) => {
+ // 로컬 선택 상태 (확인 버튼 클릭 전까지 context에 미반영)
+ const [localSelected, setLocalSelected] = useState
(
+ selectedActivityCode
+ );
+
+ const handleConfirm = () => {
+ if (!localSelected) return;
+ onConfirm(localSelected);
+ };
+
+ return (
+
+
+
+ {activities.map((activity) => {
+ const isSelected = localSelected === activity.code;
+ const iconName = getActivityIconName(
+ activity.code,
+ isSelected ? 'black' : 'gray'
+ );
+ const requiredFurnitureLabel = activity.furnitures[0]?.label;
+
+ return (
+
+ );
+ })}
+
+
+ }
+ primaryButton={
+