Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: connect backend api with sector insight on sector detail page #44

Merged
merged 3 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/app/(main)/report/dividend/_components/dividend-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { StockResponse } from "@/api/generated/endpoint.schemas";
import Image from "next/image";
import React from "react";

export interface Dividend extends StockResponse {}
export interface Dividend extends StockResponse {
share?: number;
}

export const DividendRow = React.memo(({ dividend }: { dividend: Dividend }) => {
return (
<div className="flex h-full w-full flex-1 items-center gap-4">
<Image src={dividend.logoUrl} alt={dividend.companyName} width={40} height={40} />
<Image src={dividend.logoUrl ?? "/next.svg"} alt={dividend.companyName} width={40} height={40} />
<div className="items-between flex w-full flex-col justify-center gap-1">
<div className="flex items-center justify-between">
<p className="text-h5 text-grey-900">{dividend.companyName}</p>
Expand Down
10 changes: 9 additions & 1 deletion src/app/(main)/report/sector-detail/[sector]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ import { useQueryClient } from "@tanstack/react-query";
import { enteredStocksQueryKeys } from "@/state/queries/use-stocks-sector-ratio";
import { SectorRatioResponse } from "@/api/generated/endpoint.schemas";
import { DividendList } from "../_components/dividend-list";
import { useComingDividendStocksQuery } from "../../../../../state/queries/use-coming-dividend-stocks.ts";
import { useBiggestDividendYieldStocksQuery } from "../../../../../state/queries/use-biggest-dividend-yield-stocks";

const SectorDetailPage = React.memo(({ params }: { params: { sector: string } }) => {
const queryClient = useQueryClient();
const { data: comingDividendStocks } = useComingDividendStocksQuery();
const { data: biggestDividendYieldStocks } = useBiggestDividendYieldStocksQuery();

const data = React.useMemo(
() =>
Expand Down Expand Up @@ -45,7 +49,11 @@ const SectorDetailPage = React.memo(({ params }: { params: { sector: string } })
/>
<DividendList dividendList={sectorData.stockShares} />
<div className="h-4 bg-gray-100" />
<SectorInsights />

<SectorInsights
comingDividendStocks={comingDividendStocks}
biggestDividendYieldStocks={biggestDividendYieldStocks}
/>
</div>
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import React from "react";
import { StockShareResponse } from "@/api/generated/endpoint.schemas";
import { DividendRow } from "../../dividend/_components/dividend-row";

export const DividendList = React.memo(({ dividendList }: { dividendList: StockShareResponse[] }) => {
return (
<div className="flex w-full flex-col items-center justify-start gap-6 overflow-y-auto px-5 py-8">
{dividendList.map((dividend, idx) => (
<></>
// <DividendRow dividend={dividend} key={idx} />
<DividendRow
key={idx}
dividend={{
...dividend.stockResponse,
share: dividend.share,
}}
/>
))}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { formatDateStringToMonthDay } from "@/utils/date";
import Image from "next/image";
import React from "react";
import { useRouter } from "next/navigation";
import React, { useCallback } from "react";

export interface InsightsStock {
interface InsightsStock {
stockId: string;
ticker: string;
logoUrl: string;
exDividendDate: string;
sectorRatio?: number;
exDividendDate?: string;
dividendYield?: number;
}

interface SectorInsightsItemProps {
Expand All @@ -19,17 +20,33 @@ interface SectorInsightsItemProps {
type InsightsType = "Date" | "Rate";

export const SectorInsightsItem = React.memo(({ title, stocks, type }: SectorInsightsItemProps) => {
const router = useRouter();

const handleItemClick = useCallback(
(id: string) => {
router.push(`/stock/${id}`);
},
[router]
);

return (
<div className="flex w-full flex-col">
<h4 className="mb-4 px-5 text-h4 text-grey-900 ">{title}</h4>

<div className="scrollbar-none flex gap-2.5 overflow-x-auto overflow-y-hidden px-5 ">
{stocks.map((stock, idx) => {
return (
<div key={idx} className="rounded-lg border border-grey-200 p-4" style={{ minWidth: 119, maxWidth: 119 }}>
<div
key={idx}
className="rounded-lg border border-grey-200 p-4"
style={{ minWidth: 119, maxWidth: 119 }}
onClick={() => {
handleItemClick(stock.stockId);
}}
>
<div className="flex flex-col gap-4">
<Image
src={"/next.svg"}
src={stock.logoUrl ?? "/next.svg"}
alt={stock.ticker}
className="h-8 w-8 rounded-full border border-grey-100"
width={32}
Expand All @@ -39,9 +56,9 @@ export const SectorInsightsItem = React.memo(({ title, stocks, type }: SectorIns
<div>
<h5 className="text-h5 text-grey-900">{stock.ticker}</h5>
<p className="mt-0.5 truncate text-body2 text-main-900">
{type === "Date" && formatDateStringToMonthDay(stock.exDividendDate)}
{type === "Date" && stock.exDividendDate && formatDateStringToMonthDay(stock.exDividendDate)}
{type === "Rate" &&
`${stock.sectorRatio !== undefined ? (stock.sectorRatio * 100).toFixed(0) : 0}%`}
`${stock.dividendYield !== undefined ? Math.floor(stock.dividendYield * 100) / 100 : 0}%`}
</p>
</div>
</div>
Expand Down
105 changes: 31 additions & 74 deletions src/app/(main)/report/sector-detail/_components/sector-insights.tsx
Original file line number Diff line number Diff line change
@@ -1,78 +1,35 @@
import React from "react";
import { InsightsStock, SectorInsightsItem } from "./sector-insights-item";
import { SectorInsightsItem } from "./sector-insights-item";
import { StockDividendYieldResponse, UpcomingDividendResponse } from "../../../../../api/generated/endpoint.schemas";

const dummyExDividendList: InsightsStock[] = [
{
stockId: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
ticker: "string",
logoUrl: "string",
exDividendDate: "2024-02-23T07:21:48.256Z",
},
{
stockId: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
ticker: "string",
logoUrl: "string",
exDividendDate: "2024-02-23T07:21:48.256Z",
},
{
stockId: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
ticker: "string",
logoUrl: "string",
exDividendDate: "2024-02-23T07:21:48.256Z",
},
{
stockId: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
ticker: "string",
logoUrl: "string",
exDividendDate: "2024-02-23T07:21:48.256Z",
},
];
const dummyTopDividendList: InsightsStock[] = [
{
stockId: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
ticker: "string",
logoUrl: "string",
exDividendDate: "2024-02-23T07:21:48.256Z",
sectorRatio: 0.49,
},
{
stockId: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
ticker: "string",
logoUrl: "string",
exDividendDate: "2024-02-23T07:21:48.256Z",
sectorRatio: 0.49,
},
{
stockId: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
ticker: "string",
logoUrl: "string",
exDividendDate: "2024-02-23T07:21:48.256Z",
sectorRatio: 0.49,
},
{
stockId: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
ticker: "string",
logoUrl: "string",
exDividendDate: "2024-02-23T07:21:48.256Z",
sectorRatio: 0.49,
},
];
interface SectorInsightsProps {
comingDividendStocks?: UpcomingDividendResponse[];
biggestDividendYieldStocks?: StockDividendYieldResponse[];
}

export const SectorInsights = React.memo(() => {
return (
<>
<div className="flex w-full flex-col gap-2 border-b border-b-gray-200 px-5 py-8">
<h2 className="text-h2 text-grey-900">Sector Insights</h2>
<p className="text-body3 text-grey-600">
{`Last updated `}
<span className="text-main-700">{`${"2024/01/27 21:38"}`}</span>{" "}
</p>
</div>
export const SectorInsights = React.memo(
({ comingDividendStocks, biggestDividendYieldStocks }: SectorInsightsProps) => {
if (!comingDividendStocks && !biggestDividendYieldStocks) return null;

<div className="flex w-full flex-col gap-10 py-8">
<SectorInsightsItem title={"Approaching Ex-Dividend dates"} stocks={dummyExDividendList} type="Date" />
<SectorInsightsItem title={"Top Recent Dividend Yields"} stocks={dummyTopDividendList} type="Rate" />
</div>
</>
);
});
return (
<>
<div className="flex w-full flex-col gap-2 border-b border-b-gray-200 px-5 py-8">
<h2 className="text-h2 text-grey-900">Sector Insights</h2>
<p className="text-body3 text-grey-600">
{`Last updated `}
<span className="text-main-700">{`${"2024/01/27 21:38"}`}</span>{" "}
</p>
</div>

<div className="flex w-full flex-col gap-10 py-8">
{comingDividendStocks && (
<SectorInsightsItem title={"Approaching Ex-Dividend dates"} stocks={comingDividendStocks} type="Date" />
)}
{biggestDividendYieldStocks && (
<SectorInsightsItem title={"Top Recent Dividend Yields"} stocks={biggestDividendYieldStocks} type="Rate" />
)}
</div>
</>
);
}
);
21 changes: 21 additions & 0 deletions src/state/queries/use-biggest-dividend-yield-stocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { getBiggestDividendYieldStocks } from "@/api/generated/endpoint";
import { createQueryKeys } from "@lukemorales/query-key-factory";
import { useQuery } from "@tanstack/react-query";
import { StockDividendYieldResponse } from "../../api/generated/endpoint.schemas";

export const biggestDividendYieldStocksQueryKeys = createQueryKeys("biggest-dividend-yield-stocks");

export const useBiggestDividendYieldStocksQuery = () => {
const requestClient = async (): Promise<StockDividendYieldResponse[]> => {
const { data } = await getBiggestDividendYieldStocks({ pageNumber: 1, pageSize: 5 });
return data;
};

return useQuery({
queryKey: [biggestDividendYieldStocksQueryKeys._def],
queryFn: () => requestClient(),
staleTime: Infinity,
gcTime: Infinity,
retry: 1,
});
};
21 changes: 21 additions & 0 deletions src/state/queries/use-coming-dividend-stocks.ts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { getUpComingDividendStocks } from "@/api/generated/endpoint";
import { createQueryKeys } from "@lukemorales/query-key-factory";
import { useQuery } from "@tanstack/react-query";
import { UpcomingDividendResponse } from "../../api/generated/endpoint.schemas";

export const comingDividendStocksQueryKeys = createQueryKeys("coming-dividend-stocks");

export const useComingDividendStocksQuery = () => {
const requestClient = async (): Promise<UpcomingDividendResponse[]> => {
const { data } = await getUpComingDividendStocks({ pageNumber: 1, pageSize: 5 });
return data;
};

return useQuery({
queryKey: [comingDividendStocksQueryKeys._def],
queryFn: () => requestClient(),
staleTime: Infinity,
gcTime: Infinity,
retry: 1,
});
};