From 9cb66a7aaec42362e40db4b6e3967d7f7fe07daf Mon Sep 17 00:00:00 2001 From: jiminChoi Date: Tue, 4 Jun 2024 13:04:19 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[FE]=20FIX:=20=EC=95=84=EC=9D=B4=ED=85=9C?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9=20=ED=86=B5=EA=B3=84=20api=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20#1604?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminInfo/Chart/ItemBarChart.tsx | 33 ++++------- .../Cabinet/pages/admin/AdminStorePage.tsx | 59 ++++++++++++++----- 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/frontend/src/Cabinet/components/AdminInfo/Chart/ItemBarChart.tsx b/frontend/src/Cabinet/components/AdminInfo/Chart/ItemBarChart.tsx index f8410d59e..4f7a2e8e2 100644 --- a/frontend/src/Cabinet/components/AdminInfo/Chart/ItemBarChart.tsx +++ b/frontend/src/Cabinet/components/AdminInfo/Chart/ItemBarChart.tsx @@ -1,10 +1,10 @@ -import {ResponsiveBar } from "@nivo/bar"; +import { ResponsiveBar } from "@nivo/bar"; import styled from "styled-components"; -export interface IitemUseCountDto { +export interface IItemUseCountDto { itemName: string; itemDetails: string; - useCount: number; + userCount: number; } interface ITransformedItem { @@ -12,39 +12,29 @@ interface ITransformedItem { [key: string]: number | string; } -function transformData(itemCount: IitemUseCountDto[]): ITransformedItem[] { +const transformData = (itemArr: IItemUseCountDto[]): ITransformedItem[] => { const transformedData: ITransformedItem[] = []; - itemCount.forEach((item) => { - const { itemName, itemDetails, useCount } = item; + itemArr.forEach((item) => { + const { itemName, itemDetails, userCount } = item; const existingItem = transformedData.find( (transformed) => transformed.item === itemName ); if (existingItem) { - const typeNumber = itemDetails.split("_")[1]; - if (typeNumber) - existingItem[`type_${typeNumber}`] = useCount; - else - existingItem[`type`] = useCount; + existingItem[itemDetails] = userCount; } else { const newItem: ITransformedItem = { item: itemName, + [itemDetails]: userCount, }; - - const typeNumber = itemDetails.split("_")[1]; - if (typeNumber) - newItem[`type_${typeNumber}`] = useCount; - else - newItem[`type`] = useCount; - transformedData.push(newItem); } }); return transformedData; -} +}; -const ItemBarChart = ({ data }: { data: IitemUseCountDto[] }) => ( +const ItemBarChart = ({ data }: { data: IItemUseCountDto[] }) => ( ( }, }} data={transformData(data)} - keys={["type", "type_31", "type_15", "type_7", "type_3"]} + keys={["이사권", "알림 등록권", "31일", "15일", "7일", "3일"]} indexBy="item" margin={{ top: 50, right: 60, bottom: 50, left: 60 }} padding={0.2} @@ -70,6 +60,7 @@ const ItemBarChart = ({ data }: { data: IitemUseCountDto[] }) => ( valueScale={{ type: "linear" }} indexScale={{ type: "band", round: true }} colors={[ + "var(--sys-main-color)", "var(--sys-main-color)", "var(--sys-main-color)", "var(--ref-purple-400)", diff --git a/frontend/src/Cabinet/pages/admin/AdminStorePage.tsx b/frontend/src/Cabinet/pages/admin/AdminStorePage.tsx index 5a536ad68..7c27bfa1b 100644 --- a/frontend/src/Cabinet/pages/admin/AdminStorePage.tsx +++ b/frontend/src/Cabinet/pages/admin/AdminStorePage.tsx @@ -3,7 +3,7 @@ import { useRecoilState, useSetRecoilState } from "recoil"; import styled from "styled-components"; import CoinFlow from "@/Cabinet/components/AdminInfo/Chart/CoinFlow"; import ItemBarChart, { - IitemUseCountDto, + IItemUseCountDto, } from "@/Cabinet/components/AdminInfo/Chart/ItemBarChart"; import PieChartCoin from "@/Cabinet/components/AdminInfo/Chart/PieChartCoin"; import StoreHalfPieChart from "@/Cabinet/components/AdminInfo/Chart/StoreHalfPieChart"; @@ -14,6 +14,7 @@ import { CoinDateType, CoinFlowType } from "@/Cabinet/types/enum/store.enum"; import { axiosCoinCollectStatistics, axiosCoinUseStatistics, + axiosStatisticsTotalItemUse, } from "@/Cabinet/api/axios/axios.custom"; import { axiosStatisticsItem } from "@/Cabinet/api/axios/axios.custom"; @@ -54,16 +55,18 @@ const mockData: ICoinCollectInfo[] = [ ]; // TODO : 작은 횟수부터 큰 횟수까지 차례대로 보내주는지 확인 -const itemCount: IitemUseCountDto[] = [ - { itemName: "연장권", itemDetails: "extension_31", useCount: 31 }, - { itemName: "연장권", itemDetails: "extension_15", useCount: 15 }, - { itemName: "연장권", itemDetails: "extension_3", useCount: 3 }, - { itemName: "알림권", itemDetails: "alram", useCount: 10 }, - { itemName: "이사권", itemDetails: "move", useCount: 10 }, - { itemName: "패널티 축소권", itemDetails: "penalty_31", useCount: 31 }, - { itemName: "패널티 축소권", itemDetails: "penalty_7", useCount: 7 }, - { itemName: "패널티 축소권", itemDetails: "penalty_3", useCount: 3 }, -]; +// 아이템 통계 그래프 확인용 +// const itemList: IItemUseCountDto[] = [ +// { itemName: "연장권", itemDetails: "출석 연장권 보상", userCount: 38 }, +// { itemName: "연장권", itemDetails: "31일", userCount: 123 }, +// { itemName: "연장권", itemDetails: "15일", userCount: 22 }, +// { itemName: "연장권", itemDetails: "3일", userCount: 30 }, +// { itemName: "페널티 감면권", itemDetails: "31일", userCount: 10 }, +// { itemName: "페널티 감면권", itemDetails: "7일", userCount: 30 }, +// { itemName: "페널티 감면권", itemDetails: "3일", userCount: 10 }, +// { itemName: "이사권", itemDetails: "이사권", userCount: 20 }, +// { itemName: "알림 등록권", itemDetails: "알림 등록권", userCount: 40 }, +// ]; export interface ITotalCoinInfo { used: number; unused: number; @@ -88,7 +91,7 @@ const AdminStorePage = () => { const [totalCoinUseData, setTotalCoinUseData] = useState< ICoinStatisticsDto | undefined >(); - const [totalItemData, setTotalItemData] = useState([]); + const [totalItemData, setTotalItemData] = useState([]); const dataToggleList: toggleItem[] = [ { name: "발행 코인", key: CoinFlowType.ISSUE }, @@ -126,8 +129,8 @@ const AdminStorePage = () => { const getTotalItemData = async () => { try { - // const response = await axiosStatisticsTotalItemUse(); - // setTotalItemData(response.data.coinCollectStatistics); + const response = await axiosStatisticsTotalItemUse(); + setTotalItemData(response.data.items); // setTotalItemData(itemCount); } catch (error) { console.error("Err or getting total coin data:", error); @@ -143,7 +146,7 @@ const AdminStorePage = () => { setTotalCoinUseData(response.data); // setTotalItemData(itemCount); } catch (error) { - console.error("Error getting total coin data:", error); + console.error("Error getting total item data:", error); } }; @@ -310,3 +313,29 @@ const CoinCollectTitleWrapperStyled = styled.div` `; export default AdminStorePage; + +// interface IItemUseCountDto { +// itemName: string; +// itemDetails: string; +// userCount: number; +// } + +// interface ITransformedItem { +// item: string; +// [key: string]: number | string; +// } + +// interface IItemUseCountDtoarr { +// arr : IItemUseCountDto[]; + +// }; + +// const data: ITransformedItem[] = [ +// { item: "연장권", "출석 연장권 보상": 0, "31일": 1, "15일": 2, "3일": 0 }, +// { item: "페널티 감면권", "31일": 0, "7일": 0, "3일": 0 }, +// { item: "이사권", "이사권": 0 }, +// { item: "알림 등록권", "알림 등록권": 0 }, +// ]; +// // itemName별로 묶어서 1. 0: 1. item: "연장권" 2. 3일: 3 3. 15일: 15 4. 31일: 31 5. 연장권 보상 : 10 2. 1: 1. item: "알림권" 2. 알림권: 10 +// // 1. 2: 1. item: "이사권" 2. 이사권: 10 +// // 2. 3: 1. item: "패널티 축소권" 2. 3일: 3 3. 7일: 7 4. 31일: 31 이런 형식으로 만들고싶어 From f67047f8863518ec96ecd7012dee712d7f7eb182 Mon Sep 17 00:00:00 2001 From: Minkyu01 Date: Tue, 4 Jun 2024 13:09:34 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[FE]=20FEAT:=20coinFlow=20GE=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=ED=95=B4=EA=B2=B0=20#1604?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/AdminInfo/Chart/CoinFlow.tsx | 53 +++++++++---------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/frontend/src/Cabinet/components/AdminInfo/Chart/CoinFlow.tsx b/frontend/src/Cabinet/components/AdminInfo/Chart/CoinFlow.tsx index 1191b13e4..d9c666209 100644 --- a/frontend/src/Cabinet/components/AdminInfo/Chart/CoinFlow.tsx +++ b/frontend/src/Cabinet/components/AdminInfo/Chart/CoinFlow.tsx @@ -7,16 +7,10 @@ import { } from "@/Cabinet/pages/admin/AdminStorePage"; import { CoinDateType, CoinFlowType } from "@/Cabinet/types/enum/store.enum"; -// interface ICoinAmountDto { -// date: Date; -// amount: number; -// } - // 가짜 데이터를 생성하는 함수 function generateDummyData( startDate: string, endDate: string - // totalCoinUseData : ICoinStatisticsDto[]; ): { issueCoin: ICoinAmountDto[]; unusedCoin: ICoinAmountDto[]; @@ -52,6 +46,29 @@ function generateDummyData( return dummyData; } +// const calculateEndDate = (startDate: Date, type: CoinDateType) => { +// switch (type) { +// case CoinDateType.DAY: +// return new Date(startDate.getTime() + 7 * 24 * 60 * 60 * 1000); // 7일 뒤 +// case CoinDateType.WEEK: +// return new Date(startDate.getTime() + 4 * 7 * 24 * 60 * 60 * 1000); // 4주 뒤 +// case CoinDateType.MONTH: +// const endDate = new Date(startDate); +// endDate.setMonth(startDate.getMonth() + 4); // 4개월 뒤 +// return endDate; +// default: +// return startDate; +// } +// }; +// 현재 날짜 +// const today = new Date(); +// today.setHours(0, 0, 0, 0); // 현재 날짜의 시간을 00:00:00으로 설정 +// const endDate = calculateEndDate(today, toggleType); +// const dummyData = generateDummyData( +// today.toISOString().split("T")[0], // 형식 YYYY-MM-DD +// endDate.toISOString().split("T")[0] // 형식 YYYY-MM-DD +// ); + const CoinFlow = ({ toggleType, coinToggleType, @@ -61,32 +78,10 @@ const CoinFlow = ({ coinToggleType: CoinFlowType; totalCoinUseData: ICoinStatisticsDto | undefined; }) => { - // const calculateEndDate = (startDate: Date, type: CoinDateType) => { - // switch (type) { - // case CoinDateType.DAY: - // return new Date(startDate.getTime() + 7 * 24 * 60 * 60 * 1000); // 7일 뒤 - // case CoinDateType.WEEK: - // return new Date(startDate.getTime() + 4 * 7 * 24 * 60 * 60 * 1000); // 4주 뒤 - // case CoinDateType.MONTH: - // const endDate = new Date(startDate); - // endDate.setMonth(startDate.getMonth() + 4); // 4개월 뒤 - // return endDate; - // default: - // return startDate; - // } - // }; - // 현재 날짜 - // const today = new Date(); - // today.setHours(0, 0, 0, 0); // 현재 날짜의 시간을 00:00:00으로 설정 - // const endDate = calculateEndDate(today, toggleType); - // const dummyData = generateDummyData( - // today.toISOString().split("T")[0], // 형식 YYYY-MM-DD - // endDate.toISOString().split("T")[0] // 형식 YYYY-MM-DD - // ); console.log("totalCoinUseData: ", totalCoinUseData); const formattedData = [ { - id: "issueCoin", + id: "issuedCoin", data: totalCoinUseData?.issueCoin?.map((item) => ({ x: item.date, From e7227ed2c77b58d6ef4abc104b936f097a308536 Mon Sep 17 00:00:00 2001 From: gykoh42 Date: Tue, 4 Jun 2024 13:10:00 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[FE]=20FEAT:=20=EC=95=84=EC=9D=B4=ED=85=9C?= =?UTF-8?q?=20=EC=A7=80=EA=B8=89=20=EA=B8=B0=EB=A1=9D=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=ED=86=A0=EA=B8=80=20=EB=B0=8F=20=ED=91=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20#1604?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ItemLog/AdminItemUsageLog.container.tsx | 1 - .../pages/admin/AdminItemUsageLogPage.tsx | 100 ++++++------------ 2 files changed, 31 insertions(+), 70 deletions(-) diff --git a/frontend/src/Cabinet/components/ItemLog/AdminItemUsageLog.container.tsx b/frontend/src/Cabinet/components/ItemLog/AdminItemUsageLog.container.tsx index 1efb9d47b..a05d83014 100644 --- a/frontend/src/Cabinet/components/ItemLog/AdminItemUsageLog.container.tsx +++ b/frontend/src/Cabinet/components/ItemLog/AdminItemUsageLog.container.tsx @@ -2,7 +2,6 @@ import { useEffect, useState } from "react"; import AdminItemUsageLog from "@/Cabinet/components/ItemLog/AdminItemUsageLog"; import { ItemLogResponseType } from "@/Cabinet/types/dto/admin.dto"; import useMenu from "@/Cabinet/hooks/useMenu"; -import { STATUS_400_BAD_REQUEST } from "@/Cabinet/constants/StatusCode"; const AdminItemUsageLogContainer = () => { const { closeStore } = useMenu(); diff --git a/frontend/src/Cabinet/pages/admin/AdminItemUsageLogPage.tsx b/frontend/src/Cabinet/pages/admin/AdminItemUsageLogPage.tsx index ba5fa44c5..be2accf69 100644 --- a/frontend/src/Cabinet/pages/admin/AdminItemUsageLogPage.tsx +++ b/frontend/src/Cabinet/pages/admin/AdminItemUsageLogPage.tsx @@ -1,61 +1,42 @@ -import React, { useEffect, useState } from "react"; import styled from "styled-components"; -import AdminItemProvideContainer from "@/Cabinet/components/ItemLog/AdminItemProvideLog.container"; import AdminItemUsageLogContainer from "@/Cabinet/components/ItemLog/AdminItemUsageLog.container"; import useMenu from "@/Cabinet/hooks/useMenu"; -const AdminItemUsageLogPage = ({ - toggleType = "PROVIDE", -}: { - toggleType?: string; -}) => { +const AdminItemUsageLogPage = () => { const { closeUserStore } = useMenu(); - const [currentToggleType, setToggleType] = useState(toggleType); const isSearchPage = window.location.pathname === "/admin/search"; - useEffect(() => { - if (!isSearchPage && toggleType !== currentToggleType) { - setToggleType("PROVIDE"); - } - }, [isSearchPage, toggleType]); - - const switchToggleType = () => { - setToggleType(currentToggleType === "PROVIDE" ? "LIST" : "PROVIDE"); - }; - return ( - - {isSearchPage && ( - - - - )} - {currentToggleType === "PROVIDE" ? "아이템 지급 기록" : "아이템 내역"} - - 뒤로가기 + 아이템 내역 + + 뒤로가기 + - {currentToggleType === "PROVIDE" ? ( - - ) : ( - - )} + ); }; -const GoBackButtonStyled = styled.div` +const AdminItemLogStyled = styled.div` position: absolute; - top: 3%; - color: var(--sys-sub-color); - right: 6%; - font-size: 0.875rem; - text-decoration: underline; - cursor: pointer; + top: 120px; + right: 0; + min-width: 330px; + min-height: 100%; + padding: 40px 20px 10px 20px; + z-index: 9; + transform: translateX(120%); + transition: transform 0.3s ease-in-out; + box-shadow: 0 0 40px 0 var(--page-btn-shadow-color); + display: flex; + flex-direction: column; + align-items: center; + background: var(--bg-color); + &.on { + transform: translateX(0); + } `; const TitleContainer = styled.div` @@ -68,39 +49,20 @@ const TitleContainer = styled.div` `; const TitleStyled = styled.h1<{ isClick: boolean }>` + margin-left: 15px; font-size: 1.5rem; font-weight: 700; display: flex; - cursor: ${(props) => (props.isClick ? "pointer" : "default")}; - &:hover { - color: ${(props) => (props.isClick ? "var(--sys-main-color)" : "")}; - } `; -const ImageStyled = styled.div` - width: 24px; - transform: rotate(-90deg); - margin-right: 4px; -`; - -const AdminItemLogStyled = styled.div` +const GoBackButtonStyled = styled.div` position: absolute; - top: 120px; - right: 0; - min-width: 330px; - min-height: 100%; - padding: 40px 20px 10px 20px; - z-index: 9; - transform: translateX(120%); - transition: transform 0.3s ease-in-out; - box-shadow: 0 0 40px 0 var(--page-btn-shadow-color); - display: flex; - flex-direction: column; - align-items: center; - background: var(--bg-color); - &.on { - transform: translateX(0); - } + top: 3%; + color: var(--sys-sub-color); + right: 6%; + font-size: 0.875rem; + text-decoration: underline; + cursor: pointer; `; export default AdminItemUsageLogPage;