-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
daf6da0
commit fd31850
Showing
6 changed files
with
209 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
src/shared/EmotionButtonList/ui/EmotionButtonList.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import React from 'react'; | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import EmotionButtonList from './EmotionButtonList'; | ||
import { Emotions } from '../../../shared/model/EmotionEnum'; | ||
|
||
const meta: Meta<typeof EmotionButtonList> = { | ||
component: EmotionButtonList, | ||
title: 'Shared/EmotionButtonList', | ||
tags: ['autodocs'], | ||
argTypes: { | ||
isPrimary: { | ||
control: { type: 'boolean' }, | ||
description: '대표 감정 : true, 서브 감정 : false ', | ||
}, | ||
maxSelections: { | ||
control: { type: 'number' }, | ||
description: '사용자가 선택할 수 있는 최대 감정 버튼 개수', | ||
}, | ||
initialSelectedEmotions: { | ||
control: { | ||
type: 'array', | ||
options: Object.values(Emotions), | ||
}, | ||
description: '초기 선택된 감정 목록입니다.\n\n' + | ||
'배열의 크기가 maxSelections 수량보다 클 경우, 앞에서부터 maxSelections 수량만큼 설정됩니다.', | ||
}, | ||
onSelectionChange: { | ||
description: '선택된 감정 목록이 변경될 때 호출되는 콜백 함수', | ||
action: 'onSelectionChange', | ||
}, | ||
}, | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof EmotionButtonList>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
onSelectionChange: (selectedEmotions) => { | ||
console.log('selected:', selectedEmotions); | ||
}, | ||
maxSelections: 3, | ||
isPrimary: true, | ||
initialSelectedEmotions: [], | ||
}, | ||
parameters: { | ||
docs: { | ||
description: { | ||
story: '대표 감정을 선택하기 위한 모드입니다.', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
export const PrimaryMode_Selected: Story = { | ||
args: { | ||
onSelectionChange: (selectedEmotions) => { | ||
console.log('selected:', selectedEmotions); | ||
}, | ||
maxSelections: 3, | ||
isPrimary: true, | ||
initialSelectedEmotions: [Emotions.Happy, Emotions.Sad], | ||
}, | ||
parameters: { | ||
docs: { | ||
description: { | ||
story: '대표 감정을 선택하기 위한 모드입니다.\n\n' + | ||
'선택된 감정의 초기값을 설정할 수 있습니다.\n\n' + | ||
'단, 배열의 길이가 maxSelections보다 클 경우 맨 앞의 항목만 선택됩니다. (ex. 기뻐요, 슬퍼요 선택 => 기뻐요)', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
export const SubEmotionMode_Default: Story = { | ||
args: { | ||
onSelectionChange: (selectedEmotions) => { | ||
console.log('selected:', selectedEmotions); | ||
}, | ||
maxSelections: 3, | ||
isPrimary: false, | ||
initialSelectedEmotions: [], | ||
}, | ||
parameters: { | ||
docs: { | ||
description: { | ||
story: '서브 감정을 선택하기 위한 모드입니다. 초기 선택된 감정을 설정할 수 있습니다.\n\n' + | ||
'단, 배열의 길이가 maxSelections보다 클 경우 앞에서부터 maxSelections번째 항목까지 감정이 설정됩니다.\n\n' + | ||
'(ex) maxSelections = 3으로 설정', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
export const SubEmotionMode_Selected: Story = { | ||
args: { | ||
onSelectionChange: (selectedEmotions) => { | ||
console.log('selected:', selectedEmotions); | ||
}, | ||
maxSelections: 3, | ||
isPrimary: false, | ||
initialSelectedEmotions: [Emotions.Happy, Emotions.Sad, Emotions.Awkward, Emotions.Blank], | ||
}, | ||
parameters: { | ||
docs: { | ||
description: { | ||
story: '서브 감정을 선택하기 위한 모드입니다.\n\n' + | ||
'initialSelectedEmotions에 감정 키워드 배열을 넘기면 초기 설정이 가능합니다.\n\n' + | ||
'배열의 길이가 maxSelections를 초과할 경우, 앞에서부터 maxSelections 개수만큼 설정됩니다. (ex. 기뻐요, 슬퍼요, 곤란해요 초기값 설정)', | ||
}, | ||
}, | ||
}, | ||
}; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
import { StyledEmotionButtonList } from './EmotionButtonList.styled'; | ||
import EmotionButton from '../../EmotionButton/ui/EmotionButton'; | ||
import { Emotions } from '../../model/EmotionEnum'; | ||
|
||
interface EmotionListProps { | ||
isPrimary: boolean; | ||
maxSelections: number; | ||
initialSelectedEmotions: Emotions[]; | ||
onSelectionChange: (selectedEmotions: Emotions[]) => void; | ||
} | ||
|
||
/** | ||
* 게시글에 대한 반응을 선택하는 버튼 리스트 컴포넌트입니다.<br/> | ||
* 대표 감정 모드와 서브 감정 모드를 지원하며, 초기 선택된 감정을 설정하고 최대 선택 가능 수를 제한할 수 있습니다. | ||
*/ | ||
|
||
const EmotionList: React.FC<EmotionListProps> = ({ | ||
isPrimary = true, | ||
maxSelections, | ||
initialSelectedEmotions = [], | ||
onSelectionChange | ||
}) => { | ||
const [selectedEmotions, setSelectedEmotions] = useState<Emotions[]>([]); | ||
|
||
useEffect(() => { | ||
if (isPrimary) { | ||
if (initialSelectedEmotions.length > 0) { | ||
setSelectedEmotions([initialSelectedEmotions[0]]); | ||
onSelectionChange([initialSelectedEmotions[0]]); | ||
} else { | ||
setSelectedEmotions([]); | ||
onSelectionChange([]); | ||
} | ||
} else { | ||
const validInitialEmotions = initialSelectedEmotions.slice( | ||
0, | ||
maxSelections | ||
); | ||
setSelectedEmotions(validInitialEmotions); | ||
onSelectionChange(validInitialEmotions); | ||
} | ||
}, [isPrimary, initialSelectedEmotions, onSelectionChange, maxSelections]); | ||
|
||
const handleEmotionClick = (emotion: Emotions) => { | ||
setSelectedEmotions((prev) => { | ||
let newSelection: Emotions[]; | ||
|
||
if (isPrimary) { | ||
newSelection = [emotion]; | ||
} else { | ||
// eslint-disable-next-line no-lonely-if | ||
if (prev.includes(emotion)) { | ||
newSelection = prev.filter((e) => e !== emotion); | ||
} else if (prev.length < maxSelections) { | ||
newSelection = [...prev, emotion]; | ||
} else { | ||
alert(`최대 ${maxSelections}개 감정만 선택할 수 있습니다.`); | ||
newSelection = prev; | ||
} | ||
} | ||
|
||
onSelectionChange(newSelection); | ||
return newSelection; | ||
}); | ||
}; | ||
|
||
return ( | ||
<StyledEmotionButtonList> | ||
{Object.values(Emotions).map((emotion) => ( | ||
<EmotionButton | ||
key={emotion} | ||
emotion={emotion} | ||
initialClicked={selectedEmotions.includes(emotion)} | ||
onClick={() => handleEmotionClick(emotion)} | ||
disabled={false} | ||
/> | ||
))} | ||
</StyledEmotionButtonList> | ||
); | ||
}; | ||
|
||
export default EmotionList; |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.