Skip to content

Commit

Permalink
Feat: 관리자 페이지 사이드바 현황
Browse files Browse the repository at this point in the history
  • Loading branch information
quokka-eating-carrots committed Feb 1, 2023
1 parent 8dc9a6c commit 96beeb3
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 39 deletions.
2 changes: 1 addition & 1 deletion index.html
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<title>액토몰</title>
</head>
<body>
<div id="root"></div>
Expand Down
5 changes: 3 additions & 2 deletions src/App.tsx
@@ -1,13 +1,14 @@
import './App.css';
import { ScrollRestoration, Outlet } from 'react-router-dom';
import { ScrollRestoration, Outlet, useLocation } from 'react-router-dom';
import { RecoilRoot, atom, selector, useRecoilState, useRecoilValue } from 'recoil';
import Header from './components/Header';

function App() {
const location = useLocation();
return (
<RecoilRoot>
<ScrollRestoration />
<Header />
{location.pathname.includes('/admin') ? null : <Header />}
<Outlet />
</RecoilRoot>
);
Expand Down
2 changes: 1 addition & 1 deletion src/api/requests.tsx
Expand Up @@ -33,4 +33,4 @@ export async function requestAPI({ type, endpoint, page, data, accessToken }: re
} catch (error) {
console.log(error);
}
}
}
47 changes: 47 additions & 0 deletions src/api/requestsTypes.ts
@@ -0,0 +1,47 @@
import { StringOptionsWithImporter } from 'sass';

// 전체 거래 조회
export interface TransactionDetail {
detailId: string;
user: {
email: string;
displayName: string;
profileImg: string | null;
};
account: {
backName: string;
bankCode: string;
accountNumber: string;
};
product: {
productId: string;
title: string;
price: number;
description: string;
tags: string[];
thumbnail: string | null;
};
reservation: Reservation | null;
timePaid: string;
isCanceled: boolean;
done: boolean;
}

// 예약
export interface Reservation {
start: string;
end: string;
isCanceled: boolean;
isExpired: boolean;
}

// 전체 제품 조회
export interface Product {
id: string;
title: string;
price: number;
description: string;
tags: string[];
thumbnail: string;
isSoldOut: boolean;
}
61 changes: 54 additions & 7 deletions src/components/Admin/NavBar.tsx
@@ -1,23 +1,70 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import StateBoard from './StateBoard';
import styles from './NavBar.module.scss';
import { requestAPI } from '../../api/requests';
import { TransactionDetail, Product } from '../../api/requestsTypes';

type Props = {};

const NavBar = (props: Props) => {
const [allTrans, setAllTrans] = useState<TransactionDetail[]>([]);
const [allProducts, setAllProducts] = useState<Product[]>([]);
useEffect(() => {
const getTrans = async () => {
const data = await requestAPI({
type: 'GET',
endpoint: '/products/transactions/all',
page: 'admin',
});
setAllTrans(data?.data);
};
const getProducts = async () => {
const data = await requestAPI({
type: 'GET',
endpoint: '/products',
page: 'admin',
});
setAllProducts(data?.data);
};
getTrans();
getProducts();
}, []);

const date = new Date();
const today = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();

const newOrder = allTrans.filter((el) => {
return el.timePaid.slice(0, 10) === today;
});

const purchaseConfirmed = allTrans.filter((el) => {
return el.done === true;
});

const purchaseCancel = allTrans.filter((el) => {
return el.isCanceled === true;
});

let allIncome = 0;
allTrans.forEach((el) => {
if (el && el.done) {
allIncome += el.product.price;
}
});

return (
<div className={styles.sideBar}>
<StateBoard
state='주문 현황'
content1='신규 주문'
content2='구매 확정'
content3='거래 취소'
content1={newOrder.length}
content2={purchaseConfirmed.length}
content3={purchaseCancel.length}
/>
<StateBoard
state='거래 현황'
content1='전체 상품수'
content2='전체 판매액'
content3='전체 거래수'
content1={allProducts.length}
content2={allIncome}
content3={allTrans.length}
/>
</div>
);
Expand Down
31 changes: 31 additions & 0 deletions src/components/Admin/StateBoard.module.scss
Expand Up @@ -10,11 +10,42 @@
.title {
display: flex;
align-items: center;
margin: 0 auto;
padding: 20px 0;
width: 80%;
color: #fff;
gap: 10px;
font-weight: 700;
border-bottom: 1px solid #fff;
.icon {
color: #fff;
font-size: 20px;
margin-right: 10px;
}
}
.content {
color: #fff;
padding: 20px 10% 30px;
.des {
display: flex;
margin-bottom: 10px;
align-items: center;
font-size: 14px;
.desTitle {
color: #fff;
width: 40%;
}
.desContent {
color: #fff;
width: 45%;
text-align: right;
font-weight: 700;
}
.desUnit {
color: #fff;
width: 15%;
text-align: right;
}
}
}
}
85 changes: 58 additions & 27 deletions src/components/Admin/StateBoard.tsx
@@ -1,40 +1,71 @@
import React from 'react';
import { FaFileInvoiceDollar, FaCoins } from 'react-icons/fa';
import { FaFileInvoiceDollar, FaCoins, FaDivide } from 'react-icons/fa';
import styles from './StateBoard.module.scss';

