From 84404dd0a64ec9ae7862e03f1501beb43ecde413 Mon Sep 17 00:00:00 2001 From: Shim MunSeong Date: Tue, 1 Oct 2024 21:37:57 +0900 Subject: [PATCH 01/19] =?UTF-8?q?feat:=20=EA=B3=B5=EC=97=B0=20=EC=B0=B8?= =?UTF-8?q?=EA=B0=80=EC=9E=90=20=EC=9E=85=EB=A0=A5=20UI=20=EC=9D=BC?= =?UTF-8?q?=EB=B6=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ShowBasicInfoFormContent.tsx | 6 +- .../ShowCastInfoFormContent.tsx | 71 +++++++++++++++++++ .../ShowDetailInfoFormContent.tsx | 6 +- .../ShowInfoFormContent.styles.ts | 32 +++++++-- apps/admin/src/pages/ShowAddPage/index.tsx | 4 ++ 5 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 apps/admin/src/components/ShowInfoFormContent/ShowCastInfoFormContent.tsx diff --git a/apps/admin/src/components/ShowInfoFormContent/ShowBasicInfoFormContent.tsx b/apps/admin/src/components/ShowInfoFormContent/ShowBasicInfoFormContent.tsx index fcea10c6..dc31121f 100644 --- a/apps/admin/src/components/ShowInfoFormContent/ShowBasicInfoFormContent.tsx +++ b/apps/admin/src/components/ShowInfoFormContent/ShowBasicInfoFormContent.tsx @@ -78,7 +78,11 @@ const ShowBasicInfoFormContent = ({ return ( - 기본 정보 + + + 기본 정보 + + 공연 포스터 diff --git a/apps/admin/src/components/ShowInfoFormContent/ShowCastInfoFormContent.tsx b/apps/admin/src/components/ShowInfoFormContent/ShowCastInfoFormContent.tsx new file mode 100644 index 00000000..2dc52572 --- /dev/null +++ b/apps/admin/src/components/ShowInfoFormContent/ShowCastInfoFormContent.tsx @@ -0,0 +1,71 @@ +import { Button, TextField, useDialog } from '@boolti/ui'; +import { Controller, useForm } from 'react-hook-form'; +import Styled from './ShowInfoFormContent.styles'; +import { PlusIcon } from '@boolti/icon'; +import { useState } from 'react'; + +type ShowCastInfoFormInputs = { + teamName: string; +} + +const ShowCastInfoFormContent = () => { + const dialog = useDialog(); + const { control, register } = useForm(); + + const [hasBlurred, setHasBlurred] = useState>({ + teamName: false, + }); + + return ( + + + + 출연진 정보 + + 출연진 정보를 팀 단위로 등록해 주세요.
정보는 공연 등록 이후에도 수정 및 추가할 수 있어요. +
+
+ +
+
+ ) +} + +export default ShowCastInfoFormContent; diff --git a/apps/admin/src/components/ShowInfoFormContent/ShowDetailInfoFormContent.tsx b/apps/admin/src/components/ShowInfoFormContent/ShowDetailInfoFormContent.tsx index f6e3dd25..36774ed4 100644 --- a/apps/admin/src/components/ShowInfoFormContent/ShowDetailInfoFormContent.tsx +++ b/apps/admin/src/components/ShowInfoFormContent/ShowDetailInfoFormContent.tsx @@ -23,7 +23,11 @@ const ShowDetailInfoFormContent = ({ form, disabled }: ShowDetailInfoFormContent return ( - 상세 정보 + + + 상세 정보 + + 공연 내용 diff --git a/apps/admin/src/components/ShowInfoFormContent/ShowInfoFormContent.styles.ts b/apps/admin/src/components/ShowInfoFormContent/ShowInfoFormContent.styles.ts index 79be6da0..51fcd143 100644 --- a/apps/admin/src/components/ShowInfoFormContent/ShowInfoFormContent.styles.ts +++ b/apps/admin/src/components/ShowInfoFormContent/ShowInfoFormContent.styles.ts @@ -31,16 +31,37 @@ interface MobileTicketActionProps { const ShowInfoFormGroup = styled.div``; +const ShowInfoFormGroupHeader = styled.div` + display: flex; + justify-content: space-between; +` + +const ShowInfoFormGroupInfo = styled.div` + flex: 1; + margin-bottom: 16px; + display: flex; + flex-direction: column; + gap: 2px; +` + const ShowInfoFormTitle = styled.h3` ${({ theme }) => theme.typo.sh2}; color: ${({ theme }) => theme.palette.grey.g90}; - margin-bottom: 16px; ${mq_lg} { ${({ theme }) => theme.typo.h1}; } `; +const ShowInfoFormSubtitle = styled.p` + ${({ theme }) => theme.typo.b1}; + color: ${({ theme }) => theme.palette.grey.g60}; + + strong { + font-weight: 600; + } +` + const ShowInfoFormRow = styled.div` margin-bottom: 28px; display: flex; @@ -84,7 +105,7 @@ const ShowInfoFormButtonContainer = styled.div` gap: 8px; `; -const ShowInfoFormButton = styled(Button)` +const ShowInfoFormButton = styled(Button) ` width: ${({ width }) => width}; `; @@ -251,7 +272,7 @@ const TextArea = styled.textarea` padding: 12px; border: 1px solid ${({ theme, hasError }) => - hasError ? `${theme.palette.status.error} !important` : theme.palette.grey.g20}; + hasError ? `${theme.palette.status.error} !important` : theme.palette.grey.g20}; border-radius: 4px; background-color: ${({ theme }) => theme.palette.grey.w}; color: ${({ theme }) => theme.palette.grey.g90}; @@ -503,7 +524,7 @@ const MobileTicketAction = styled.div` width: 24px; height: 24px; stroke: ${({ theme, disabled }) => - disabled ? theme.palette.grey.g40 : theme.palette.grey.g90}; + disabled ? theme.palette.grey.g40 : theme.palette.grey.g90}; } } } @@ -515,7 +536,10 @@ const MobileTicketAction = styled.div` export default { ShowInfoFormGroup, + ShowInfoFormGroupHeader, + ShowInfoFormGroupInfo, ShowInfoFormTitle, + ShowInfoFormSubtitle, ShowInfoFormRow, ShowInfoFormContent, ShowInfoFormLabel, diff --git a/apps/admin/src/pages/ShowAddPage/index.tsx b/apps/admin/src/pages/ShowAddPage/index.tsx index d55a2bb4..752d0b27 100644 --- a/apps/admin/src/pages/ShowAddPage/index.tsx +++ b/apps/admin/src/pages/ShowAddPage/index.tsx @@ -18,6 +18,7 @@ import { ShowInfoFormInputs, ShowTicketFormInputs } from '~/components/ShowInfoF import { PATH } from '~/constants/routes'; import Styled from './ShowAddPage.styles'; +import ShowCastInfoFormContent from '~/components/ShowInfoFormContent/ShowCastInfoFormContent'; interface ShowAddPageProps { step: 'info' | 'ticket'; @@ -145,6 +146,9 @@ const ShowAddPage = ({ step }: ShowAddPageProps) => { + + + - ) -} + ); +}; export default ShowCastInfoFormContent; From 4933c082b66175f122e21f7603ae6acb27d31caa Mon Sep 17 00:00:00 2001 From: Minsu Kim Date: Sat, 5 Oct 2024 12:48:43 +0900 Subject: [PATCH 03/19] =?UTF-8?q?feat:=20=EB=AA=A9=EB=A1=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ShowCastInfoFormDialogContent.styles.ts | 13 +- .../ShowCastInfoFormDialogContent/index.tsx | 119 ++++++++++-------- 2 files changed, 76 insertions(+), 56 deletions(-) diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts b/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts index 40d9c419..b4a535bf 100644 --- a/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts @@ -28,12 +28,21 @@ const ShowInfoFormLabel = styled.label` } `; +const MemberList = styled.div` + max-height: 364px; + overflow-y: scroll; + ::-webkit-scrollbar { + display: none; + } +`; + const InputWrapper = styled.div` ${({ theme }) => theme.typo.b3}; border: 1px solid ${({ text, theme }) => (text ? theme.palette.grey.g90 : theme.palette.grey.g20)}; border-radius: 4px; background-color: ${({ theme }) => theme.palette.grey.w}; - padding: 12px; + padding: 8px 12px; + height: 48px; margin-right: 8px; flex: auto; position: relative; @@ -79,6 +88,7 @@ const MemberAddButton = styled.button` background: var(--W-White, #fff); ${({ theme }) => theme.typo.sh1}; color: ${({ theme }) => theme.palette.grey.g40}; + width: 536px; & > svg { margin-right: 8px; @@ -98,4 +108,5 @@ export default { TrashCanButton, MemberAddButton, RegisterButton, + MemberList, }; diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx index 525fdf5a..fce319d9 100644 --- a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx @@ -8,9 +8,8 @@ import { PlusIcon, TrashIcon } from '@boolti/icon'; type ShowCastInfoFormInputs = { name: string; members?: Array<{ - id?: number; userCode?: string; - roleName: string; + roleName?: string; }>; }; @@ -18,7 +17,7 @@ const ShowCastInfoFormDialogContent = () => { const { control, register } = useForm({ defaultValues: { members: [{}] }, }); - const { fields } = useFieldArray({ + const { fields, append, remove } = useFieldArray({ control, name: 'members', }); @@ -57,58 +56,68 @@ const ShowCastInfoFormDialogContent = () => { name="name" /> 팀원 - {fields.map((field, index) => ( - - ( - - # - { - onBlur(); - }} - value={value ?? ''} - /> - - )} - name={`members.${index}.userCode`} - /> - ( - - { - onBlur(); - }} - value={value ?? ''} - /> - - )} - name={`members.${index}.roleName`} - /> - - - - - ))} - - - 팀원 추가 - + + {fields.map((field, index) => ( + + ( + + # + { + onBlur(); + }} + value={value ?? ''} + /> + + )} + name={`members.${index}.userCode`} + /> + ( + + { + onBlur(); + }} + value={value ?? ''} + /> + + )} + name={`members.${index}.roleName`} + /> + { + remove(index); + }} + > + + + + ))} + { + append({}); + }} + > + + 팀원 추가 + + 등록하기 From 456febc8e55f83a444f2a4b64fec3f42189656f7 Mon Sep 17 00:00:00 2001 From: Minsu Kim Date: Sat, 5 Oct 2024 12:55:42 +0900 Subject: [PATCH 04/19] =?UTF-8?q?feat:=20=EB=B2=84=ED=8A=BC=20=EB=B9=84?= =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ShowCastInfoFormDialogContent.styles.ts | 2 +- .../src/components/ShowCastInfoFormDialogContent/index.tsx | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts b/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts index b4a535bf..63aacb17 100644 --- a/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts @@ -9,7 +9,7 @@ interface InputWrapperProps { text: string; } -const ShowInfoFormLabel = styled.label` +const ShowInfoFormLabel = styled.span` display: block; ${({ theme }) => theme.typo.b3}; color: ${({ theme }) => theme.palette.grey.g90}; diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx index fce319d9..014b94cd 100644 --- a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx @@ -14,7 +14,7 @@ type ShowCastInfoFormInputs = { }; const ShowCastInfoFormDialogContent = () => { - const { control, register } = useForm({ + const { control, getValues } = useForm({ defaultValues: { members: [{}] }, }); const { fields, append, remove } = useFieldArray({ @@ -22,6 +22,8 @@ const ShowCastInfoFormDialogContent = () => { name: 'members', }); + const disabled = !getValues('name'); + useBodyScrollLock(true); const [hasBlurred, setHasBlurred] = useState< @@ -118,7 +120,7 @@ const ShowCastInfoFormDialogContent = () => { 팀원 추가 - + 등록하기 From a2b3ca84fd41abfd66a7f9331b1fc5a6042028ac Mon Sep 17 00:00:00 2001 From: Minsu Kim Date: Sat, 5 Oct 2024 13:41:03 +0900 Subject: [PATCH 05/19] =?UTF-8?q?feat:=20=EC=84=9C=EB=B2=84=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=94=84=EB=A1=9C=ED=95=84=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=99=80=EC=84=9C=20=ED=8F=BC=EC=97=90=20?= =?UTF-8?q?=EC=84=B8=ED=8C=85=ED=95=98=EB=8A=94=20=EB=8F=99=EC=9E=91=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ShowCastInfoFormDialogContent.styles.ts | 29 +++++++- .../ShowCastInfoFormDialogContent/index.tsx | 68 +++++++++++++++---- apps/admin/src/utils/replace.ts | 6 ++ packages/api/src/queries/index.ts | 2 + packages/api/src/queries/useUserByUserCode.ts | 9 +++ packages/api/src/queryKey.ts | 12 +++- 6 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 apps/admin/src/utils/replace.ts create mode 100644 packages/api/src/queries/useUserByUserCode.ts diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts b/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts index 63aacb17..79f9fdfd 100644 --- a/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts @@ -84,7 +84,7 @@ const MemberAddButton = styled.button` width: 100%; border-radius: 4px; padding: 11px 0; - border: 1px dashed var(--W-G20, #d8dbe5); + border: 1px dashed ${({ theme }) => theme.palette.grey.g20}; background: var(--W-White, #fff); ${({ theme }) => theme.typo.sh1}; color: ${({ theme }) => theme.palette.grey.g40}; @@ -99,6 +99,30 @@ const RegisterButton = styled(Button)` margin: 32px 0 0 auto; `; +const UsrImage = styled.div` + box-sizing: border-box; + width: 32px; + height: 32px; + border-radius: 32px; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + background-image: var(--imgPath); +`; + +const Username = styled.span` + ${({ theme }) => theme.typo.b3}; + color: ${({ theme }) => theme.palette.grey.g90}; + margin: 0 8px; + flex: 1 1 auto; +`; + +const RemoveButton = styled.button` + width: 24px; + height: 24px; + cursor: pointer; +`; + export default { ShowInfoFormLabel, InputWrapper, @@ -109,4 +133,7 @@ export default { MemberAddButton, RegisterButton, MemberList, + UsrImage, + Username, + RemoveButton, }; diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx index 014b94cd..3d9bea84 100644 --- a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx @@ -3,24 +3,36 @@ import { Controller, useFieldArray, useForm } from 'react-hook-form'; import Styled from './ShowCastInfoFormDialogContent.styles'; import { useState } from 'react'; import { useBodyScrollLock } from '~/hooks/useBodyScrollLock'; -import { PlusIcon, TrashIcon } from '@boolti/icon'; +import { ClearIcon, CloseIcon, PlusIcon, TrashIcon } from '@boolti/icon'; +import { queryKeys, useQueryClient } from '@boolti/api'; +import { replaceUserCode } from '~/utils/replace'; type ShowCastInfoFormInputs = { name: string; members?: Array<{ + imgPath?: string; + nickname?: string; userCode?: string; roleName?: string; }>; }; const ShowCastInfoFormDialogContent = () => { - const { control, getValues } = useForm({ + const queryClient = useQueryClient(); + const { control, getValues, setValue, watch } = useForm({ defaultValues: { members: [{}] }, }); - const { fields, append, remove } = useFieldArray({ + const { fields, append, remove, update } = useFieldArray({ control, name: 'members', }); + const watchMemberFields = watch('members') ?? []; + const controlledFields = fields.map((field, index) => { + return { + ...field, + ...watchMemberFields[index], + }; + }); const disabled = !getValues('name'); @@ -59,7 +71,7 @@ const ShowCastInfoFormDialogContent = () => { /> 팀원 - {fields.map((field, index) => ( + {controlledFields.map((field, index) => ( { }} render={({ field: { onChange, onBlur, value } }) => ( - # - { - onBlur(); - }} - value={value ?? ''} - /> + {field.imgPath && field.nickname ? ( + <> + + {field.nickname} + { + update(index, { roleName: field.roleName }); + }} + > + + + + ) : ( + <> + # + { + const nextValue = replaceUserCode(e.target.value); + onChange(nextValue); + }} + onBlur={async (event) => { + onBlur(); + const userCode = event.target.value; + if (userCode !== '') { + const { imgPath, nickname } = await queryClient.fetchQuery( + queryKeys.user.userCode(event.target.value), + ); + update(index, { ...field, imgPath, nickname }); + } + }} + value={value ?? ''} + /> + + )} )} name={`members.${index}.userCode`} diff --git a/apps/admin/src/utils/replace.ts b/apps/admin/src/utils/replace.ts new file mode 100644 index 00000000..2df251e7 --- /dev/null +++ b/apps/admin/src/utils/replace.ts @@ -0,0 +1,6 @@ +export const replaceUserCode = (text: string) => { + return text + .replace(/[^a-z0-9]/gi, '') + .toUpperCase() + .slice(0, 8); +}; diff --git a/packages/api/src/queries/index.ts b/packages/api/src/queries/index.ts index 4e55406d..de925177 100644 --- a/packages/api/src/queries/index.ts +++ b/packages/api/src/queries/index.ts @@ -30,8 +30,10 @@ import useAdminShowInfo from './useAdminShowInfo'; import useAdminReservations from './useAdminReservations'; import useAdminReservationSummary from './useAdminReservationSummary'; import useUserProfile from './useUserProfile'; +import useUserByUserCode from './useUserByUserCode'; export { + useUserByUserCode, useAdminSettlementEvent, useAdminSettlementInfo, useGift, diff --git a/packages/api/src/queries/useUserByUserCode.ts b/packages/api/src/queries/useUserByUserCode.ts new file mode 100644 index 00000000..5dffff93 --- /dev/null +++ b/packages/api/src/queries/useUserByUserCode.ts @@ -0,0 +1,9 @@ +import { useQuery } from '@tanstack/react-query'; + +import { queryKeys } from '../queryKey'; + +const useUserByUserCode = (userCode: string) => { + return useQuery({ ...queryKeys.user.userCode(userCode) }); +}; + +export default useUserByUserCode; diff --git a/packages/api/src/queryKey.ts b/packages/api/src/queryKey.ts index 7040ba91..838d552d 100644 --- a/packages/api/src/queryKey.ts +++ b/packages/api/src/queryKey.ts @@ -30,7 +30,11 @@ import { SuperAdminShowStatus, TicketSalesInfoResponse, } from './types/adminShow'; -import { BankAccountListResponse, UserProfileResponse, UserProfileSummaryResponse } from './types/users'; +import { + BankAccountListResponse, + UserProfileResponse, + UserProfileSummaryResponse, +} from './types/users'; import { GiftInfoResponse } from './types/gift'; import { HostListItem, HostListResponse } from './types/host'; import { @@ -295,7 +299,7 @@ export const showQueryKeys = createQueryKeys('show', { export const userQueryKeys = createQueryKeys('user', { profile: { queryKey: null, - queryFn: () => fetcher.get('web/v1/users/me') + queryFn: () => fetcher.get('web/v1/users/me'), }, summary: { queryKey: null, @@ -305,6 +309,10 @@ export const userQueryKeys = createQueryKeys('user', { queryKey: null, queryFn: () => fetcher.get(`web/v1/host/users/me/bank-accounts`), }, + userCode: (userCode: string) => ({ + queryKey: [userCode], + queryFn: () => fetcher.get(`web/papi/v1/users/${userCode}`), + }), }); export const giftQueryKeys = createQueryKeys('gift', { From 8980d2c9ff8def0f9edff89dcec866a3c04174be Mon Sep 17 00:00:00 2001 From: Minsu Kim Date: Sat, 5 Oct 2024 13:46:15 +0900 Subject: [PATCH 06/19] =?UTF-8?q?feat:=20=ED=8C=80=EB=AA=85=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EB=85=B8=EC=B6=9C=20=EC=B6=94=EA=B0=80=20=EB=B0=8F?= =?UTF-8?q?=20=EA=B0=84=EA=B2=A9=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ShowCastInfoFormDialogContent.styles.ts | 5 +++- .../ShowCastInfoFormDialogContent/index.tsx | 25 ++++++++++--------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts b/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts index 79f9fdfd..a1bc32cc 100644 --- a/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts @@ -24,7 +24,7 @@ const ShowInfoFormLabel = styled.span` } &:not(:first-of-type) { - margin-top: 20px; + margin-top: 28px; } `; @@ -50,6 +50,8 @@ const InputWrapper = styled.div` align-items: center; `; +const TextFieldWrap = styled.div``; + const HashTag = styled.span` color: ${({ theme }) => theme.palette.grey.g90}; line-height: 24px; @@ -136,4 +138,5 @@ export default { UsrImage, Username, RemoveButton, + TextFieldWrap, }; diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx index 3d9bea84..4c82bd5d 100644 --- a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx @@ -54,18 +54,19 @@ const ShowCastInfoFormDialogContent = () => { required: true, }} render={({ field: { onChange, onBlur, value } }) => ( - - { - onBlur(); - setHasBlurred((prev) => ({ ...prev, name: true })); - }} - value={value ?? ''} - /> - + { + onBlur(); + setHasBlurred((prev) => ({ ...prev, name: true })); + }} + value={value ?? ''} + errorMessage={hasBlurred.name && !value ? '필수 입력사항입니다.' : undefined} + /> )} name="name" /> From d769189ca13643053d5b87112b1701d88d10401d Mon Sep 17 00:00:00 2001 From: Minsu Kim Date: Sat, 5 Oct 2024 13:50:59 +0900 Subject: [PATCH 07/19] =?UTF-8?q?feat:=20=ED=8C=80=EB=AA=85=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EC=B0=BD=20=EB=84=88=EB=B9=84=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ShowCastInfoFormDialogContent.styles.ts | 12 ++++--- .../ShowCastInfoFormDialogContent/index.tsx | 34 ++++++++++--------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts b/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts index a1bc32cc..da31a916 100644 --- a/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/ShowCastInfoFormDialogContent.styles.ts @@ -22,10 +22,6 @@ const ShowInfoFormLabel = styled.span` display: ${({ required }) => (required ? 'inline' : 'none')}; margin-left: 2px; } - - &:not(:first-of-type) { - margin-top: 28px; - } `; const MemberList = styled.div` @@ -50,7 +46,13 @@ const InputWrapper = styled.div` align-items: center; `; -const TextFieldWrap = styled.div``; +const TextFieldWrap = styled.div` + margin-bottom: 28px; + + & > div { + width: auto; + } +`; const HashTag = styled.span` color: ${({ theme }) => theme.palette.grey.g90}; diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx index 4c82bd5d..62b956a6 100644 --- a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx @@ -1,9 +1,9 @@ -import { Button, TextButton, TextField } from '@boolti/ui'; +import { TextField } from '@boolti/ui'; import { Controller, useFieldArray, useForm } from 'react-hook-form'; import Styled from './ShowCastInfoFormDialogContent.styles'; import { useState } from 'react'; import { useBodyScrollLock } from '~/hooks/useBodyScrollLock'; -import { ClearIcon, CloseIcon, PlusIcon, TrashIcon } from '@boolti/icon'; +import { ClearIcon, PlusIcon, TrashIcon } from '@boolti/icon'; import { queryKeys, useQueryClient } from '@boolti/api'; import { replaceUserCode } from '~/utils/replace'; @@ -19,7 +19,7 @@ type ShowCastInfoFormInputs = { const ShowCastInfoFormDialogContent = () => { const queryClient = useQueryClient(); - const { control, getValues, setValue, watch } = useForm({ + const { control, getValues, watch } = useForm({ defaultValues: { members: [{}] }, }); const { fields, append, remove, update } = useFieldArray({ @@ -54,19 +54,21 @@ const ShowCastInfoFormDialogContent = () => { required: true, }} render={({ field: { onChange, onBlur, value } }) => ( - { - onBlur(); - setHasBlurred((prev) => ({ ...prev, name: true })); - }} - value={value ?? ''} - errorMessage={hasBlurred.name && !value ? '필수 입력사항입니다.' : undefined} - /> + + { + onBlur(); + setHasBlurred((prev) => ({ ...prev, name: true })); + }} + value={value ?? ''} + errorMessage={hasBlurred.name && !value ? '필수 입력사항입니다.' : undefined} + /> + )} name="name" /> From 4145bb95bcece4594b92a8e7526ed233bdb42d87 Mon Sep 17 00:00:00 2001 From: Minsu Kim Date: Sat, 5 Oct 2024 14:36:03 +0900 Subject: [PATCH 08/19] =?UTF-8?q?feat:=20=ED=8C=80=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=ED=83=80=EC=9E=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ShowInfoFormContent/types.ts | 9 +++++ packages/api/src/types/cast.ts | 33 +++++++++++++++++++ packages/api/src/types/index.ts | 1 + 3 files changed, 43 insertions(+) create mode 100644 packages/api/src/types/cast.ts diff --git a/apps/admin/src/components/ShowInfoFormContent/types.ts b/apps/admin/src/components/ShowInfoFormContent/types.ts index c82df41d..53503244 100644 --- a/apps/admin/src/components/ShowInfoFormContent/types.ts +++ b/apps/admin/src/components/ShowInfoFormContent/types.ts @@ -16,3 +16,12 @@ export interface ShowTicketFormInputs { endDate: string; ticketNotice: string; } + +export interface ShowTeamFromInputs { + name: string; + members?: Array<{ + id?: number; + userCode: string; + roleName: string; + }>; +} diff --git a/packages/api/src/types/cast.ts b/packages/api/src/types/cast.ts new file mode 100644 index 00000000..2d9a3816 --- /dev/null +++ b/packages/api/src/types/cast.ts @@ -0,0 +1,33 @@ +export interface ShowCastTeamReadResponse { + /** 출연진 팀 식별자 */ + id: number; + /** 출연진 팀 이름 */ + name: string; + /** 출연진 팀 멤버 목록 */ + members?: Array<{ + /** 공연 출연진 팀원 ID */ + id: number; + /** 유저 식별 코드 */ + userCode: string; + /** 역할 이름 (1~100자. 빈 문자열 불가) */ + roleName: string; + }>; + /** 팀 생성 일시 */ + createdAt: string; + /** 팀 수정 일시 */ + modifiedAt: string; +} + +export interface ShowCastTeamUpdateRequest { + /** 팀 이름 */ + name: ShowCastTeamReadResponse['name']; + /** 팀원 목록 */ + members: ShowCastTeamReadResponse['members']; +} + +export interface ShowCastTeamCreateRequest { + /** 팀 이름 */ + name: ShowCastTeamReadResponse['name']; + /** 팀원 목록 */ + members: ShowCastTeamReadResponse['members']; +} diff --git a/packages/api/src/types/index.ts b/packages/api/src/types/index.ts index 42d25db0..d4c560d2 100644 --- a/packages/api/src/types/index.ts +++ b/packages/api/src/types/index.ts @@ -2,3 +2,4 @@ export * from './common'; export * from './entrance'; export * from './show'; export * from './users'; +export * from './cast'; From e63f0b84aface92cc4a4d25f2d460baf713dd95c Mon Sep 17 00:00:00 2001 From: Minsu Kim Date: Sat, 5 Oct 2024 15:04:40 +0900 Subject: [PATCH 09/19] =?UTF-8?q?feat:=20=EB=8B=A4=EC=9D=B4=EC=96=BC?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EB=8B=AB=EB=8A=94=20=EA=B3=BC=EC=A0=95?= =?UTF-8?q?=EA=B9=8C=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LinkFormDialogContent.styles.ts | 20 +- .../LinkFormDialogContent/index.tsx | 21 +- .../SettingDialogContent.styles.ts | 36 +- .../components/SettingDialogContent/index.tsx | 317 ++++++++++-------- .../ShowCastInfoFormDialogContent/index.tsx | 33 +- .../ShowCastInfoFormDialogContent/types.ts | 9 + .../ShowCastInfoFormContent.tsx | 16 +- .../ShowInfoFormContent.styles.ts | 12 +- apps/admin/src/pages/ShowAddPage/index.tsx | 11 +- packages/api/src/mutations/useDeleteMe.ts | 6 +- packages/api/src/types/users.ts | 14 +- .../icon/src/components/BooltiLightGrey.tsx | 40 ++- packages/icon/src/components/Call.tsx | 13 +- packages/icon/src/components/Logout.tsx | 35 +- packages/icon/src/components/Message.tsx | 11 +- packages/icon/src/components/Photo.tsx | 19 +- packages/icon/src/components/index.ts | 2 +- .../ui/src/components/Drawer/Drawer.styles.ts | 2 +- .../ui/src/components/Footer/Footer.styles.ts | 2 +- .../ShowPreview/ShowPreview.styles.ts | 20 +- .../components/TextField/TextField.styles.ts | 2 +- 21 files changed, 408 insertions(+), 233 deletions(-) create mode 100644 apps/admin/src/components/ShowCastInfoFormDialogContent/types.ts diff --git a/apps/admin/src/components/LinkFormDialogContent/LinkFormDialogContent.styles.ts b/apps/admin/src/components/LinkFormDialogContent/LinkFormDialogContent.styles.ts index d72debe3..e0234826 100644 --- a/apps/admin/src/components/LinkFormDialogContent/LinkFormDialogContent.styles.ts +++ b/apps/admin/src/components/LinkFormDialogContent/LinkFormDialogContent.styles.ts @@ -1,5 +1,5 @@ -import styled from '@emotion/styled' -import { mq_lg } from '@boolti/ui' +import styled from '@emotion/styled'; +import { mq_lg } from '@boolti/ui'; interface LabelProps { required?: boolean; @@ -17,7 +17,7 @@ const LinkForm = styled.form` ${mq_lg} { padding: 0; } -` +`; const LinkFormControl = styled.div` margin-bottom: 28px; @@ -25,7 +25,7 @@ const LinkFormControl = styled.div` & > div { width: 100%; } -` +`; const LinkFormButtonWrapper = styled.div` display: flex; @@ -35,7 +35,7 @@ const LinkFormButtonWrapper = styled.div` margin-top: 4px; button { - width: ${({ isEditMode }) => isEditMode ? 'auto' : '100%'}; + width: ${({ isEditMode }) => (isEditMode ? 'auto' : '100%')}; } ${mq_lg} { @@ -43,7 +43,7 @@ const LinkFormButtonWrapper = styled.div` width: auto; } } -` +`; const Label = styled.label` ${({ theme }) => theme.typo.b3}; @@ -53,7 +53,7 @@ const Label = styled.label` position: relative; &::after { - content: ${({ required }) => (required ? "'*'" : "none")}; + content: ${({ required }) => (required ? "'*'" : 'none')}; color: ${({ theme }) => theme.palette.status.error}; ${({ theme }) => theme.typo.b1}; line-height: 22px; @@ -66,12 +66,12 @@ const LinkDeleteButton = styled.button` line-height: 22px; text-decoration: underline; cursor: pointer; -` +`; export default { LinkForm, LinkFormControl, LinkFormButtonWrapper, Label, - LinkDeleteButton -} + LinkDeleteButton, +}; diff --git a/apps/admin/src/components/LinkFormDialogContent/index.tsx b/apps/admin/src/components/LinkFormDialogContent/index.tsx index eca6822b..5d18d9b5 100644 --- a/apps/admin/src/components/LinkFormDialogContent/index.tsx +++ b/apps/admin/src/components/LinkFormDialogContent/index.tsx @@ -11,9 +11,13 @@ interface LinkFormDialogContentProps { onDelete?: () => void; } -const LinkFormDialogContent = ({ defaultValues, onSubmit, onDelete }: LinkFormDialogContentProps) => { +const LinkFormDialogContent = ({ + defaultValues, + onSubmit, + onDelete, +}: LinkFormDialogContentProps) => { const linkForm = useForm({ - defaultValues + defaultValues, }); const isEditMode = !!defaultValues; @@ -23,7 +27,7 @@ const LinkFormDialogContent = ({ defaultValues, onSubmit, onDelete }: LinkFormDi title: data.title.trim(), link: data.link.trim(), }); - } + }; return ( @@ -47,7 +51,12 @@ const LinkFormDialogContent = ({ defaultValues, onSubmit, onDelete }: LinkFormDi /> - {isEditMode && onDelete && ( @@ -57,7 +66,7 @@ const LinkFormDialogContent = ({ defaultValues, onSubmit, onDelete }: LinkFormDi )} - ) -} + ); +}; export default LinkFormDialogContent; diff --git a/apps/admin/src/components/SettingDialogContent/SettingDialogContent.styles.ts b/apps/admin/src/components/SettingDialogContent/SettingDialogContent.styles.ts index 52922741..6fe6a179 100644 --- a/apps/admin/src/components/SettingDialogContent/SettingDialogContent.styles.ts +++ b/apps/admin/src/components/SettingDialogContent/SettingDialogContent.styles.ts @@ -116,7 +116,7 @@ const SettingContentHeader = styled.div` display: flex; justify-content: space-between; } -` +`; const SettingContentTitle = styled.h3` ${({ theme }) => theme.typo.h1}; @@ -134,7 +134,7 @@ const SettingContentSubmitWrapper = styled.div` ${mq_lg} { display: block; } -` +`; const SettingContentSubmitWrapperMobile = styled.div` position: fixed; @@ -154,9 +154,9 @@ const SettingContentSubmitWrapperMobile = styled.div` ${mq_lg} { display: none; } -` +`; -const SettingContentForm = styled.form`` +const SettingContentForm = styled.form``; const SettingContentFormControl = styled.div` margin-bottom: 24px; @@ -173,14 +173,14 @@ const ProfileImageWrapper = styled.div` width: 100px; height: 100px; } -` +`; const ProfileImage = styled.img` width: 100px; height: 100px; border-radius: 100px; object-fit: cover; -` +`; const DefaultProfileImage = styled(DefaultUserProfileIcon)` border-radius: 100px; @@ -200,7 +200,7 @@ const ProfileImageEditButton = styled.label` bottom: 0; left: calc(100px - 42px + 8px); cursor: pointer; -` +`; const Label = styled.label` ${({ theme }) => theme.typo.b3}; @@ -210,7 +210,7 @@ const Label = styled.label` position: relative; &::after { - content: ${({ required }) => (required ? "'*'" : "none")}; + content: ${({ required }) => (required ? "'*'" : 'none')}; color: ${({ theme }) => theme.palette.status.error}; ${({ theme }) => theme.typo.b1}; line-height: 22px; @@ -231,19 +231,19 @@ const LinkItem = styled.div` align-items: center; gap: 16px; height: 56px; -` +`; const LinkInfo = styled.div` display: flex; flex-direction: column; gap: 2px; min-width: 0; -` +`; const LinkTitle = styled.p` ${({ theme }) => theme.typo.sh1}; color: ${({ theme }) => theme.palette.grey.g90}; -` +`; const LinkDescription = styled.p` ${({ theme }) => theme.typo.b1}; @@ -251,7 +251,7 @@ const LinkDescription = styled.p` overflow: hidden; white-space: nowrap; text-overflow: ellipsis; -` +`; const LinkEditButton = styled.button` width: 24px; @@ -260,7 +260,7 @@ const LinkEditButton = styled.button` justify-content: center; align-items: center; cursor: pointer; -` +`; const ConnectedServiceList = styled.div` display: flex; @@ -314,12 +314,12 @@ const SettingDescriptionItem = styled.li``; const TextAreaWrapper = styled.div` position: relative; height: 122px; -` +`; const TextAreaBox = styled.div` border: 1px solid ${({ theme, hasError }) => - hasError ? `${theme.palette.status.error} !important` : theme.palette.grey.g20}; + hasError ? `${theme.palette.status.error} !important` : theme.palette.grey.g20}; border-radius: 4px; background-color: ${({ theme }) => theme.palette.grey.w}; position: absolute; @@ -341,13 +341,13 @@ const TextAreaBox = styled.div` border: 1px solid ${({ theme }) => theme.palette.grey.g20}; background: ${({ theme }) => theme.palette.grey.g10}; } -` +`; const TextArea = styled.textarea` position: absolute; top: 0; left: 0; - width: calc(100% - 12px - 12px); + width: calc(100% - 12px - 12px); height: 72px; margin: 12px 12px 38px; color: ${({ theme }) => theme.palette.grey.g90}; @@ -368,7 +368,7 @@ const TextAreaCount = styled.span` bottom: 12px; right: 12px; z-index: 3; -` +`; export default { SettingDialogContent, diff --git a/apps/admin/src/components/SettingDialogContent/index.tsx b/apps/admin/src/components/SettingDialogContent/index.tsx index bae743aa..12b1c0ff 100644 --- a/apps/admin/src/components/SettingDialogContent/index.tsx +++ b/apps/admin/src/components/SettingDialogContent/index.tsx @@ -36,7 +36,7 @@ const AppleIcon = () => { type ProfileFormInputs = { nickname: string; introduction: string; -} +}; interface SettingDialogContentProps { onDeleteAccount?: () => void; @@ -51,7 +51,7 @@ const NICKNAME_ERROR_MESSAGE = { required: '1자 이상 입력해 주세요.', minLength: '1자 이상 입력해 주세요.', maxLength: `${MAX_NICKNAME_LENGTH}자 이내로 입력해 주세요.`, -} +}; const SettingDialogContent = ({ onDeleteAccount }: SettingDialogContentProps) => { const theme = useTheme(); @@ -64,7 +64,8 @@ const SettingDialogContent = ({ onDeleteAccount }: SettingDialogContentProps) => const uploadProfileImageMutation = useUploadProfileImage(); const editProfileMutation = useEditUserProfile(); - const { register, handleSubmit, setValue, watch, setError, clearErrors, formState } = useForm(); + const { register, handleSubmit, setValue, watch, setError, clearErrors, formState } = + useForm(); const [profileImageFile, setProfileImageFile] = useState(null); const [profileImagePreview, setProfileImagePreview] = useState(null); @@ -78,7 +79,7 @@ const SettingDialogContent = ({ onDeleteAccount }: SettingDialogContentProps) => if (files && files.length > 0) { setProfileImageFile(files[0]); } - } + }; const submitHandler = async (data: ProfileFormInputs) => { if (editProfileMutation.isLoading) return; @@ -107,7 +108,7 @@ const SettingDialogContent = ({ onDeleteAccount }: SettingDialogContentProps) => } catch (error) { toast.error('프로필 정보를 저장하는 중 문제가 발생했습니다.'); } - } + }; useEffect(() => { if (!userProfile) return; @@ -116,29 +117,37 @@ const SettingDialogContent = ({ onDeleteAccount }: SettingDialogContentProps) => setValue('introduction', userProfile.introduction ?? ''); setLinks(userProfile.link); - }, [setValue, userProfile]) + }, [setValue, userProfile]); useEffect(() => { - if (!profileImageFile) return + if (!profileImageFile) return; - const url = URL.createObjectURL(profileImageFile) - setProfileImagePreview(url) + const url = URL.createObjectURL(profileImageFile); + setProfileImagePreview(url); - return () => URL.revokeObjectURL(url) - }, [profileImageFile]) + return () => URL.revokeObjectURL(url); + }, [profileImageFile]); return ( - { - setCurrentMenu('profile'); - }}> + { + setCurrentMenu('profile'); + }} + > 프로필 - { - setCurrentMenu('account'); - }}> + { + setCurrentMenu('account'); + }} + > 계정 @@ -160,19 +169,29 @@ const SettingDialogContent = ({ onDeleteAccount }: SettingDialogContentProps) => {profileImagePreview ?? userProfile?.imgPath ? ( - + ) : ( )} - + - 닉네임 + + 닉네임 + // 문자열이 0자일 때 에러 메시지 출력 if (event.target.value.trim().length === 0) { - setError('nickname', { type: 'minLength', message: NICKNAME_ERROR_MESSAGE.minLength }); + setError('nickname', { + type: 'minLength', + message: NICKNAME_ERROR_MESSAGE.minLength, + }); - return + return; } // 문자열 20자 초과 시 에러 메시지 출력 if (event.target.value.trim().length > MAX_NICKNAME_LENGTH) { - setError('nickname', { type: 'maxLength', message: NICKNAME_ERROR_MESSAGE.maxLength }); + setError('nickname', { + type: 'maxLength', + message: NICKNAME_ERROR_MESSAGE.maxLength, + }); - return + return; } // 이외의 경우에는 에러 메시지 미출력 - clearErrors('nickname') - } + clearErrors('nickname'); + }, })} /> @@ -225,7 +250,8 @@ const SettingDialogContent = ({ onDeleteAccount }: SettingDialogContentProps) => placeholder="예) 재즈와 펑크락을 좋아해요" maxLength={MAX_INTRODUCTION_LENGTH} {...register('introduction', { - maxLength: MAX_INTRODUCTION_LENGTH, onChange(event) { + maxLength: MAX_INTRODUCTION_LENGTH, + onChange(event) { if (event.target.value.length > MAX_INTRODUCTION_LENGTH) { event.target.value = event.target.value.slice(0, MAX_INTRODUCTION_LENGTH); } @@ -242,19 +268,25 @@ const SettingDialogContent = ({ onDeleteAccount }: SettingDialogContentProps) => SNS 링크 - @@ -265,30 +297,40 @@ const SettingDialogContent = ({ onDeleteAccount }: SettingDialogContentProps) => {link.title} {link.link} - { - linkDialog.open({ - title: '링크 편집', - content: ( - { - setLinks((prev) => prev.map((item) => { - if (item.title === link.title && item.link === link.link) { - return { title: data.title, link: data.link }; - } - - return item; - })); - linkDialog.close(); - }} - onDelete={() => { - setLinks((prev) => prev.filter((item) => item.title !== link.title && item.link !== link.link)); - linkDialog.close(); - }} - /> - ), - }) - }}> + { + linkDialog.open({ + title: '링크 편집', + content: ( + { + setLinks((prev) => + prev.map((item) => { + if (item.title === link.title && item.link === link.link) { + return { title: data.title, link: data.link }; + } + + return item; + }), + ); + linkDialog.close(); + }} + onDelete={() => { + setLinks((prev) => + prev.filter( + (item) => + item.title !== link.title && item.link !== link.link, + ), + ); + linkDialog.close(); + }} + /> + ), + }); + }} + > @@ -297,85 +339,84 @@ const SettingDialogContent = ({ onDeleteAccount }: SettingDialogContentProps) => - + )} - { - currentMenu === 'account' && ( - - - 계정 - - - 식별 코드 - { - event.preventDefault(); - }} - style={{ caretColor: 'transparent' }} - /> - - - 연결 서비스 - - {userProfile?.oauthType === 'KAKAO' && ( - - 카카오 - - )} - {userProfile?.oauthType === 'APPLE' && ( - - Apple - - )} - - - - 계정 삭제 - - - 주최한 공연 정보는 사라지지 않아요. - - - 예매한 티켓은 전부 사라지며 복구할 수 없어요. - - - 삭제일로 부터 30일 이내 재 로그인 시 삭제를 취소할 수 있어요. - - - - - ) - } - - + style={{ caretColor: 'transparent' }} + /> + + + 연결 서비스 + + {userProfile?.oauthType === 'KAKAO' && ( + + 카카오 + + )} + {userProfile?.oauthType === 'APPLE' && ( + + Apple + + )} + + + + 계정 삭제 + + + 주최한 공연 정보는 사라지지 않아요. + + + 예매한 티켓은 전부 사라지며 복구할 수 없어요. + + + 삭제일로 부터 30일 이내 재 로그인 시 삭제를 취소할 수 있어요. + + + + + )} + ); }; diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx index 62b956a6..73728253 100644 --- a/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/index.tsx @@ -6,8 +6,9 @@ import { useBodyScrollLock } from '~/hooks/useBodyScrollLock'; import { ClearIcon, PlusIcon, TrashIcon } from '@boolti/icon'; import { queryKeys, useQueryClient } from '@boolti/api'; import { replaceUserCode } from '~/utils/replace'; +import { ShowCastInfoFormInput } from './types'; -type ShowCastInfoFormInputs = { +interface TempShowCastInfoFormInput { name: string; members?: Array<{ imgPath?: string; @@ -15,11 +16,16 @@ type ShowCastInfoFormInputs = { userCode?: string; roleName?: string; }>; -}; +} + +interface Props { + setValue: (value: ShowCastInfoFormInput) => void; +} -const ShowCastInfoFormDialogContent = () => { +const ShowCastInfoFormDialogContent = ({ setValue }: Props) => { const queryClient = useQueryClient(); - const { control, getValues, watch } = useForm({ + + const { control, getValues, watch } = useForm({ defaultValues: { members: [{}] }, }); const { fields, append, remove, update } = useFieldArray({ @@ -39,7 +45,7 @@ const ShowCastInfoFormDialogContent = () => { useBodyScrollLock(true); const [hasBlurred, setHasBlurred] = useState< - Record + Record >({ name: false, members: [], @@ -163,7 +169,22 @@ const ShowCastInfoFormDialogContent = () => { 팀원 추가 - + { + e.preventDefault(); + + const name = getValues('name'); + const members = (getValues('members') ?? []).filter((member) => + Object.values(member).every(Boolean), + ) as ShowCastInfoFormInput['members']; + + setValue({ name, members }); + }} + > 등록하기 diff --git a/apps/admin/src/components/ShowCastInfoFormDialogContent/types.ts b/apps/admin/src/components/ShowCastInfoFormDialogContent/types.ts new file mode 100644 index 00000000..c376075a --- /dev/null +++ b/apps/admin/src/components/ShowCastInfoFormDialogContent/types.ts @@ -0,0 +1,9 @@ +import { ShowCastTeamCreateRequest, UserProfileResponse } from '@boolti/api'; + +export type ShowCastInfoFormInput = { + name: ShowCastTeamCreateRequest['name']; + members?: Array< + Exclude[number] & + Pick + >; +}; diff --git a/apps/admin/src/components/ShowInfoFormContent/ShowCastInfoFormContent.tsx b/apps/admin/src/components/ShowInfoFormContent/ShowCastInfoFormContent.tsx index 718725c7..5d274c0d 100644 --- a/apps/admin/src/components/ShowInfoFormContent/ShowCastInfoFormContent.tsx +++ b/apps/admin/src/components/ShowInfoFormContent/ShowCastInfoFormContent.tsx @@ -3,8 +3,13 @@ import { Button, useDialog } from '@boolti/ui'; import Styled from './ShowInfoFormContent.styles'; import { PlusIcon } from '@boolti/icon'; import ShowCastInfoFormDialogContent from '../ShowCastInfoFormDialogContent'; +import { ShowCastInfoFormInput } from '../ShowCastInfoFormDialogContent/types'; -const ShowCastInfoFormContent = () => { +interface Props { + setValue: (value: ShowCastInfoFormInput) => void; +} + +const ShowCastInfoFormContent = ({ setValue }: Props) => { const dialog = useDialog(); return ( @@ -27,7 +32,14 @@ const ShowCastInfoFormContent = () => { dialog.open({ isAuto: true, title: '출연진 정보 등록', - content: , + content: ( + { + setValue(value); + dialog.close(); + }} + /> + ), }); }} > diff --git a/apps/admin/src/components/ShowInfoFormContent/ShowInfoFormContent.styles.ts b/apps/admin/src/components/ShowInfoFormContent/ShowInfoFormContent.styles.ts index 51fcd143..19b414c9 100644 --- a/apps/admin/src/components/ShowInfoFormContent/ShowInfoFormContent.styles.ts +++ b/apps/admin/src/components/ShowInfoFormContent/ShowInfoFormContent.styles.ts @@ -34,7 +34,7 @@ const ShowInfoFormGroup = styled.div``; const ShowInfoFormGroupHeader = styled.div` display: flex; justify-content: space-between; -` +`; const ShowInfoFormGroupInfo = styled.div` flex: 1; @@ -42,7 +42,7 @@ const ShowInfoFormGroupInfo = styled.div` display: flex; flex-direction: column; gap: 2px; -` +`; const ShowInfoFormTitle = styled.h3` ${({ theme }) => theme.typo.sh2}; @@ -60,7 +60,7 @@ const ShowInfoFormSubtitle = styled.p` strong { font-weight: 600; } -` +`; const ShowInfoFormRow = styled.div` margin-bottom: 28px; @@ -105,7 +105,7 @@ const ShowInfoFormButtonContainer = styled.div` gap: 8px; `; -const ShowInfoFormButton = styled(Button) ` +const ShowInfoFormButton = styled(Button)` width: ${({ width }) => width}; `; @@ -272,7 +272,7 @@ const TextArea = styled.textarea` padding: 12px; border: 1px solid ${({ theme, hasError }) => - hasError ? `${theme.palette.status.error} !important` : theme.palette.grey.g20}; + hasError ? `${theme.palette.status.error} !important` : theme.palette.grey.g20}; border-radius: 4px; background-color: ${({ theme }) => theme.palette.grey.w}; color: ${({ theme }) => theme.palette.grey.g90}; @@ -524,7 +524,7 @@ const MobileTicketAction = styled.div` width: 24px; height: 24px; stroke: ${({ theme, disabled }) => - disabled ? theme.palette.grey.g40 : theme.palette.grey.g90}; + disabled ? theme.palette.grey.g40 : theme.palette.grey.g90}; } } } diff --git a/apps/admin/src/pages/ShowAddPage/index.tsx b/apps/admin/src/pages/ShowAddPage/index.tsx index 752d0b27..f4911ec2 100644 --- a/apps/admin/src/pages/ShowAddPage/index.tsx +++ b/apps/admin/src/pages/ShowAddPage/index.tsx @@ -1,6 +1,6 @@ import { ImageFile, useAddShow, useUploadShowImage } from '@boolti/api'; import { ArrowLeftIcon } from '@boolti/icon'; -import { Button, useToast } from '@boolti/ui'; +import { Button, useDialog, useToast } from '@boolti/ui'; import { useState } from 'react'; import { SubmitHandler, useForm } from 'react-hook-form'; import { Navigate, useNavigate } from 'react-router-dom'; @@ -19,6 +19,7 @@ import { PATH } from '~/constants/routes'; import Styled from './ShowAddPage.styles'; import ShowCastInfoFormContent from '~/components/ShowInfoFormContent/ShowCastInfoFormContent'; +import { ShowCastInfoFormInput } from '~/components/ShowCastInfoFormDialogContent/types'; interface ShowAddPageProps { step: 'info' | 'ticket'; @@ -26,6 +27,7 @@ interface ShowAddPageProps { const ShowAddPage = ({ step }: ShowAddPageProps) => { const navigate = useNavigate(); + const dialog = useDialog(); const [imageFiles, setImageFiles] = useState([]); const [salesTicketList, setSalesTicketList] = useState([]); @@ -33,6 +35,7 @@ const ShowAddPage = ({ step }: ShowAddPageProps) => { const showInfoForm = useForm(); const showTicketForm = useForm(); + const [showCastInfo, setShowCastInfo] = useState([]); const uploadShowImageMutation = useUploadShowImage(); const addShowMutation = useAddShow(); @@ -147,7 +150,11 @@ const ShowAddPage = ({ step }: ShowAddPageProps) => {
- + { + setShowCastInfo((prev) => [...prev, showCastInfoFormInput]); + }} + />