From 6c836d53452a33c11388461e4754460aad5d0d56 Mon Sep 17 00:00:00 2001 From: hhhello Date: Mon, 20 Jan 2025 13:34:03 +0900 Subject: [PATCH] =?UTF-8?q?=ED=86=B5=EA=B3=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InvitationStatisticsDetail.style.ts | 32 +- .../detail/InvitationStatisticsDetail.tsx | 314 ++++++++++++------ .../detail/component/StatisticsValueCell.tsx | 12 +- src/remote/enumeration/GuestType.ts | 11 + 4 files changed, 256 insertions(+), 113 deletions(-) diff --git a/src/page/invitation/statistics/detail/InvitationStatisticsDetail.style.ts b/src/page/invitation/statistics/detail/InvitationStatisticsDetail.style.ts index 0482ab6..33746d8 100644 --- a/src/page/invitation/statistics/detail/InvitationStatisticsDetail.style.ts +++ b/src/page/invitation/statistics/detail/InvitationStatisticsDetail.style.ts @@ -1,5 +1,21 @@ import styled from "styled-components"; import colors from "@designsystem/foundation/colors"; +import makeText from "@designsystem/foundation/text/textType"; + +const BaseRow = styled.div` + display: flex; + padding: 0 8px; + height: 60px; + align-items: stretch; +`; + +const BaseCell = styled.div` + display: flex; + align-items: center; + justify-content: center; + width: 146px; + ${makeText('p4')}; +` const S = { container: styled.div` @@ -7,7 +23,21 @@ const S = { flex: 1; overflow-y: scroll; background: ${colors.white}; - ` + `, + rsvp: { + headerRow: styled(BaseRow)` + border-bottom: 1px solid ${colors.black}; + `, + bodyRow: styled(BaseRow)` + border-bottom: 1px solid ${colors.g100}; + `, + contentCell: styled(BaseCell)` + flex: 1; + `, + cell: styled(BaseCell)<{ width: number }>` + width: ${({width}) => width}px; + `, + }, }; export default S; \ No newline at end of file diff --git a/src/page/invitation/statistics/detail/InvitationStatisticsDetail.tsx b/src/page/invitation/statistics/detail/InvitationStatisticsDetail.tsx index 4787efd..f33a85b 100644 --- a/src/page/invitation/statistics/detail/InvitationStatisticsDetail.tsx +++ b/src/page/invitation/statistics/detail/InvitationStatisticsDetail.tsx @@ -1,54 +1,43 @@ import React, {useEffect, useState} from 'react'; import S from '@page/invitation/statistics/detail/InvitationStatisticsDetail.style'; -import {useNavigate, useParams, useSearchParams} from "react-router-dom"; +import {useNavigate, useParams} from "react-router-dom"; import {Column, Row} from "@designsystem/component/flexLayout"; import Icon, {IconType} from "@designsystem/foundation/icon"; import colors from "@designsystem/foundation/colors"; import Text from "@designsystem/component/text"; import HorizontalDivider from "@designsystem/component/horizontalDivider"; import StatisticsValueCell from "@page/invitation/statistics/detail/component/StatisticsValueCell"; -import { - Chart as ChartJS, - LineElement, - CategoryScale, - LinearScale, - PointElement, - Tooltip, - Legend -} from 'chart.js'; +import {CategoryScale, Chart as ChartJS, Legend, LinearScale, LineElement, PointElement, Tooltip} from 'chart.js'; import {Line} from "react-chartjs-2"; import weddingApi from "@remote/api/WeddingApi"; import WeddingStatistics from "@remote/value/WeddingStatistics"; +import Wedding from "@remote/value/Wedding"; +import OptionTextField from "@page/invitation/design/component/OptionTextField"; +import GuestType, {guestTypeRecord} from "@remote/enumeration/GuestType"; +import WeddingStatisticsInfo from "@remote/value/WeddingStatisticsInfo"; ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement, Tooltip, Legend); -const data = { - labels: [ // TODO: DUMMY - "12/16", - "12/17", - "12/18", - "12/19", - "12/20", - "12/21", - "12/22", - "12/23", - ], - datasets: [ - { - label: "방문자 수", - data: [1, 5, 10, 12, 15, 12, 8, 18], // TODO: DUMMY - borderColor: colors.g400, - fill: true, - tension: 0, - }, - { - label: "링크 공유 수", - data: [1, 3, 6, 8, 10, 9, 5, 3], // TODO: DUMMY - borderColor: colors.p800, - fill: true, - tension: 0, - }, - ], +const makeData = (infos: WeddingStatisticsInfo[]) => { + return { + labels: infos.map(i => i.date), + datasets: [ + { + label: "방문자 수", + data: infos.map(i => i.visitorCnt), + borderColor: colors.g400, + fill: true, + tension: 0, + }, + { + label: "링크 공유 수", + data: infos.map(i => i.linkShareCnt), + borderColor: colors.p800, + fill: true, + tension: 0, + }, + ], + }; }; const options = { @@ -87,7 +76,10 @@ const options = { function InvitationStatisticsDetail() { const navigate = useNavigate(); const {url} = useParams(); + const [weddingStatistics, setWeddingStatistics] = useState(); + const [wedding, setWedding] = useState(); + const [selectedGuestType, setSelectedGuestType] = useState(); useEffect(() => { if (!url) { @@ -99,87 +91,195 @@ function InvitationStatisticsDetail() { const {data} = await weddingApi.getStatistics(url); setWeddingStatistics(data); })(); + + (async () => { + const {data} = await weddingApi.getWedding(url); + setWedding(data); + })(); }, []); return ( - - - { - navigate('/statistics'); - }} - /> - {weddingStatistics && ( - <> - - https://linkmarry-web/{url} - 2024.02.01 작성{/*TODO: DUMMY*/} - - - - - 방문자 통계 - - - - 방문자 수 {1} - - - - 링크 공유 수 {1} - - - - - - - - - 하객 통계 - 동행 인원을 포함한 수치입니다. - - - - - + + { + navigate('/statistics'); + }} + /> + {weddingStatistics && wedding && ( + <> + + https://linkmarry-web/{wedding.url} + 2024.02.01 작성{/*TODO: DUMMY*/} + + + + + 방문자 통계 + + + + 방문자 + 수 {weddingStatistics.totalVisitorCnt} + + + + 링크 공유 + 수 {weddingStatistics.totalLinkShareCnt} + + + - - - 식사 여부 - 동행 인원을 포함한 수치입니다. - + + + + 하객 통계 + 동행 인원을 포함한 수치입니다. + + + + w.guestType === GuestType.GROOM).length} + filtered={selectedGuestType === GuestType.GROOM} + onClick={() => { + if (selectedGuestType === GuestType.GROOM) { + setSelectedGuestType(undefined); + + } else { + setSelectedGuestType(GuestType.GROOM); + } + }} + style={{cursor: 'pointer'}} + /> + w.guestType === GuestType.BRIDE).length} + filtered={selectedGuestType === GuestType.BRIDE} + onClick={() => { + if (selectedGuestType === GuestType.BRIDE) { + setSelectedGuestType(undefined); + } else { + setSelectedGuestType(GuestType.BRIDE); + } + }} + style={{cursor: 'pointer'}} + /> + + + + + 식사 여부 + 동행 인원을 포함한 수치입니다. + + {wedding.rsvp.attendMealStatus ? ( - - + w.isMeal).length} + filtered={false} + /> + !w.isMeal).length} + filtered={false} + /> - - - 디바이스 접속 - - - + ) : ( + + 식사 정보가 집계되지 않았습니다 + ? - + )} - - - + + 디바이스 접속 + + + + + + + + + + } + width={264} + style={{alignSelf: 'flex-end'}} + /> + + + + 작성일 + 참석인 + 참석여부 + 식사여부 + 전달사항 + 전화번호 + + {weddingStatistics.rsvpInfos + .filter(w => { + if (selectedGuestType === undefined) return true; + return w.guestType === selectedGuestType; + }) + .map(rsvp => ( + + TODO + {rsvp.guestName} + {rsvp.isAttend ? (`${guestTypeRecord[rsvp.guestType].korean}측`) : '미참석'} + {wedding.rsvp.attendMealStatus ? (rsvp.isMeal ? '식사함' : '식사안함') : '-'} + {wedding.rsvp.attendEtcStatus ? (rsvp.guestComment ?? '-') : '-'} + {wedding.rsvp.attendPhoneStatus ? (rsvp.guestPhone ?? '-') : '-'} + + ))} + - - )} - - + + + )} + ); } diff --git a/src/page/invitation/statistics/detail/component/StatisticsValueCell.tsx b/src/page/invitation/statistics/detail/component/StatisticsValueCell.tsx index 5ecbcc5..47d137e 100644 --- a/src/page/invitation/statistics/detail/component/StatisticsValueCell.tsx +++ b/src/page/invitation/statistics/detail/component/StatisticsValueCell.tsx @@ -1,9 +1,9 @@ -import React from 'react'; +import React, {HTMLAttributes} from 'react'; import styled from "styled-components"; import Text from "@designsystem/component/text"; import colors from "@designsystem/foundation/colors"; -interface StatisticsValueCellProps { +interface StatisticsValueCellProps extends HTMLAttributes { label: string; value: number; filtered: boolean; @@ -13,11 +13,12 @@ function StatisticsValueCell( { label, value, - filtered + filtered, + ...props }: StatisticsValueCellProps ) { return ( - + {label} {value} @@ -25,7 +26,8 @@ function StatisticsValueCell( } const S = { - container: styled.div` + container: styled.div<{ filtered: boolean; }>` + background: ${({filtered}) => filtered ? colors.g100 : colors.white}; display: flex; width: 281px; flex-direction: column; diff --git a/src/remote/enumeration/GuestType.ts b/src/remote/enumeration/GuestType.ts index cb2d914..5595d02 100644 --- a/src/remote/enumeration/GuestType.ts +++ b/src/remote/enumeration/GuestType.ts @@ -3,4 +3,15 @@ enum GuestType { GROOM = 'GROOM', } +export const guestTypeRecord: Record = { + [GuestType.BRIDE]: { + korean: '신부' + }, + [GuestType.GROOM]: { + korean: '신랑' + } +}; + export default GuestType; \ No newline at end of file