type Props = {
state: string;
content1: string;
content2: string;
content3: string;
content1: number;
content2: number;
content3: number;
};

const StateBoard = ({ state, content1, content2, content3 }: Props) => {
return (
<div className={styles.board}>
<div className={styles.title}>
{state === '주문 현황' ? (
const orderState = () => {
return (
<>
<div className={styles.title}>
<FaFileInvoiceDollar className={styles.icon} />
) : (
<h3>{state}</h3>
</div>
<div className={styles.content}>
<div className={styles.des}>
<span className={styles.desTitle}>신규 주문</span>
<span className={styles.desContent}>{content1}</span>
<span className={styles.desUnit}></span>
</div>
<div className={styles.des}>
<span className={styles.desTitle}>구매 확정</span>
<span className={styles.desContent}>{content2}</span>
<span className={styles.desUnit}></span>
</div>
<div className={styles.des}>
<span className={styles.desTitle}>거래 취소</span>
<span className={styles.desContent}>{content3}</span>
<span className={styles.desUnit}></span>
</div>
</div>
</>
);
};

const payState = () => {
return (
<>
<div className={styles.title}>
<FaCoins className={styles.icon} />
)}
<h3>{state}</h3>
</div>
<hr />
<div>
<span>{content1}</span>
<span>{state === '주문 현황' ? '건' : '개'}</span>
</div>
<div>
<span>{content2}</span>
<span>{state === '주문 현황' ? '건' : '원'}</span>
</div>
<div>
<span>{content3}</span>
<span></span>
</div>
</div>
);
<h3>{state}</h3>
</div>
<div className={styles.content}>
<div className={styles.des}>
<span className={styles.desTitle}>전체 상품 수</span>
<span className={styles.desContent}>{content1}</span>
<span className={styles.desUnit}></span>
</div>
<div className={styles.des}>
<span className={styles.desTitle}>전체 판매액</span>
<span className={styles.desContent}>{content2.toLocaleString()}</span>
<span className={styles.desUnit}></span>
</div>
<div className={styles.des}>
<span className={styles.desTitle}>전체 거래 수</span>
<span className={styles.desContent}>{content3}</span>
<span className={styles.desUnit}></span>
</div>
</div>
</>
);
};
return <div className={styles.board}>{state === '주문 현황' ? orderState() : payState()}</div>;
};

export default StateBoard;
7 changes: 6 additions & 1 deletion src/index.css
@@ -1 +1,6 @@
@import 'reset-css'
@import 'reset-css';
@import url(//fonts.googleapis.com/earlyaccess/nanumgothic.css);

body {
font-family: 'Nanum Gothic', sans-serif;
}

0 comments on commit 96beeb3

Please sign in to comment.