Skip to content

Commit

Permalink
Merge pull request #209 from Nexters/feat/preview-cast-info
Browse files Browse the repository at this point in the history
feat: 미리보기 페이지 출연진 정보 대응
  • Loading branch information
alstn2468 authored Oct 7, 2024
2 parents ae5da7a + 9990fab commit b65b631
Show file tree
Hide file tree
Showing 13 changed files with 489 additions and 151 deletions.
8 changes: 8 additions & 0 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions apps/admin/src/pages/ShowInfoPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ const ShowInfoPage = () => {
hostName: showInfoForm.watch('hostName'),
hostPhoneNumber: showInfoForm.watch('hostPhoneNumber'),
}}
showCastTeams={castTeamList}
hasNoticePage
/>
</Styled.ShowPreview>
Expand Down Expand Up @@ -382,6 +383,7 @@ const ShowInfoPage = () => {
hostName: showInfoForm.watch('hostName'),
hostPhoneNumber: showInfoForm.watch('hostPhoneNumber'),
}}
showCastTeams={castTeamList}
hasNoticePage
/>
</Styled.ShowInfoPreview>
Expand Down
1 change: 1 addition & 0 deletions apps/preview/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"react-dom": "^18.2.0",
"react-helmet-async": "^2.0.5",
"react-router-dom": "^6.22.3",
"swiper": "^11.1.14",
"the-new-css-reset": "^1.11.2"
},
"devDependencies": {
Expand Down
7 changes: 5 additions & 2 deletions apps/preview/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import './index.css';
import 'the-new-css-reset/css/reset.css';

import { ShowPreviewResponse } from '@boolti/api';
import { ShowCastTeamReadResponse, ShowPreviewResponse } from '@boolti/api';
import { BooltiUIProvider } from '@boolti/ui';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';
Expand All @@ -17,7 +17,10 @@ const router = createBrowserRouter([
loader: async ({ params }) => {
const showId = params.showId;
if (showId) {
const response = await fetcher.get<ShowPreviewResponse>(`web/papi/v1/shows/${showId}`);
const response = await Promise.all([
fetcher.get<ShowPreviewResponse>(`web/papi/v1/shows/${showId}`),
fetcher.get<ShowCastTeamReadResponse[]>(`web/papi/v1/shows/${showId}/cast-teams`),
]);
return response;
}
},
Expand Down
18 changes: 15 additions & 3 deletions apps/preview/src/pages/ShowPreviewPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ShowPreviewResponse } from '@boolti/api';
import { ShowCastTeamReadResponse, ShowPreviewResponse } from '@boolti/api';
import { BooltiDark, ShareIcon } from '@boolti/icon';
import { Footer, ShowPreview, useDialog } from '@boolti/ui';
import { format, setDefaultOptions } from 'date-fns';
Expand All @@ -13,14 +13,18 @@ import BooltiGrayLogo from '../../components/BooltiGrayLogo';
setDefaultOptions({ locale: ko });

const ShowPreviewPage = () => {
const previewData = useLoaderData() as ShowPreviewResponse | undefined;
const loaderData = useLoaderData() as
| [ShowPreviewResponse, ShowCastTeamReadResponse[]]
| undefined;

const dialog = useDialog();

if (!previewData) {
if (!loaderData) {
window.location.href = 'https://boolti.in';
return;
}

const [previewData, showCastTeams = []] = loaderData;
const {
id,
name: title,
Expand Down Expand Up @@ -110,6 +114,14 @@ const ShowPreviewPage = () => {
hostName: hostName,
hostPhoneNumber: hostPhoneNumber,
}}
showCastTeams={showCastTeams.map(({ name, members }) => ({
name,
members: members?.map(({ roleName, userNickname, userImgPath }) => ({
roleName,
userNickname,
userImgPath,
})),
}))}
onClickLink={reservationButtonClickHandler}
onClickLinkMobile={reservationButtonMobileClickHandler}
/>
Expand Down
52 changes: 52 additions & 0 deletions packages/ui/src/components/ShowPreview/ShowCastInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import Styled from './ShowPreview.styles';

interface Props {
showCastTeams: Array<{
name: string;
members?: {
roleName: string;
userNickname: string;
userImgPath: string;
}[];
}>;
}

const ShowCastInfo = ({ showCastTeams }: Props) => {
return (
<Styled.ShowInfo>
{showCastTeams.length > 0 ? (
showCastTeams.map((team, teamIndex) => (
<Styled.ShowInfoGroup key={teamIndex}>
<Styled.ShowInfoTitleContainer>
<Styled.ShowInfoTitle>{team.name}</Styled.ShowInfoTitle>
</Styled.ShowInfoTitleContainer>
<Styled.ShowCastList>
{team.members?.map((member, memberIndex) => (
<Styled.ShowCastListItem key={memberIndex}>
<Styled.UserImage
style={
{
'--imgPath': `url(${member.userImgPath})`,
} as React.CSSProperties
}
/>
<Styled.UserInfoWrap>
<Styled.UserNickname>{member.userNickname}</Styled.UserNickname>
<Styled.UserRoleName>{member.roleName}</Styled.UserRoleName>
</Styled.UserInfoWrap>
</Styled.ShowCastListItem>
))}
</Styled.ShowCastList>
</Styled.ShowInfoGroup>
))
) : (
<Styled.EmptryCastTeam>
<Styled.EmptyCastTeamTitle>COMMING SOON</Styled.EmptyCastTeamTitle>
<Styled.EmptyCastTeamDescription>조금만 기다려주세요!</Styled.EmptyCastTeamDescription>
</Styled.EmptryCastTeam>
)}
</Styled.ShowInfo>
);
};

export default ShowCastInfo;
163 changes: 163 additions & 0 deletions packages/ui/src/components/ShowPreview/ShowInfoDetail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import Linkify from 'linkify-react';
import Styled from './ShowPreview.styles';
import { CallIcon, MessageIcon } from '@boolti/icon';
import { useState } from 'react';
import ShowPreviewNotice from './ShowPreviewNotice';

interface Props {
show: {
images: string[];
name: string;
date: string;
startTime: string;
runningTime: string;
salesStartTime: string;
salesEndTime: string;
placeName: string;
placeStreetAddress: string;
placeDetailAddress: string;
notice: string;
hostName: string;
hostPhoneNumber: string;
};
hasNoticePage?: boolean;
onClickLink?: () => void;
onClickLinkMobile?: () => void;
}

const ShowInfoDetail = ({
show: {
date,
startTime,
runningTime,
placeName,
placeStreetAddress,
placeDetailAddress,
notice,
hostName,
},
hasNoticePage,
onClickLink,
onClickLinkMobile,
}: Props) => {
const [noticeOpen, setNoticeOpen] = useState<boolean>(false);
if (noticeOpen) {
return (
<ShowPreviewNotice
notice={notice}
onClickBackButton={() => {
setNoticeOpen(false);
}}
/>
);
}

return (
<Styled.ShowInfo>
<Styled.ShowInfoGroup>
<Styled.ShowInfoTitleContainer>
<Styled.ShowInfoTitle>일시</Styled.ShowInfoTitle>
</Styled.ShowInfoTitleContainer>
<Styled.ShowInfoDescription>
{date} / {startTime} ({runningTime}분)
</Styled.ShowInfoDescription>
</Styled.ShowInfoGroup>
<Styled.ShowInfoGroup>
<Styled.ShowInfoTitleContainer>
<Styled.ShowInfoTitle>장소</Styled.ShowInfoTitle>
<Styled.ShowInfoTitleButton
type="button"
onClick={() => {
navigator.clipboard.writeText(`${placeStreetAddress} ${placeDetailAddress}`);
alert('공연장 주소가 복사되었어요');
}}
>
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_3914_12951)">
<path
d="M11.666 4.66602H5.83268C5.18835 4.66602 4.66602 5.18835 4.66602 5.83268V11.666C4.66602 12.3103 5.18835 12.8327 5.83268 12.8327H11.666C12.3103 12.8327 12.8327 12.3103 12.8327 11.666V5.83268C12.8327 5.18835 12.3103 4.66602 11.666 4.66602Z"
stroke="#6F7485"
strokeWidth="1.3"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M2.33268 9.33268C1.69102 9.33268 1.16602 8.80768 1.16602 8.16602V2.33268C1.16602 1.69102 1.69102 1.16602 2.33268 1.16602H8.16602C8.80768 1.16602 9.33268 1.69102 9.33268 2.33268"
stroke="#6F7485"
strokeWidth="1.3"
strokeLinecap="round"
strokeLinejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_3914_12951">
<rect width="14" height="14" fill="white" />
</clipPath>
</defs>
</svg>
주소복사
</Styled.ShowInfoTitleButton>
</Styled.ShowInfoTitleContainer>
<Styled.ShowInfoSubtitle>{placeName}</Styled.ShowInfoSubtitle>
<Styled.ShowInfoDescription>
{placeStreetAddress} / {placeDetailAddress}
</Styled.ShowInfoDescription>
</Styled.ShowInfoGroup>
<Styled.ShowInfoGroup>
<Styled.ShowInfoTitleContainer>
<Styled.ShowInfoTitle>공연 내용</Styled.ShowInfoTitle>
{hasNoticePage && (
<Styled.ShowInfoTitleTextButton
type="button"
onClick={() => {
setNoticeOpen(true);
}}
>
전체보기
</Styled.ShowInfoTitleTextButton>
)}
</Styled.ShowInfoTitleContainer>
<Styled.ShowInfoDescription as="p" isFullContent={hasNoticePage}>
{notice.split('\n').map((text, index) => (
<Linkify key={`${text}_${index}`} options={{ target: '_blank' }}>
{text}
<br />
</Linkify>
))}
</Styled.ShowInfoDescription>
</Styled.ShowInfoGroup>
<Styled.ShowInfoGroup>
<Styled.ShowInfoTitleContainer>
<Styled.ShowInfoTitle>공연 관리 문의</Styled.ShowInfoTitle>
</Styled.ShowInfoTitleContainer>
<Styled.ShowHost>
<Styled.ShowHostName>{hostName}</Styled.ShowHostName>
<Styled.ShowHostLink>
<a onClick={onClickLink}>
<CallIcon />
</a>
<a onClick={onClickLink}>
<MessageIcon />
</a>
</Styled.ShowHostLink>
<Styled.ShowHostLinkMobile>
<a onClick={onClickLinkMobile}>
<CallIcon />
</a>
<a onClick={onClickLinkMobile}>
<MessageIcon />
</a>
</Styled.ShowHostLinkMobile>
</Styled.ShowHost>
</Styled.ShowInfoGroup>
</Styled.ShowInfo>
);
};

export default ShowInfoDetail;
Loading

0 comments on commit b65b631

Please sign in to comment.