From b01cb3a135694528b321f14b2c2cc4086fdd2823 Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:12:48 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20Sentry=20prod=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EC=97=90=EC=84=9C=EB=A7=8C=20=EB=8F=8C=EC=95=84=EA=B0=80?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20fetcher=20=EC=84=A4=EC=A0=95=20(#343)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: typescript에 NodeEnv 환경설정 타입 선언 * chore: Sentry 캡쳐 에러를 prod 환경에서만 실행되도록 설정 * refactor: captureError에서 early return 방식으로 변경 --- client/src/apis/useFetch.ts | 3 +++ client/src/global.d.ts | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/client/src/apis/useFetch.ts b/client/src/apis/useFetch.ts index b5f94df84..512ef4a96 100644 --- a/client/src/apis/useFetch.ts +++ b/client/src/apis/useFetch.ts @@ -64,6 +64,9 @@ export const useFetch = () => { }; const captureError = async (error: Error, navigate: NavigateFunction, eventId: string) => { + // prod 환경에서만 Sentry capture 실행 + if (process.env.NODE_ENV !== 'production') return; + const errorBody: ServerError = error instanceof FetchError ? error.errorBody : {message: error.message, errorCode: error.name}; diff --git a/client/src/global.d.ts b/client/src/global.d.ts index bff94710c..97ed3c462 100644 --- a/client/src/global.d.ts +++ b/client/src/global.d.ts @@ -1 +1,7 @@ declare module '*.svg'; + +declare namespace NodeJS { + interface ProcessEnv { + readonly NODE_ENV: 'development' | 'production' | 'test'; + } +} From 08c60bd84677d3a6a6e5ff998cd644165c87bc01 Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:13:47 +0900 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20=ED=99=98=EA=B2=BD=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=ED=83=80=EC=9E=85=20=EC=84=A0=EC=96=B8=20(#345)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: env key 타입 선언 * refactor: env type 선언으로 인한 빈 문자열 대체 제거 * refactor: NODE_ENV 타입 선언으로 빈 문자열 제거 및 development 환경 바로 비교 * refactor: 이벤트 페이지 url 자주사용되는 로직 유틸로 분리 --------- Co-authored-by: Pakxe <64801796+pakxe@users.noreply.github.com> --- client/src/apis/baseUrl.ts | 2 +- client/src/global.d.ts | 4 ++++ .../pages/CreateEventPage/CompleteCreateEventPage.tsx | 9 +++++---- client/src/pages/EventPage/EventPageLayout.tsx | 6 +++--- client/src/utils/getEventPageUrlByEnvironment.ts | 11 +++++++++++ 5 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 client/src/utils/getEventPageUrlByEnvironment.ts diff --git a/client/src/apis/baseUrl.ts b/client/src/apis/baseUrl.ts index e508ba375..37fc00a94 100644 --- a/client/src/apis/baseUrl.ts +++ b/client/src/apis/baseUrl.ts @@ -1,3 +1,3 @@ export const BASE_URL = { - HD: process.env.API_BASE_URL ?? '', + HD: process.env.API_BASE_URL, }; diff --git a/client/src/global.d.ts b/client/src/global.d.ts index 97ed3c462..dbf6320af 100644 --- a/client/src/global.d.ts +++ b/client/src/global.d.ts @@ -3,5 +3,9 @@ declare module '*.svg'; declare namespace NodeJS { interface ProcessEnv { readonly NODE_ENV: 'development' | 'production' | 'test'; + + // env keys + readonly API_BASE_URL: string; + readonly AMPLITUDE_KEY: string; } } diff --git a/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx b/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx index 200642f30..d60817f79 100644 --- a/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx +++ b/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx @@ -6,6 +6,8 @@ import {css} from '@emotion/react'; import {useToast} from '@components/Toast/ToastProvider'; +import getEventPageUrlByEnvironment from '@utils/getEventPageUrlByEnvironment'; + import {ROUTER_URLS} from '@constants/routerUrls'; const CompleteCreateEventPage = () => { @@ -26,8 +28,7 @@ const CompleteCreateEventPage = () => { const {showToast} = useToast(); - const env = process.env.NODE_ENV || ''; - const homeUrlByEnvironment = `https://${env.includes('development') ? 'dev.' : ''}haengdong.pro${ROUTER_URLS.event}/${url}/home`; + const homePageUrl = getEventPageUrlByEnvironment(url, 'home'); return ( @@ -41,10 +42,10 @@ const CompleteCreateEventPage = () => { 링크가 없으면 페이지에 접근할 수 없어요. 관리를 위해서 행사 링크를 복사 후 보관해 주세요. - + showToast({ showingTime: 3000, diff --git a/client/src/pages/EventPage/EventPageLayout.tsx b/client/src/pages/EventPage/EventPageLayout.tsx index 13a6aa67a..771422087 100644 --- a/client/src/pages/EventPage/EventPageLayout.tsx +++ b/client/src/pages/EventPage/EventPageLayout.tsx @@ -10,6 +10,7 @@ import useNavSwitch from '@hooks/useNavSwitch'; import StepListProvider from '@hooks/useStepList'; import getEventIdByUrl from '@utils/getEventIdByUrl'; +import getEventPageUrlByEnvironment from '@utils/getEventPageUrlByEnvironment'; import {ROUTER_URLS} from '@constants/routerUrls'; @@ -44,8 +45,7 @@ const EventPageLayout = () => { }; const {showToast} = useToast(); - - const env = process.env.NODE_ENV || ''; + const url = getEventPageUrlByEnvironment(eventId, 'home'); return ( @@ -53,7 +53,7 @@ const EventPageLayout = () => { showToast({ showingTime: 3000, diff --git a/client/src/utils/getEventPageUrlByEnvironment.ts b/client/src/utils/getEventPageUrlByEnvironment.ts new file mode 100644 index 000000000..bcfce54e9 --- /dev/null +++ b/client/src/utils/getEventPageUrlByEnvironment.ts @@ -0,0 +1,11 @@ +import {ROUTER_URLS} from '@constants/routerUrls'; + +type EventPageTab = 'home' | 'admin'; + +const getEventPageUrlByEnvironment = (eventId: string, tab: EventPageTab) => { + const isDevelopment = process.env.NODE_ENV === 'development'; + + return `https://${isDevelopment ? 'dev.' : ''}haengdong.pro${ROUTER_URLS.event}/${eventId}/${tab}`; +}; + +export default getEventPageUrlByEnvironment; From 364bcd8035a2d673f4f870d7f196b02df02125d1 Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:14:08 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feat:=20useDeleteMemberAction=20=ED=86=A0?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=ED=95=A8=EC=88=98=20=EA=B2=B0=ED=95=A9?= =?UTF-8?q?=EB=8F=84=20=EC=A0=9C=EA=B1=B0=20(#347)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: useDeleteMemberAction 토스트 로직 UI 컴포넌트로 이동 * refactor: isExistSameMember 함수 훅 외부로 넘겨주지 않고 특이한 케이스를 검사하는 함수를 훅 인자로 넘겨줌 * refactor: UI 컴포넌트에 토스트 띄우는 함수만 남기고 훅으로 이동 * chore: todo 주석 삭제 --- .../DeleteMemberActionModal.tsx | 34 ++++++++++++- client/src/hooks/useDeleteMemberAction.tsx | 49 +++++++++---------- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.tsx b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.tsx index a509b5d54..18b7e13ac 100644 --- a/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.tsx +++ b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.tsx @@ -2,6 +2,8 @@ import type {MemberAction, MemberType} from 'types/serviceType'; import {BottomSheet, Flex, Input, Text, IconButton, FixedButton, Icon} from 'haengdong-design'; +import {useToast} from '@components/Toast/ToastProvider'; + import useDeleteMemberAction from '@hooks/useDeleteMemberAction'; import {bottomSheetHeaderStyle, bottomSheetStyle, inputGroupStyle} from './DeleteMemberActionModal.style'; @@ -19,10 +21,38 @@ const DeleteMemberActionModal = ({ isBottomSheetOpened, setIsBottomSheetOpened, }: DeleteMemberActionModalProps) => { - const {aliveActionList, deleteMemberActionList, addDeleteMemberAction} = useDeleteMemberAction( + const {showToast} = useToast(); + + const showToastAlreadyExistMemberAction = () => { + showToast({ + isClickToClose: true, + showingTime: 3000, + message: '이미 삭제된 인원입니다.', + type: 'error', + bottom: '160px', + }); + }; + + const showToastExistSameMemberFromAfterStep = (name: string) => { + showToast({ + isClickToClose: true, + showingTime: 3000, + message: `이후의 ${name}가 사라져요`, + type: 'error', + position: 'top', + top: '30px', + style: { + zIndex: 9000, + }, + }); + }; + + const {aliveActionList, deleteMemberActionList, addDeleteMemberAction} = useDeleteMemberAction({ memberActionList, setIsBottomSheetOpened, - ); + showToastAlreadyExistMemberAction, + showToastExistSameMemberFromAfterStep, + }); return ( setIsBottomSheetOpened(false)}> diff --git a/client/src/hooks/useDeleteMemberAction.tsx b/client/src/hooks/useDeleteMemberAction.tsx index 1883929f2..be16baf02 100644 --- a/client/src/hooks/useDeleteMemberAction.tsx +++ b/client/src/hooks/useDeleteMemberAction.tsx @@ -2,7 +2,6 @@ import type {MemberAction} from 'types/serviceType'; import {useState} from 'react'; -import {useToast} from '@components/Toast/ToastProvider'; import {requestDeleteMemberAction} from '@apis/request/member'; import {useStepList} from '@hooks/useStepList'; @@ -11,14 +10,22 @@ import {useFetch} from '@apis/useFetch'; import getEventIdByUrl from '@utils/getEventIdByUrl'; -const useDeleteMemberAction = ( - memberActionList: MemberAction[], - setIsBottomSheetOpened: React.Dispatch>, -) => { +type UseDeleteMemberActionProps = { + memberActionList: MemberAction[]; + setIsBottomSheetOpened: React.Dispatch>; + showToastAlreadyExistMemberAction: () => void; + showToastExistSameMemberFromAfterStep: (name: string) => void; +}; + +const useDeleteMemberAction = ({ + memberActionList, + setIsBottomSheetOpened, + showToastAlreadyExistMemberAction, + showToastExistSameMemberFromAfterStep, +}: UseDeleteMemberActionProps) => { const {stepList, refreshStepList} = useStepList(); const [aliveActionList, setAliveActionList] = useState(memberActionList); const eventId = getEventIdByUrl(); - const {showToast} = useToast(); const {fetch} = useFetch(); const deleteMemberAction = async (actionId: number) => { @@ -46,36 +53,24 @@ const useDeleteMemberAction = ( } }; - const addDeleteMemberAction = (memberAction: MemberAction) => { + const checkAlreadyExistMemberAction = (memberAction: MemberAction, showToast: () => void) => { if (!memberActionList.includes(memberAction)) { - showToast({ - isClickToClose: true, - showingTime: 3000, - message: '이미 삭제된 인원입니다.', - type: 'error', - bottom: '160px', - }); - return; + showToast(); } + }; + const checkExistSameMemberFromAfterStep = (memberAction: MemberAction, showToast: () => void) => { if (isExistSameMemberFromAfterStep(memberAction)) { - showToast({ - isClickToClose: true, - showingTime: 3000, - message: `이후의 ${memberAction.name}가 사라져요`, - type: 'error', - position: 'top', - top: '30px', - style: { - zIndex: 9000, - }, - }); + showToast(); } + }; + const addDeleteMemberAction = (memberAction: MemberAction) => { + checkAlreadyExistMemberAction(memberAction, showToastAlreadyExistMemberAction); + checkExistSameMemberFromAfterStep(memberAction, () => showToastExistSameMemberFromAfterStep(memberAction.name)); setAliveActionList(prev => prev.filter(aliveMember => aliveMember.actionId !== memberAction.actionId)); }; - // 현재 선택된 액션의 인덱스를 구해서 뒤의 동일인물의 액션이 있는지를 파악하는 기능 const isExistSameMemberFromAfterStep = (memberAction: MemberAction) => { const memberActionList = stepList .filter(step => step.type !== 'BILL') From ae6ce80a71cc75c86a696b2327e58efaee80190d Mon Sep 17 00:00:00 2001 From: TaehunLee <85233397+Todari@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:14:42 +0900 Subject: [PATCH 4/9] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=84=B1=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0=20-=20Title=20component=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=20=EB=B0=8F=20UX=20writing=20=EC=88=98=EC=A0=95=20(#352)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Text component 줄바꿈 가능하도록 변경 * fix: Title component 변경 * chore: v0.1.72 배포 * feat: ux writing 변경 * fix: 디자인시스템 버전 변경 --- HDesign/package-lock.json | 4 ++-- HDesign/package.json | 2 +- HDesign/src/components/Text/Text.style.ts | 6 +++++- HDesign/src/components/Title/Title.stories.tsx | 3 ++- HDesign/src/components/Title/Title.tsx | 8 ++++++-- client/package-lock.json | 8 ++++---- client/package.json | 2 +- .../SetInitialMemberListModal.tsx | 2 +- client/src/pages/EventPage/AdminPage/AdminPage.tsx | 7 ++++--- 9 files changed, 26 insertions(+), 16 deletions(-) diff --git a/HDesign/package-lock.json b/HDesign/package-lock.json index 192588f72..084161fd1 100644 --- a/HDesign/package-lock.json +++ b/HDesign/package-lock.json @@ -1,12 +1,12 @@ { "name": "haengdong-design", - "version": "0.1.69", + "version": "0.1.72", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "haengdong-design", - "version": "0.1.69", + "version": "0.1.72", "license": "ISC", "dependencies": { "@emotion/react": "^11.11.4", diff --git a/HDesign/package.json b/HDesign/package.json index 4e555b3fc..ad2a06ea3 100644 --- a/HDesign/package.json +++ b/HDesign/package.json @@ -1,6 +1,6 @@ { "name": "haengdong-design", - "version": "0.1.69", + "version": "0.1.72", "description": "", "main": "./dist/index.js", "module": "./dist/index.js", diff --git a/HDesign/src/components/Text/Text.style.ts b/HDesign/src/components/Text/Text.style.ts index 6560c8274..650260e62 100644 --- a/HDesign/src/components/Text/Text.style.ts +++ b/HDesign/src/components/Text/Text.style.ts @@ -21,5 +21,9 @@ export const getSizeStyling = ({size, textColor, theme}: Required; diff --git a/HDesign/src/components/Title/Title.tsx b/HDesign/src/components/Title/Title.tsx index 759588b5e..e17de5e88 100644 --- a/HDesign/src/components/Title/Title.tsx +++ b/HDesign/src/components/Title/Title.tsx @@ -1,4 +1,5 @@ /** @jsxImportSource @emotion/react */ +import Flex from '@components/Flex/Flex'; import Text from '@components/Text/Text'; import {priceContainerStyle, titleContainerStyle} from '@components/Title/Title.style'; import {TitleProps} from '@components/Title/Title.type'; @@ -11,7 +12,7 @@ export const Title: React.FC = ({title, description, price}: TitlePr
{title} {description && ( - + {description} )} @@ -20,7 +21,10 @@ export const Title: React.FC = ({title, description, price}: TitlePr 전체 지출 금액 - {price.toLocaleString('ko-kr')}원 + + {price.toLocaleString('ko-kr')} + +
)} diff --git a/client/package-lock.json b/client/package-lock.json index f3731b138..0a884603e 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@emotion/react": "^11.11.4", "@sentry/react": "^8.25.0", - "haengdong-design": "^0.1.69", + "haengdong-design": "^0.1.72", "react": "^18.3.1", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", @@ -8123,9 +8123,9 @@ } }, "node_modules/haengdong-design": { - "version": "0.1.69", - "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.69.tgz", - "integrity": "sha512-XlZ7hnKn51aQOOz/x+hNM6tLjJDvvTOqLiVfOSjEvRpkMKquNWFoijclXHLNhK7tqrb6m+hDREf12mIXwSN/Ew==", + "version": "0.1.72", + "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.72.tgz", + "integrity": "sha512-7Qtk/HygT5IhLzUTQzcx7FbgZo/ZrqVZhKA08zJaf1wcOlc3CkXO3Ljl1wQloHGejg71K1N1BO3L208tppxycQ==", "dependencies": { "@emotion/react": "^11.11.4", "@storybook/addon-webpack5-compiler-swc": "^1.0.5", diff --git a/client/package.json b/client/package.json index c73dae15d..b0d9e7ff0 100644 --- a/client/package.json +++ b/client/package.json @@ -54,7 +54,7 @@ "dependencies": { "@emotion/react": "^11.11.4", "@sentry/react": "^8.25.0", - "haengdong-design": "^0.1.69", + "haengdong-design": "^0.1.72", "react": "^18.3.1", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", diff --git a/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.tsx b/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.tsx index ac9375d52..623d9f98f 100644 --- a/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.tsx +++ b/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.tsx @@ -37,7 +37,7 @@ const SetInitialMemberListModal = ({isOpenBottomSheet, setIsOpenBottomSheet}: Se return ( setIsOpenBottomSheet(false)}>
- 초기 인원 설정하기 + 시작 인원 추가하기
{inputList.map(({value, index}) => ( diff --git a/client/src/pages/EventPage/AdminPage/AdminPage.tsx b/client/src/pages/EventPage/AdminPage/AdminPage.tsx index a1ea053d9..ac0d85c05 100644 --- a/client/src/pages/EventPage/AdminPage/AdminPage.tsx +++ b/client/src/pages/EventPage/AdminPage/AdminPage.tsx @@ -36,8 +36,9 @@ const AdminPage = () => { const getTitleDescriptionByInitialMemberSetting = () => { return allMemberList.length > 0 - ? '“행동 추가하기” 버튼을 눌러서 지출 내역 및 인원 변동사항을 추가해 주세요.' - : '“초기인원 설정하기” 버튼을 눌러서 행사 초기 인원을 설정해 주세요.'; + ? `지출 내역 및 인원 변동을 추가해 주세요. + 인원 변동을 기준으로 몇 차인지 나뉘어져요.` + : '“시작 인원 추가” 버튼을 눌러 행사의 시작부터 참여하는 사람들의 이름을 입력해 주세요.'; }; return ( @@ -55,7 +56,7 @@ const AdminPage = () => {
setIsOpenFixedBottomBottomSheet(prev => !prev)} /> {isOpenFixedButtonBottomSheet && ( From 843d6795d6ded6f997b09b4827fb556f421e4fc9 Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:14:58 +0900 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=9E=85=EB=A0=A5=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=BB=A4=EC=8A=A4=ED=85=80=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20(#354)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 비밀번호 설정 커스텀 훅으로 분리 * refactor: event name 상태 제거 * style: index.ts에 setEventPasswordPage 컴포넌트 추가 * refactor: navigate 책임을 UI 컴포넌트로 위임 * style: 비밀번호 입력을 관리하는 함수라는 의미로 변경 --- client/src/hooks/useSetPassword.ts | 49 +++++++++++++++++++ .../CreateEventPage/SetEventPasswordPage.tsx | 42 ++++------------ client/src/pages/CreateEventPage/index.ts | 1 + client/src/router.tsx | 3 +- 4 files changed, 61 insertions(+), 34 deletions(-) create mode 100644 client/src/hooks/useSetPassword.ts diff --git a/client/src/hooks/useSetPassword.ts b/client/src/hooks/useSetPassword.ts new file mode 100644 index 000000000..0ba5e7272 --- /dev/null +++ b/client/src/hooks/useSetPassword.ts @@ -0,0 +1,49 @@ +import {useState} from 'react'; + +import validateEventPassword from '@utils/validate/validateEventPassword'; + +import {useFetch} from '@apis/useFetch'; + +import RULE from '@constants/rule'; + +import useEvent from './useEvent'; + +const useSetPassword = (eventName: string) => { + const {fetch} = useFetch(); + const [password, setPassword] = useState(''); + const [errorMessage, setErrorMessage] = useState(''); + const [canSubmit, setCanSubmit] = useState(false); + const {createNewEvent} = useEvent(); + + const submitPassword = async (event: React.FormEvent) => { + event.preventDefault(); + + const {eventId} = await fetch({queryFunction: () => createNewEvent({eventName, password: parseInt(password)})}); + return eventId; + }; + + const handlePasswordChange = (event: React.ChangeEvent) => { + const newValue = event.target.value; + const {isValid, errorMessage} = validateEventPassword(newValue); + + setCanSubmit(newValue.length === RULE.maxEventPasswordLength); + + if (isValid) { + setPassword(newValue); + setErrorMessage(''); + } else { + event.target.value = password; + setErrorMessage(errorMessage ?? ''); + } + }; + + return { + password, + errorMessage, + canSubmit, + submitPassword, + handlePasswordChange, + }; +}; + +export default useSetPassword; diff --git a/client/src/pages/CreateEventPage/SetEventPasswordPage.tsx b/client/src/pages/CreateEventPage/SetEventPasswordPage.tsx index 04c8dd760..a3572d24d 100644 --- a/client/src/pages/CreateEventPage/SetEventPasswordPage.tsx +++ b/client/src/pages/CreateEventPage/SetEventPasswordPage.tsx @@ -2,60 +2,38 @@ import {useEffect, useState} from 'react'; import {useLocation, useNavigate} from 'react-router-dom'; import {FixedButton, MainLayout, LabelInput, Title, TopNav, Back} from 'haengdong-design'; -import validateEventPassword from '@utils/validate/validateEventPassword'; -import {requestPostNewEvent} from '@apis/request/event'; - -import useEvent from '@hooks/useEvent'; +import useSetPassword from '@hooks/useSetPassword'; import RULE from '@constants/rule'; import {ROUTER_URLS} from '@constants/routerUrls'; const SetEventPasswordPage = () => { - const [eventName, setEventName] = useState(''); - const [password, setPassword] = useState(''); - const [errorMessage, setErrorMessage] = useState(''); - const [canSubmit, setCanSubmit] = useState(false); - const {createNewEvent} = useEvent(); const navigate = useNavigate(); const location = useLocation(); useEffect(() => { if (!location.state) { navigate(ROUTER_URLS.main); - } else { - setEventName(location.state.eventName); } - }, []); + }, [location.state]); - const submitPassword = async (event: React.FormEvent) => { - event.preventDefault(); + const {password, errorMessage, canSubmit, submitPassword, handlePasswordChange} = useSetPassword( + location.state?.eventName, + ); - const {eventId} = await createNewEvent({eventName, password: parseInt(password)}); + const onSubmit = async (event: React.FormEvent) => { + const eventId = await submitPassword(event); navigate(`${ROUTER_URLS.eventCreateComplete}?${new URLSearchParams({eventId})}`); }; - const handleChange = (event: React.ChangeEvent) => { - const newValue = event.target.value; - const validation = validateEventPassword(newValue); - - setCanSubmit(newValue.length === RULE.maxEventPasswordLength); - - if (validation.isValid) { - setPassword(newValue); - setErrorMessage(''); - } else { - event.target.value = password; - setErrorMessage(validation.errorMessage ?? ''); - } - }; return ( - <form onSubmit={submitPassword} style={{padding: '0 1rem'}}> + <form onSubmit={onSubmit} style={{padding: '0 1rem'}}> <LabelInput labelText="비밀번호" errorText={errorMessage} @@ -63,10 +41,10 @@ const SetEventPasswordPage = () => { type="secret" maxLength={RULE.maxEventPasswordLength} placeholder="비밀번호" - onChange={e => handleChange(e)} + onChange={handlePasswordChange} isError={!!errorMessage} autoFocus - ></LabelInput> + /> <FixedButton disabled={!canSubmit}>행동 개시!</FixedButton> </form> </MainLayout> diff --git a/client/src/pages/CreateEventPage/index.ts b/client/src/pages/CreateEventPage/index.ts index 9b66c3ba5..6d3d6c808 100644 --- a/client/src/pages/CreateEventPage/index.ts +++ b/client/src/pages/CreateEventPage/index.ts @@ -1,2 +1,3 @@ export {default as SetEventNamePage} from './SetEventNamePage'; +export {default as SetEventPasswordPage} from './SetEventPasswordPage'; export {default as CompleteCreateEventPage} from './CompleteCreateEventPage'; diff --git a/client/src/router.tsx b/client/src/router.tsx index 52d6da760..a6af2184d 100644 --- a/client/src/router.tsx +++ b/client/src/router.tsx @@ -3,10 +3,9 @@ import {createBrowserRouter} from 'react-router-dom'; import {AdminPage} from '@pages/EventPage/AdminPage'; import {HomePage} from '@pages/EventPage/HomePage'; import ErrorPage from '@pages/ErrorPage/ErrorPage'; -import SetEventPasswordPage from '@pages/CreateEventPage/SetEventPasswordPage'; import EventLoginPage from '@pages/EventPage/AdminPage/EventLoginPage'; -import {CompleteCreateEventPage, SetEventNamePage} from '@pages/CreateEventPage'; +import {CompleteCreateEventPage, SetEventNamePage, SetEventPasswordPage} from '@pages/CreateEventPage'; import {MainPage} from '@pages/MainPage'; import {EventPage} from '@pages/EventPage'; From 26eb877bbcad0f6d3e38530768fd555630742044 Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:15:11 +0900 Subject: [PATCH 6/9] =?UTF-8?q?fix:=20=ED=83=AD=20=ED=81=B4=EB=A6=AD=20?= =?UTF-8?q?=EC=8B=9C=20=EC=A0=84=EC=B2=B4=EA=B0=80=20=ED=81=B4=EB=A6=AD?= =?UTF-8?q?=EB=90=98=EB=8A=94=20=EA=B2=83=EC=B2=98=EB=9F=BC=20=EB=B3=B4?= =?UTF-8?q?=EC=9D=B4=EB=8A=94=20=ED=98=84=EC=83=81=20=ED=95=B4=EA=B2=B0=20?= =?UTF-8?q?(#356)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HDesign/src/components/Tabs/Tabs.style.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HDesign/src/components/Tabs/Tabs.style.ts b/HDesign/src/components/Tabs/Tabs.style.ts index 99a514547..3ea38924c 100644 --- a/HDesign/src/components/Tabs/Tabs.style.ts +++ b/HDesign/src/components/Tabs/Tabs.style.ts @@ -10,6 +10,8 @@ export const tabListStyle = (theme: Theme) => cursor: 'pointer', + WebkitTapHighlightColor: 'transparent', + '&::after': { position: 'absolute', left: 0, From c1c0916d0cf7fd4d36b0e49c15042e0a6c41b0da Mon Sep 17 00:00:00 2001 From: TaehunLee <85233397+Todari@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:16:19 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=84=B1=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0=20-=20=EC=A7=80=EC=B6=9C=20=EB=82=B4?= =?UTF-8?q?=EC=97=AD=20=EC=9E=85=EB=A0=A5=20=EC=95=84=EC=9D=B4=ED=85=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#357)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: EditableItem Component 구현 * chore: v0.1.73 배포 * style: lint 적용 * style: 오타 수정 * fix: EditableItem을 export 하지 않던 오류 수정 * chore: v0.1.74 배포 --------- Co-authored-by: Pakxe <64801796+pakxe@users.noreply.github.com> --- HDesign/package-lock.json | 5 +- HDesign/package.json | 2 +- .../EditableItem/EditableItem.Input.style.ts | 75 +++++++++++++++++++ .../EditableItem/EditableItem.Input.tsx | 27 +++++++ .../EditableItem/EditableItem.Input.type.ts | 18 +++++ .../EditableItem/EditableItem.context.tsx | 23 ++++++ .../EditableItem.input.stories.tsx | 44 +++++++++++ .../EditableItem/EditableItem.stories.tsx | 44 +++++++++++ .../EditableItem/EditableItem.style.ts | 14 ++++ .../components/EditableItem/EditableItem.tsx | 40 ++++++++++ .../EditableItem/EditableItem.type.ts | 20 +++++ .../EditableItem/useEditableItem.ts | 23 ++++++ .../EditableItem/useEditableItemInput.ts | 46 ++++++++++++ HDesign/src/index.tsx | 2 + 14 files changed, 380 insertions(+), 3 deletions(-) create mode 100644 HDesign/src/components/EditableItem/EditableItem.Input.style.ts create mode 100644 HDesign/src/components/EditableItem/EditableItem.Input.tsx create mode 100644 HDesign/src/components/EditableItem/EditableItem.Input.type.ts create mode 100644 HDesign/src/components/EditableItem/EditableItem.context.tsx create mode 100644 HDesign/src/components/EditableItem/EditableItem.input.stories.tsx create mode 100644 HDesign/src/components/EditableItem/EditableItem.stories.tsx create mode 100644 HDesign/src/components/EditableItem/EditableItem.style.ts create mode 100644 HDesign/src/components/EditableItem/EditableItem.tsx create mode 100644 HDesign/src/components/EditableItem/EditableItem.type.ts create mode 100644 HDesign/src/components/EditableItem/useEditableItem.ts create mode 100644 HDesign/src/components/EditableItem/useEditableItemInput.ts diff --git a/HDesign/package-lock.json b/HDesign/package-lock.json index 084161fd1..274804d74 100644 --- a/HDesign/package-lock.json +++ b/HDesign/package-lock.json @@ -1,12 +1,13 @@ { "name": "haengdong-design", - "version": "0.1.72", + "version": "0.1.74", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "haengdong-design", - "version": "0.1.72", + "version": "0.1.74", + "license": "ISC", "dependencies": { "@emotion/react": "^11.11.4", diff --git a/HDesign/package.json b/HDesign/package.json index ad2a06ea3..e01107490 100644 --- a/HDesign/package.json +++ b/HDesign/package.json @@ -1,6 +1,6 @@ { "name": "haengdong-design", - "version": "0.1.72", + "version": "0.1.74", "description": "", "main": "./dist/index.js", "module": "./dist/index.js", diff --git a/HDesign/src/components/EditableItem/EditableItem.Input.style.ts b/HDesign/src/components/EditableItem/EditableItem.Input.style.ts new file mode 100644 index 000000000..fc346d77b --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.Input.style.ts @@ -0,0 +1,75 @@ +import {css} from '@emotion/react'; + +import {TextSize} from '@components/Text/Text.type'; + +import {Theme} from '@theme/theme.type'; + +import TYPOGRAPHY from '@token/typography'; + +interface InputWrapperStyleProps { + theme: Theme; + hasFocus: boolean; + hasError: boolean; +} + +interface InputStyleProps { + theme: Theme; + textSize: TextSize; +} + +interface InputSizeStyleProps { + textSize: TextSize; +} + +interface InputBaseStyleProps { + theme: Theme; +} + +export const inputWrapperStyle = ({theme, hasFocus, hasError}: InputWrapperStyleProps) => + css({ + position: 'relative', + display: 'inline-block', + + '&::after': { + content: '""', + position: 'absolute', + left: 0, + right: 0, + bottom: 0, + height: '0.125rem', + backgroundColor: hasFocus ? theme.colors.primary : hasError ? theme.colors.error : 'transparent', + transition: 'background-color 0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + }, + }); + +export const inputStyle = ({theme, textSize}: InputStyleProps) => [inputSizeStyle({textSize}), inputBaseStyle({theme})]; + +const inputSizeStyle = ({textSize}: InputSizeStyleProps) => { + const style = { + head: css(TYPOGRAPHY.head), + title: css(TYPOGRAPHY.title), + subTitle: css(TYPOGRAPHY.subTitle), + bodyBold: css(TYPOGRAPHY.bodyBold), + body: css(TYPOGRAPHY.body), + smallBodyBold: css(TYPOGRAPHY.smallBodyBold), + smallBody: css(TYPOGRAPHY.smallBody), + captionBold: css(TYPOGRAPHY.captionBold), + caption: css(TYPOGRAPHY.caption), + tiny: css(TYPOGRAPHY.tiny), + }; + + return [style[textSize]]; +}; + +const inputBaseStyle = ({theme}: InputBaseStyleProps) => + css({ + border: 'none', + outline: 'none', + paddingBottom: '0.125rem', + + color: theme.colors.black, + '&:placeholder': { + color: theme.colors.gray, + }, + }); diff --git a/HDesign/src/components/EditableItem/EditableItem.Input.tsx b/HDesign/src/components/EditableItem/EditableItem.Input.tsx new file mode 100644 index 000000000..b6af0c144 --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.Input.tsx @@ -0,0 +1,27 @@ +/** @jsxImportSource @emotion/react */ +import React, {forwardRef, useEffect, useImperativeHandle, useRef, useState} from 'react'; + +import {InputProps} from '@components/EditableItem/EditableItem.Input.type'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {inputStyle, inputWrapperStyle} from './EditableItem.Input.style'; +import useEditableItemInput from './useEditableItemInput'; + +export const EditableItemInput: React.FC<InputProps> = forwardRef<HTMLInputElement, InputProps>(function Input( + {textSize = 'body', hasError = false, ...htmlProps}, + ref, +) { + const {theme} = useTheme(); + const inputRef = useRef<HTMLInputElement>(null); + const {hasFocus} = useEditableItemInput({inputRef}); + useImperativeHandle(ref, () => inputRef.current!); + + return ( + <div css={inputWrapperStyle({theme, hasFocus, hasError})}> + <input css={inputStyle({theme, textSize})} ref={inputRef} {...htmlProps} /> + </div> + ); +}); + +export default EditableItemInput; diff --git a/HDesign/src/components/EditableItem/EditableItem.Input.type.ts b/HDesign/src/components/EditableItem/EditableItem.Input.type.ts new file mode 100644 index 000000000..5d58238e8 --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.Input.type.ts @@ -0,0 +1,18 @@ +import {TextSize} from '@components/Text/Text.type'; + +import {Theme} from '@theme/theme.type'; + +export interface InputStyleProps { + hasError?: boolean; + textSize?: TextSize; +} + +export interface InputCustomProps {} + +export interface InputStylePropsWithTheme extends InputStyleProps { + theme: Theme; +} + +export type InputOptionProps = InputStyleProps & InputCustomProps; + +export type InputProps = React.ComponentProps<'input'> & InputOptionProps; diff --git a/HDesign/src/components/EditableItem/EditableItem.context.tsx b/HDesign/src/components/EditableItem/EditableItem.context.tsx new file mode 100644 index 000000000..a2aeef4bc --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.context.tsx @@ -0,0 +1,23 @@ +/** @jsxImportSource @emotion/react */ +import {createContext, PropsWithChildren, useContext, useState} from 'react'; + +interface EditableItemContextProps { + hasAnyFocus: boolean; + setHasAnyFocus: React.Dispatch<React.SetStateAction<boolean>>; +} + +const EditableItemContext = createContext<EditableItemContextProps | null>(null); + +export const useEditableItemContext = () => { + const context = useContext(EditableItemContext); + if (!context) { + throw new Error('useEditableItemContext must be used within an EditableItemProvider'); + } + return context; +}; + +export const EditableItemProvider: React.FC<PropsWithChildren> = ({children}: React.PropsWithChildren) => { + const [hasAnyFocus, setHasAnyFocus] = useState(false); + + return <EditableItemContext.Provider value={{hasAnyFocus, setHasAnyFocus}}>{children}</EditableItemContext.Provider>; +}; diff --git a/HDesign/src/components/EditableItem/EditableItem.input.stories.tsx b/HDesign/src/components/EditableItem/EditableItem.input.stories.tsx new file mode 100644 index 000000000..a23483b78 --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.input.stories.tsx @@ -0,0 +1,44 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import EditableItemInput from '@components/EditableItem/EditableItem.Input'; + +import EditableItem from './EditableItem'; +import {EditableItemProvider} from './EditableItem.context'; + +const meta = { + title: 'Components/EditableItemInput', + component: EditableItemInput, + tags: ['autodocs'], + parameters: {}, + argTypes: { + textSize: { + description: '', + control: {type: 'select'}, + }, + hasError: { + description: '', + control: {type: 'boolean'}, + }, + }, + args: { + placeholder: '지출 내역', + textSize: 'body', + hasError: false, + autoFocus: true, + }, +} satisfies Meta<typeof EditableItemInput>; + +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Playground: Story = { + render: ({...args}) => { + return ( + <EditableItemProvider> + <EditableItem.Input {...args} /> + </EditableItemProvider> + ); + }, +}; diff --git a/HDesign/src/components/EditableItem/EditableItem.stories.tsx b/HDesign/src/components/EditableItem/EditableItem.stories.tsx new file mode 100644 index 000000000..976a4aa90 --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.stories.tsx @@ -0,0 +1,44 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import EditableItem from '@components/EditableItem/EditableItem'; +import Flex from '@components/Flex/Flex'; +import Text from '@components/Text/Text'; + +const meta = { + title: 'Components/EditableItem', + component: EditableItem, + tags: ['autodocs'], + parameters: {}, + argTypes: { + backgroundColor: { + description: '', + control: {type: 'select'}, + }, + }, + args: { + backgroundColor: 'lightGrayContainer', + }, +} satisfies Meta<typeof EditableItem>; + +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Playground: Story = { + render: ({...args}) => { + return ( + <EditableItem + backgroundColor={args.backgroundColor} + onFocus={() => console.log('focus')} + onBlur={() => console.log('blur')} + > + <EditableItem.Input placeholder="지출 내역" textSize="bodyBold"></EditableItem.Input> + <Flex gap="0.25rem" alignItems="center"> + <EditableItem.Input placeholder="0" type="number" style={{textAlign: 'right'}}></EditableItem.Input> + <Text size="caption">원</Text> + </Flex> + </EditableItem> + ); + }, +}; diff --git a/HDesign/src/components/EditableItem/EditableItem.style.ts b/HDesign/src/components/EditableItem/EditableItem.style.ts new file mode 100644 index 000000000..c817e5f7d --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.style.ts @@ -0,0 +1,14 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +import {ColorKeys} from '@token/colors'; + +export const editableItemStyle = (theme: Theme, backgroundColor: ColorKeys) => + css({ + display: 'flex', + justifyContent: 'space-between', + padding: '0.5rem', + borderRadius: '0.5rem', + backgroundColor: theme.colors[backgroundColor], + }); diff --git a/HDesign/src/components/EditableItem/EditableItem.tsx b/HDesign/src/components/EditableItem/EditableItem.tsx new file mode 100644 index 000000000..cc1892370 --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.tsx @@ -0,0 +1,40 @@ +/** @jsxImportSource @emotion/react */ +import React, {useEffect} from 'react'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {editableItemStyle} from './EditableItem.style'; +import EditableItemInput from './EditableItem.Input'; +import {EditableItemProps} from './EditableItem.type'; +import {EditableItemProvider} from './EditableItem.context'; +import useEditableItem from './useEditableItem'; + +const EditableItemBase = ({ + onInputFocus, + onInputBlur, + backgroundColor = 'white', + children, + ...htmlProps +}: EditableItemProps) => { + const {theme} = useTheme(); + + useEditableItem({onInputFocus, onInputBlur}); + + return ( + <div css={editableItemStyle(theme, backgroundColor)} {...htmlProps}> + {children} + </div> + ); +}; + +export const EditableItem = (props: EditableItemProps) => { + return ( + <EditableItemProvider> + <EditableItemBase {...props} /> + </EditableItemProvider> + ); +}; + +EditableItem.Input = EditableItemInput; + +export default EditableItem; diff --git a/HDesign/src/components/EditableItem/EditableItem.type.ts b/HDesign/src/components/EditableItem/EditableItem.type.ts new file mode 100644 index 000000000..b19a76427 --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.type.ts @@ -0,0 +1,20 @@ +import {Theme} from '@theme/theme.type'; + +import {ColorKeys} from '@token/colors'; + +export interface EditableItemStyleProps { + backgroundColor: ColorKeys; +} + +export interface EditableItemCustomProps { + onInputFocus?: () => void; + onInputBlur?: () => void; +} + +export interface EditableItemStylePropsWithTheme extends EditableItemStyleProps { + theme: Theme; +} + +export type EditableItemOptionProps = EditableItemStyleProps & EditableItemCustomProps; + +export type EditableItemProps = React.ComponentProps<'div'> & EditableItemOptionProps; diff --git a/HDesign/src/components/EditableItem/useEditableItem.ts b/HDesign/src/components/EditableItem/useEditableItem.ts new file mode 100644 index 000000000..86880deb6 --- /dev/null +++ b/HDesign/src/components/EditableItem/useEditableItem.ts @@ -0,0 +1,23 @@ +import {useEffect} from 'react'; + +import {useEditableItemContext} from './EditableItem.context'; + +interface UseEditableItemProps { + onInputFocus?: () => void; + onInputBlur?: () => void; +} + +const useEditableItem = ({onInputFocus, onInputBlur}: UseEditableItemProps) => { + const {hasAnyFocus} = useEditableItemContext(); + + useEffect(() => { + if (hasAnyFocus && onInputFocus) { + onInputFocus(); + } + if (!hasAnyFocus && onInputBlur) { + onInputBlur(); + } + }, [hasAnyFocus, onInputFocus, onInputBlur]); +}; + +export default useEditableItem; diff --git a/HDesign/src/components/EditableItem/useEditableItemInput.ts b/HDesign/src/components/EditableItem/useEditableItemInput.ts new file mode 100644 index 000000000..3253ad0ea --- /dev/null +++ b/HDesign/src/components/EditableItem/useEditableItemInput.ts @@ -0,0 +1,46 @@ +import {useCallback, useEffect, useState} from 'react'; + +import {useEditableItemContext} from './EditableItem.context'; + +interface UseEditableItemInputProps { + inputRef: React.RefObject<HTMLInputElement>; +} + +const useEditableItemInput = ({inputRef}: UseEditableItemInputProps) => { + const [hasFocus, setHasFocus] = useState(false); + const {setHasAnyFocus} = useEditableItemContext(); + + const handleFocus = useCallback(() => { + setHasFocus(true); + setHasAnyFocus(true); + }, [setHasAnyFocus]); + + const handleBlur = useCallback(() => { + setHasFocus(false); + setHasAnyFocus(false); + }, [setHasAnyFocus]); + + useEffect(() => { + const input = inputRef.current; + + if (input) { + input.addEventListener('focus', handleFocus); + input.addEventListener('blur', handleBlur); + + return () => { + input.removeEventListener('focus', handleFocus); + input.removeEventListener('blur', handleBlur); + }; + } + }, [handleFocus, handleBlur, inputRef]); + + useEffect(() => { + if (document.activeElement === inputRef.current) { + handleFocus(); + } + }, [handleFocus, inputRef]); + + return {hasFocus}; +}; + +export default useEditableItemInput; diff --git a/HDesign/src/index.tsx b/HDesign/src/index.tsx index e6498965e..656690951 100644 --- a/HDesign/src/index.tsx +++ b/HDesign/src/index.tsx @@ -2,6 +2,7 @@ import BottomSheet from '@components/BottomSheet/BottomSheet'; import Button from '@components/Button/Button'; import DragHandleItem from '@components/DragHandleItem/DragHandleItem'; import DragHandleItemContainer from '@components/DragHandleItemContainer/DragHandleItemContainer'; +import EditableItem from '@components/EditableItem/EditableItem'; import ExpenseList from '@components/ExpenseList/ExpenseList'; import FixedButton from '@components/FixedButton/FixedButton'; import Flex from '@components/Flex/Flex'; @@ -33,6 +34,7 @@ export { Button, DragHandleItem, DragHandleItemContainer, + EditableItem, ExpenseList, FixedButton, Flex, From 9634f1539d5ef3a0a0259d41bd8220a395c63bd5 Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:18:55 +0900 Subject: [PATCH 8/9] =?UTF-8?q?refactor:=20=ED=96=89=EC=82=AC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=99=84=EB=A3=8C=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EC=A0=9C=EA=B1=B0=20(#350)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 행사생성 완료페이지 불필요한 상태 제거 * refactor: 사용하지 않는 import 구문 제거 및 코드 제거 --- .../CreateEventPage/CompleteCreateEventPage.tsx | 16 +++------------- .../pages/CreateEventPage/SetEventNamePage.tsx | 3 --- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx b/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx index d60817f79..d9c4f6bce 100644 --- a/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx +++ b/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx @@ -1,4 +1,3 @@ -import {useEffect, useState} from 'react'; import {useLocation, useNavigate} from 'react-router-dom'; import {Button, FixedButton, Flex, Input, MainLayout, Text, Title, TopNav} from 'haengdong-design'; import {CopyToClipboard} from 'react-copy-to-clipboard'; @@ -13,18 +12,9 @@ import {ROUTER_URLS} from '@constants/routerUrls'; const CompleteCreateEventPage = () => { const navigate = useNavigate(); const location = useLocation(); - const [url, setUrl] = useState(''); - useEffect(() => { - const getUrl = async () => { - // TODO: (@weadie) eventId를 location에서 불러오는 로직 함수로 분리해서 재사용 - const params = new URLSearchParams(location.search); - const eventId = params.get('eventId'); - // TODO: (@weadie) eventId가 없는 경우에 대한 처리 필요 - setUrl(eventId ?? ''); - }; - getUrl(); - }, []); + const params = new URLSearchParams(location.search); + const eventId = params.get('eventId'); const {showToast} = useToast(); @@ -62,7 +52,7 @@ const CompleteCreateEventPage = () => { </CopyToClipboard> </div> - <FixedButton onClick={() => navigate(`${ROUTER_URLS.event}/${url}/admin`)}>관리 페이지로 이동</FixedButton> + <FixedButton onClick={() => navigate(`${ROUTER_URLS.event}/${eventId}/admin`)}>관리 페이지로 이동</FixedButton> </MainLayout> ); }; diff --git a/client/src/pages/CreateEventPage/SetEventNamePage.tsx b/client/src/pages/CreateEventPage/SetEventNamePage.tsx index ef0417d8a..68f57a242 100644 --- a/client/src/pages/CreateEventPage/SetEventNamePage.tsx +++ b/client/src/pages/CreateEventPage/SetEventNamePage.tsx @@ -4,8 +4,6 @@ import {FixedButton, MainLayout, LabelInput, Title, TopNav, Back} from 'haengdon import validateEventName from '@utils/validate/validateEventName'; -import useEvent from '@hooks/useEvent'; - import {ROUTER_URLS} from '@constants/routerUrls'; const SetEventNamePage = () => { @@ -13,7 +11,6 @@ const SetEventNamePage = () => { const [errorMessage, setErrorMessage] = useState(''); const [canSubmit, setCanSubmit] = useState(false); const navigate = useNavigate(); - const {createNewEvent} = useEvent(); const submitEventName = async (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); From 249fc3f9fc032bc17666047d13f15bf9169775a4 Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Fri, 16 Aug 2024 17:32:46 +0900 Subject: [PATCH 9/9] =?UTF-8?q?fix:=20=EC=9D=B8=EC=9B=90=20=ED=83=88?= =?UTF-8?q?=EC=A3=BC=20=EC=8B=9C=20=EA=B2=80=EC=83=89=EC=9D=B4=20=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20(#368)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/apis/request/member.ts | 2 +- client/src/hooks/useSearchInMemberList.ts | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/client/src/apis/request/member.ts b/client/src/apis/request/member.ts index 48329e78f..141061bc1 100644 --- a/client/src/apis/request/member.ts +++ b/client/src/apis/request/member.ts @@ -73,7 +73,7 @@ export const requestDeleteAllMemberList = async ({eventId, memberName}: WithEven }; export type ResponseGetCurrentInMemberList = { - members: Array<{name: string}>; + memberNames: string[]; }; export const requestGetCurrentInMemberList = async (eventId: string) => { diff --git a/client/src/hooks/useSearchInMemberList.ts b/client/src/hooks/useSearchInMemberList.ts index 66e65b887..04514d689 100644 --- a/client/src/hooks/useSearchInMemberList.ts +++ b/client/src/hooks/useSearchInMemberList.ts @@ -23,7 +23,7 @@ const useSearchInMemberList = ( const [currentInputIndex, setCurrentInputIndex] = useState(-1); // 서버에서 가져온 전체 리스트 - const [currentInMemberList, setCurrentInMemberList] = useState<Array<{name: string}>>([]); + const [currentInMemberList, setCurrentInMemberList] = useState<Array<string>>([]); // 검색된 리스트 (따로 둔 이유는 검색 후 클릭했을 때 리스트를 비워주어야하기 때문) const [filteredInMemberList, setFilteredInMemberList] = useState<Array<string>>([]); @@ -31,7 +31,7 @@ const useSearchInMemberList = ( useEffect(() => { const getCurrentInMembers = async () => { const currentInMemberListFromServer = await fetch({queryFunction: () => requestGetCurrentInMemberList(eventId)}); - setCurrentInMemberList(currentInMemberListFromServer.members); + setCurrentInMemberList(currentInMemberListFromServer.memberNames); }; getCurrentInMembers(); @@ -40,11 +40,9 @@ const useSearchInMemberList = ( const filterMatchItems = (keyword: string) => { if (keyword.trim() === '') return []; - const MatchItems = currentInMemberList.map(({name}) => name); - - return MatchItems.filter( - matchItem => matchItem.toLocaleLowerCase().indexOf(keyword.toLocaleLowerCase()) > -1, - ).slice(0, 3); + return currentInMemberList + .filter(member => member.toLocaleLowerCase().indexOf(keyword.toLocaleLowerCase()) > -1) + .slice(0, 3); }; const chooseMember = (inputIndex: number, name: string) => {