From 4200f768894892802ce7a712d30d87e42f0d2526 Mon Sep 17 00:00:00 2001 From: Seok93 Date: Mon, 24 Jun 2024 22:22:48 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20#24=20=EC=83=81=ED=83=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=AA=A8=EB=8B=AC=20UI=20=EC=9E=91=EC=97=85?= =?UTF-8?q?=EA=B3=BC=20Form=20Validation=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/modal/ModalTodoStatus.tsx | 143 +++++++++++++++++++++++ src/constants/.gitkeep | 0 src/constants/formValidationRules.ts | 26 +++++ src/types/TodoStatusType.tsx | 11 ++ 4 files changed, 180 insertions(+) create mode 100644 src/components/modal/ModalTodoStatus.tsx delete mode 100644 src/constants/.gitkeep create mode 100644 src/constants/formValidationRules.ts create mode 100644 src/types/TodoStatusType.tsx diff --git a/src/components/modal/ModalTodoStatus.tsx b/src/components/modal/ModalTodoStatus.tsx new file mode 100644 index 00000000..e8a61007 --- /dev/null +++ b/src/components/modal/ModalTodoStatus.tsx @@ -0,0 +1,143 @@ +import { GiCheckMark } from 'react-icons/gi'; +import { IoIosClose } from 'react-icons/io'; +import { RiProhibited2Fill, RiProhibited2Line } from 'react-icons/ri'; +import { SubmitHandler, useForm } from 'react-hook-form'; +import { STATUS_VALIDATION_RULES } from '@constants/formValidationRules'; +import type { TodoStatus, TodoStatusFormValues } from '@/types/TodoStatusType'; + +type TodoProps = { + todoStatus: TodoStatus[]; + onClose: () => void; +}; + +const DEFAULT_TODO_COLORS = Object.freeze({ + RED: '#c83c00', + YELLOW: '#dab700', + GREEN: '#237700', + BLUE: '#00c2ff', + ORANGE: '#ff7a00', + PURPLE: '#db00ff', + PINK: '#ff0099', + YELLO_GREEN: '#8fff00', +}); + +// 색상 정보 취득 +function getTodoColors(todoStatus: TodoStatus[]) { + const colorMap = new Map(); + + Object.values(DEFAULT_TODO_COLORS).forEach((color) => + colorMap.set(color, { color, isDefault: true, isUsable: true }), + ); + + todoStatus.forEach(({ color }) => { + const colorStatusInfo = colorMap.has(color) + ? { ...colorMap.get(color), isUsable: false } + : { color, isDefault: false, isUsable: false }; + colorMap.set(color, colorStatusInfo); + }); + + return [...colorMap.values()]; +} + +export default function ModalTodoStatus({ todoStatus, onClose }: TodoProps) { + const { + register, + watch, + handleSubmit, + formState: { errors }, + } = useForm({ + mode: 'onChange', + defaultValues: { + name: '', + color: '', + }, + }); + const statusName = watch('name'); + const selectedColor = watch('color'); + + // ToDo: useMemo, useCallback 고려해보기 + const colorList = getTodoColors(todoStatus); + const nameList = todoStatus.map((status) => status.name); + const colorNameList = todoStatus.map((status) => status.color); + + const handleClickDelete = (color: string) => { + // ToDo: 색상 삭제시 등록된 할일 목록이 있는지 확인하는 로직 추가 + // ToDo: 색상 삭제를 위한 네트워크 로직 추가 + console.log(`${color} 삭제`); + }; + + const onSubmit: SubmitHandler = async (data) => { + // ToDo: 색상 생성을 위한 네트워크 로직 추가 + console.log(data); + }; + + return ( +
+
+ +

색상

+
+ {colorList.map(({ color, isUsable, isDefault }, index) => ( +
+ + {!isDefault && ( + + )} +
+ ))} +
+ {errors.color &&
{errors.color.message}
} +
+
+ + +
+
+ ); +} diff --git a/src/constants/.gitkeep b/src/constants/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/constants/formValidationRules.ts b/src/constants/formValidationRules.ts new file mode 100644 index 00000000..1f3ae126 --- /dev/null +++ b/src/constants/formValidationRules.ts @@ -0,0 +1,26 @@ +import Validator from '@utils/Validator'; +import { deepFreeze } from '@utils/deepFreeze'; + +export const STATUS_VALIDATION_RULES = deepFreeze({ + STATUS_NAME: (nameList: string[]) => ({ + required: '상태명을 입력해주세요.', + minLength: { + value: 2, + message: '상태명을 2자리 이상 20자리 이하로 입력해주세요.', + }, + maxLength: { + value: 20, + message: '상태명을 2자리 이상 20자리 이하로 입력해주세요.', + }, + validate: { + isEmpty: (value: string) => !Validator.isEmptyString(value) || '상태명을 제대로 입력해주세요.', + duplicatedName: (value: string) => !Validator.isDuplicatedName(nameList, value) || '이미 사용중인 상태명입니다.', + }, + }), + COLOR: (colorList: string[]) => ({ + required: '색상을 선택해주세요.', + validate: { + duplicatedName: (value: string) => !Validator.isDuplicatedName(colorList, value) || '이미 사용중인 색상입니다.', + }, + }), +}); diff --git a/src/types/TodoStatusType.tsx b/src/types/TodoStatusType.tsx new file mode 100644 index 00000000..77aa0f5d --- /dev/null +++ b/src/types/TodoStatusType.tsx @@ -0,0 +1,11 @@ +// ToDo: API 설계 완료시 데이터 타입 변경할 것 +export type TodoStatus = { + statusId: number; + name: string; + color: string; +}; + +export type TodoStatusFormValues = { + name: string; + color: string; +};