Skip to content

Commit

Permalink
fix : 컴포넌트명 수정 및 대표서브모드 설정 추가 (#77)
Browse files Browse the repository at this point in the history
  • Loading branch information
jymaeng1234 authored Oct 31, 2024
1 parent daf6da0 commit fd31850
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 77 deletions.
24 changes: 12 additions & 12 deletions src/shared/EmotionButton/ui/EmotionButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useEffect, useState } from 'react';

import EmotionIcon from '../../EmotionIcon/ui/EmotionIcon';
import { Emotions, getEmotionInfo } from '../../model/EmotionEnum';
import { StyledEmotionButton } from './EmotionButton.styled';
Expand All @@ -8,24 +7,25 @@ interface EmotionButtonProps {
emotion: Emotions;
initialClicked: boolean;
onClick: () => void;
disabled: boolean;
}

const EmotionButton = ({
const EmotionButton: React.FC<EmotionButtonProps> = ({
emotion,
onClick,
initialClicked = false
}: EmotionButtonProps) => {
initialClicked,
disabled
}) => {
const [isClicked, setIsClicked] = useState(initialClicked);
useEffect(() => {
setIsClicked(initialClicked);
}, [initialClicked]);

const handleClick = () => {
setIsClicked((prev) => !prev);
onClick();
};
useEffect(() => setIsClicked(initialClicked), [initialClicked]);

return (
<StyledEmotionButton clicked={isClicked} onClick={handleClick}>
<StyledEmotionButton
clicked={isClicked}
onClick={!disabled ? onClick : undefined}
disabled={disabled}
>
<EmotionIcon emotion={emotion} width="20px" height="20px" />
<p>{getEmotionInfo(emotion).description}</p>
</StyledEmotionButton>
Expand Down
114 changes: 114 additions & 0 deletions src/shared/EmotionButtonList/ui/EmotionButtonList.stories.tsx
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. 기뻐요, 슬퍼요, 곤란해요 초기값 설정)',
},
},
},
};
83 changes: 83 additions & 0 deletions src/shared/EmotionButtonList/ui/EmotionButtonList.tsx
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;
26 changes: 0 additions & 26 deletions src/shared/EmotionList/ui/EmotionButtonList.stories.tsx

This file was deleted.

39 changes: 0 additions & 39 deletions src/shared/EmotionList/ui/EmotionButtonList.tsx

This file was deleted.

0 comments on commit fd31850

Please sign in to comment.