From 49cd23f6de0983753892280c89dc366a2135866e Mon Sep 17 00:00:00 2001 From: Bokdol11859 <2019147551@yonsei.ac.kr> Date: Wed, 28 Feb 2024 00:08:48 +0900 Subject: [PATCH] feat: integrate backend with yearly, monthly dividend ranking pages along with design qa --- .../dividend/_components/dividend-row.tsx | 4 +- .../_components/dividend-accordion.tsx | 40 +- .../dividend/monthly/_components/header.tsx | 3 +- .../(main)/report/dividend/monthly/page.tsx | 580 +----------------- .../yearly/_components/dividend-list.tsx | 2 +- .../dividend/yearly/_components/header.tsx | 17 +- .../(main)/report/dividend/yearly/page.tsx | 2 +- .../queries/use-monthly-dividend-mutation.ts | 37 ++ src/utils/date.ts | 16 + 9 files changed, 108 insertions(+), 593 deletions(-) create mode 100644 src/state/queries/use-monthly-dividend-mutation.ts diff --git a/src/app/(main)/report/dividend/_components/dividend-row.tsx b/src/app/(main)/report/dividend/_components/dividend-row.tsx index dadadcc..db50ded 100644 --- a/src/app/(main)/report/dividend/_components/dividend-row.tsx +++ b/src/app/(main)/report/dividend/_components/dividend-row.tsx @@ -7,7 +7,9 @@ export interface Dividend extends StockResponse {} export const DividendRow = React.memo(({ dividend }: { dividend: SingleYearlyDividendResponse }) => { return (
- {dividend.ticker} +
+ {dividend.ticker} +

{dividend.ticker}

diff --git a/src/app/(main)/report/dividend/monthly/_components/dividend-accordion.tsx b/src/app/(main)/report/dividend/monthly/_components/dividend-accordion.tsx index cd7ccd7..26c5832 100644 --- a/src/app/(main)/report/dividend/monthly/_components/dividend-accordion.tsx +++ b/src/app/(main)/report/dividend/monthly/_components/dividend-accordion.tsx @@ -2,45 +2,59 @@ import React from "react"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"; -import { MonthlyDividendIncome } from "../page"; + import { DividendRow } from "../../_components/dividend-row"; import { cn } from "@/utils/cn"; +import { MonthlyDividendResponse } from "@/api/generated/endpoint.schemas"; -export const DividendAccordion = ({ monthlyDividendList }: { monthlyDividendList: MonthlyDividendIncome[] }) => { +export const DividendAccordion = ({ monthlyDividendList }: { monthlyDividendList: MonthlyDividendResponse[] }) => { return ( - + {monthlyDividendList.map((monthDividend, idx) => { - const isOpenable = monthDividend.dividendList.length > 0; + const isOpenable = monthDividend.dividends.length > 0; + const currentMonthDate = new Date(monthDividend.year, monthDividend.month - 1); + + let month = currentMonthDate.toLocaleString("default", { month: "short" }); + let year = ""; + if (idx === 0 || monthDividend.year !== monthlyDividendList[idx - 1]?.year) { + year = ` ${monthDividend.year}`; + } + if (!isOpenable) { return (
-

{monthDividend.date.toDateString()}

-

{monthDividend.totalIncome}

+

{`${month}${year}`}

+

${monthDividend.totalDividend}

); } return ( -
-

{monthDividend.date.toDateString()}

-

{monthDividend.totalIncome}

+
+

{`${month}${year}`}

+

${monthDividend.totalDividend}

- {monthDividend.dividendList.map((dividend, idx) => ( + {monthDividend.dividends.map((dividend, idx) => ( ))}
diff --git a/src/app/(main)/report/dividend/monthly/_components/header.tsx b/src/app/(main)/report/dividend/monthly/_components/header.tsx index 356abe8..f11eb3c 100644 --- a/src/app/(main)/report/dividend/monthly/_components/header.tsx +++ b/src/app/(main)/report/dividend/monthly/_components/header.tsx @@ -1,10 +1,11 @@ +import { getYearRange } from "@/utils/date"; import React from "react"; export const Header = React.memo(() => { return (

Monthly Dividend Income

-

YYYY.MM ~ YYYY.MM

+

{getYearRange(new Date())}

); }); diff --git a/src/app/(main)/report/dividend/monthly/page.tsx b/src/app/(main)/report/dividend/monthly/page.tsx index b3890f3..369d765 100644 --- a/src/app/(main)/report/dividend/monthly/page.tsx +++ b/src/app/(main)/report/dividend/monthly/page.tsx @@ -1,7 +1,11 @@ +"use client"; + import React from "react"; import { Header } from "./_components/header"; import { DividendAccordion } from "./_components/dividend-accordion"; import { Dividend } from "../_components/dividend-row"; +import { useMonthlyDividendMutation } from "@/state/queries/use-monthly-dividend-mutation"; +import { Loader2Icon } from "lucide-react"; export interface MonthlyDividendIncome { date: Date; @@ -9,569 +13,25 @@ export interface MonthlyDividendIncome { dividendList: Dividend[]; } -const dummyMonthlyDividendList: MonthlyDividendIncome[] = [ - { - date: new Date(), - totalIncome: 20, - dividendList: [ - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - ], - }, - { - date: new Date(), - totalIncome: 20, - dividendList: [ - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - ], - }, - { - date: new Date(), - totalIncome: 20, - dividendList: [ - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - ], - }, - { - date: new Date(), - totalIncome: 20, - dividendList: [ - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - ], - }, - { - date: new Date(), - totalIncome: 20, - dividendList: [ - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - ], - }, - { - date: new Date(), - totalIncome: 20, - dividendList: [ - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - ], - }, - { - date: new Date(), - totalIncome: 20, - dividendList: [ - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - ], - }, - { - date: new Date(), - totalIncome: 20, - dividendList: [ - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - ], - }, - { - date: new Date(), - totalIncome: 20, - dividendList: [ - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - ], - }, - { - date: new Date(), - totalIncome: 20, - dividendList: [ - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - ], - }, - { - date: new Date(), - totalIncome: 20, - dividendList: [ - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - { - companyName: "companyName", - exchange: "exchange", - industry: "industry", - sectorName: "sectorName", - stockId: "stockId", - logoUrl: "/next.svg", - price: 12, - volume: 18, - ticker: "AAPL", - }, - ], - }, - { - date: new Date(), - totalIncome: 20, - dividendList: [], - }, -]; - const MonthlyDividendPage = React.memo(() => { + const { mutate: mutateMonthlyDividend, data: monthlyDividendData } = useMonthlyDividendMutation(); + + React.useEffect(() => { + mutateMonthlyDividend(); + }, [mutateMonthlyDividend]); + + if (!monthlyDividendData) { + return ( +
+ +
+ ); + } + return ( -
+
- +
); }); diff --git a/src/app/(main)/report/dividend/yearly/_components/dividend-list.tsx b/src/app/(main)/report/dividend/yearly/_components/dividend-list.tsx index f1b7f7b..e1a05b4 100644 --- a/src/app/(main)/report/dividend/yearly/_components/dividend-list.tsx +++ b/src/app/(main)/report/dividend/yearly/_components/dividend-list.tsx @@ -4,7 +4,7 @@ import { SingleYearlyDividendResponse } from "@/api/generated/endpoint.schemas"; export const DividendList = React.memo(({ dividendList }: { dividendList: SingleYearlyDividendResponse[] }) => { return ( -
+
{dividendList.map((dividend, idx) => (

diff --git a/src/app/(main)/report/dividend/yearly/_components/header.tsx b/src/app/(main)/report/dividend/yearly/_components/header.tsx index 9eef197..9d07c61 100644 --- a/src/app/(main)/report/dividend/yearly/_components/header.tsx +++ b/src/app/(main)/report/dividend/yearly/_components/header.tsx @@ -1,21 +1,6 @@ +import { getYearRange } from "@/utils/date"; import React from "react"; -const getYearRange = (date: Date): string => { - const startDate = new Date(date); - const endDate = new Date(startDate.getFullYear() + 1, startDate.getMonth(), startDate.getDate()); - - const startYear = startDate.getFullYear(); - const startMonth = startDate.getMonth() + 1; - const endYear = endDate.getFullYear(); - const endMonth = endDate.getMonth() + 1; - - const formattedStartMonth = startMonth < 10 ? `0${startMonth}` : startMonth.toString(); - const formattedEndMonth = endMonth < 10 ? `0${endMonth}` : endMonth.toString(); - - const dateRange = `${startYear}.${formattedStartMonth} ~ ${endYear}.${formattedEndMonth}`; - return dateRange; -}; - export const Header = React.memo(() => { return (

diff --git a/src/app/(main)/report/dividend/yearly/page.tsx b/src/app/(main)/report/dividend/yearly/page.tsx index dd6a818..06a50f2 100644 --- a/src/app/(main)/report/dividend/yearly/page.tsx +++ b/src/app/(main)/report/dividend/yearly/page.tsx @@ -33,7 +33,7 @@ const YearlyDividendPage = React.memo(() => { } return ( -
+
diff --git a/src/state/queries/use-monthly-dividend-mutation.ts b/src/state/queries/use-monthly-dividend-mutation.ts new file mode 100644 index 0000000..e95a178 --- /dev/null +++ b/src/state/queries/use-monthly-dividend-mutation.ts @@ -0,0 +1,37 @@ +import { createQueryKeys } from "@lukemorales/query-key-factory"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { useStocksStore } from "../stores/stocks-store"; +import React from "react"; +import { getMonthlyDividends } from "@/api/generated/endpoint"; +import { MonthlyDividendResponse } from "@/api/generated/endpoint.schemas"; + +export const MonthlyDividendQueryKeys = createQueryKeys("monthly-dividend"); + +export const useMonthlyDividendMutation = () => { + const { stocks } = useStocksStore(); + + const tickerShares = React.useMemo( + () => + stocks.map((stock) => ({ + share: stock.count, + ticker: stock.ticker ?? "", + })), + [stocks] + ); + + const requestClient = async (): Promise => { + const response = await getMonthlyDividends({ + tickerShares, + }); + return response.data; + }; + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: MonthlyDividendQueryKeys._def, + mutationFn: requestClient, + onSuccess: (data) => { + queryClient.setQueryData(MonthlyDividendQueryKeys._def, data); + }, + }); +}; diff --git a/src/utils/date.ts b/src/utils/date.ts index 3ddb733..3a5c26f 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -14,3 +14,19 @@ export function formatDateStringToMonthDay(dateString: string): string { return formattedDate + suffix; } + +export const getYearRange = (date: Date): string => { + const startDate = new Date(date); + const endDate = new Date(startDate.getFullYear() + 1, startDate.getMonth(), startDate.getDate()); + + const startYear = startDate.getFullYear(); + const startMonth = startDate.getMonth() + 1; + const endYear = endDate.getFullYear(); + const endMonth = endDate.getMonth() + 1; + + const formattedStartMonth = startMonth < 10 ? `0${startMonth}` : startMonth.toString(); + const formattedEndMonth = endMonth < 10 ? `0${endMonth}` : endMonth.toString(); + + const dateRange = `${startYear}.${formattedStartMonth} ~ ${endYear}.${formattedEndMonth}`; + return dateRange; +};