Skip to content

Commit

Permalink
Merge pull request #90 from Duri-Salon/feat(salon)/income-statistic-shim
Browse files Browse the repository at this point in the history
[feat] 매장 매출관리 그래프 페이지
  • Loading branch information
seungboshim authored Dec 19, 2024
2 parents 972cd24 + cad7800 commit 2e8c479
Show file tree
Hide file tree
Showing 11 changed files with 589 additions and 31 deletions.
4 changes: 4 additions & 0 deletions apps/salon/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
"@duri-fe/utils": "workspace:packages/utils",
"@emotion/react": "^11.13.5",
"@emotion/styled": "^11.13.5",
"@nivo/bar": "^0.88.0",
"@nivo/core": "^0.88.0",
"@nivo/line": "^0.88.0",
"@nivo/pie": "^0.88.0",
"@tanstack/react-query": "^5.62.1",
"@tanstack/react-query-devtools": "^5.62.2",
Expand All @@ -38,6 +41,7 @@
"zustand": "^5.0.2"
},
"devDependencies": {
"@types/lodash": "^4.17.13",
"@types/navermaps": "^3.7.8",
"@types/react": "^18",
"@types/react-dom": "^18",
Expand Down
140 changes: 138 additions & 2 deletions apps/salon/src/components/income/MonthIncomeStatistic.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { Flex, Text, theme, WidthFitFlex } from '@duri-fe/ui';
import { IncomeMonthListType } from '@duri-fe/utils/src/apis/types/income';
import styled from '@emotion/styled';
import { ResponsiveLine } from '@nivo/line';

interface MonthIncomeStatisticProps {
beforeRatio: number; //전월대비 증감
Expand All @@ -9,6 +12,139 @@ export const MonthIncomeStatistic = ({
beforeRatio,
incomeMonthList,
}: MonthIncomeStatisticProps) => {
console.log(incomeMonthList, beforeRatio);
return <div>MonthIncomeStatistic</div>;
const transformedData = [
{
id: 'Income',
data: incomeMonthList.map((item) => ({
x: item.date,
y: item.income,
})),
},
];

const thisMonthIncome = incomeMonthList[4].income;

const avgIncome =
incomeMonthList.reduce((sum, item) => sum + item.income, 0) /
incomeMonthList.length;

// y축 최소값과 최대값을 구한 후, 4등분한 값들로 가로선을 그리기 위한 값
const minIncome = Math.min(...incomeMonthList.map((item) => item.income));
const maxIncome = Math.max(...incomeMonthList.map((item) => item.income));
const minGridY = Math.max(0, minIncome - 500000);
const maxGridY = maxIncome + 500000;
const step = (maxGridY - minGridY) / 3;

const gridYValues = [
minGridY,
minGridY + step,
minGridY + step * 2,
maxGridY,
];

return (
<Flex direction="column" padding="32px 20px" align="flex-start" gap={8}>
<Text typo="Title1">이번달 매출</Text>
<AmountText>{thisMonthIncome.toLocaleString('ko-KR')}</AmountText>
<WidthFitFlex gap={4}>
<Text typo="Caption1" colorCode={theme.palette.Link}>
전월 대비
</Text>
<Text typo="Label1" colorCode={theme.palette.Link}>
{beforeRatio}%
</Text>
<Text typo="Caption1" colorCode={theme.palette.Link}>
{beforeRatio > 0 ? '증가' : '감소'}
</Text>
</WidthFitFlex>

<Flex margin="32px 0">
<div style={{ height: 100, width: '100%' }}>
<ResponsiveLine
data={transformedData}
margin={{ top: 20, right: 40, bottom: 40, left: 20 }}
xScale={{ type: 'point' }}
yScale={{
type: 'linear',
min: 'auto',
max: 'auto',
stacked: false,
reverse: false,
}}
axisLeft={null}
axisRight={{
tickSize: 0,
tickPadding: 6,
tickRotation: 0,
tickValues: gridYValues.map((value) => value), // y축 값
format: (value) => value / 10000,
}}
axisBottom={{
tickSize: 0,
tickPadding: 20,
tickRotation: 0,
tickValues: incomeMonthList.map((item) => item.date), // x축 값
format: (value) => value + '월', // 월 표시
legendOffset: 36,
legendPosition: 'middle',
}}
theme={{
axis: {
ticks: {
text: {
fill: theme.palette.Gray300, // x축 글씨 색을 회색으로 변경
},
line: {
stroke: theme.palette.Gray200, // x축 선 색상
strokeDasharray: '2 3',
},
},
},
}}
enableGridX={false}
enableGridY={true}
lineWidth={2}
colors={theme.palette.Normal700} // 꺾은선 색상
enablePoints={false}
useMesh={true}
layers={[
'grid',
'axes',
'lines',
'markers',
'legends',
({ innerWidth, innerHeight }) => {
// 평균선 추가
const avgY =
(avgIncome /
Math.max(...incomeMonthList.map((item) => item.income))) *
innerHeight;

return (
<g>
<line
x1={0}
x2={innerWidth}
y1={avgY}
y2={avgY}
stroke={theme.palette.Alert}
strokeWidth={1}
strokeDasharray="2 3"
/>
</g>
);
},
]}
gridYValues={gridYValues} // y축 가로선 설정 (4등분)
onClick={(data) => console.log(data)}
/>
</div>
</Flex>
</Flex>
);
};

const AmountText = styled(Text)`
font-size: 24px;
font-weight: 500;
`;
20 changes: 14 additions & 6 deletions apps/salon/src/components/income/RecentIncomeStatistic.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import { Flex, Text } from '@duri-fe/ui';
import { IncomeMonthListType } from '@duri-fe/utils/src/apis/types/income';

import { ResponsiveBarChart } from './ResponsiveBarChart';

interface RecentIncomeStatisticProps {
incomeMonthList: IncomeMonthListType[]; //선택, 이전, 이번달 매출 리스트
beforeRatio: number; //전월 대비 증감
nowRatio: number; //이번달 대비 증감
}

export const RecentIncomeStatistic = ({
incomeMonthList,
beforeRatio,
nowRatio,
}: RecentIncomeStatisticProps) => {
console.log(incomeMonthList, beforeRatio, nowRatio);
return <div>RecentIncomeStatistic</div>;
return (
<Flex direction="column">
<Flex direction="column" align="flex-start" gap={8} padding="0 20px">
<Text typo="Title2">매장 매출 통계</Text>
<Text typo="Caption1">최근 일주일간의 매장 매출을 보여줍니다.</Text>
</Flex>
<Flex margin="24px 0" padding="0 20px" height={180}>
<ResponsiveBarChart data={incomeMonthList} />
</Flex>
</Flex>
);
};
Loading

0 comments on commit 2e8c479

Please sign in to comment.