Skip to content

Commit cc78953

Browse files
committed
feat(frontend): cooperative-page
1 parent bb3a393 commit cc78953

File tree

14 files changed

+705
-2
lines changed

14 files changed

+705
-2
lines changed
Lines changed: 10 additions & 0 deletions
Loading
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from "react";
2+
3+
import Link from "next/link";
4+
5+
import Button from "@/components/Button";
6+
import { CooperativeLearnMoreSection } from "@/queries/cooperative/member-section";
7+
import Image from "next/image";
8+
9+
const LearnMore: React.FC<CooperativeLearnMoreSection> = ({
10+
title,
11+
button,
12+
background,
13+
}) => {
14+
return (
15+
<div className="relative w-full flex flex-col items-center justify-center mt-16 p-8 ">
16+
<h2 className="text-primary-text text-xl mb-8 z-[1]">{title}</h2>
17+
<Link
18+
href={button.link.url}
19+
target="_blank"
20+
rel="noopener noreferrer"
21+
className="z-[1]"
22+
>
23+
<Button>
24+
<span className="text-background-2">{button.text}</span>
25+
</Button>
26+
</Link>
27+
<Image
28+
src={background.url}
29+
alt="Learn more Image Background"
30+
fill
31+
className="object-cover rounded-2xl"
32+
/>
33+
</div>
34+
);
35+
};
36+
export default LearnMore;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import ExternalLink from "@/components/ExternalLink";
2+
import { CooperativePageMemberQueryType } from "@/queries/cooperative/member-section";
3+
import LearnMore from "./LearnMore";
4+
5+
interface IMemberSection {
6+
memberData: CooperativePageMemberQueryType["cooperativePageMemberSection"];
7+
}
8+
9+
const MemberSection: React.FC<IMemberSection> = ({ memberData }) => {
10+
return (
11+
<div className="bg-background-1 py-12 lg:py-24 px-6 lg:px-32">
12+
<h1 className="text-2xl lg:text-3xl text-primary-text font-medium mb-8">
13+
{memberData.header}
14+
</h1>
15+
<p className="text-lg text-secondary-text mb-16">{memberData.subtitle}</p>
16+
<LearnMore {...memberData.learnMoreSection} />
17+
<h1 className="text-2xl lg:text-3xl text-primary-text font-medium mb-8 mt-16">
18+
{memberData.secondaryHeader}
19+
</h1>
20+
<ExternalLink
21+
url={memberData.arrowLink.link.url}
22+
text={memberData.arrowLink.text}
23+
className="!gap-2"
24+
/>
25+
</div>
26+
);
27+
};
28+
29+
export default MemberSection;
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import Dropdown from "@/components/Dropdown";
2+
import { Reports } from "./ReportCard";
3+
import { useEffect, useMemo, useState } from "react";
4+
import { Report } from "@/queries/cooperative/report-section";
5+
6+
interface IDropdownContainer
7+
extends Pick<Report, "yearDropdownLabel" | "monthDropdownLabel"> {
8+
reports: Reports;
9+
setReportUrl: (url?: string) => void;
10+
}
11+
12+
const DropdownContainer: React.FC<IDropdownContainer> = ({
13+
reports,
14+
setReportUrl,
15+
yearDropdownLabel,
16+
monthDropdownLabel,
17+
}) => {
18+
const [year, setYear] = useState<number>();
19+
const [month, setMonth] = useState<string>();
20+
21+
const yearsSet = useMemo(
22+
() =>
23+
reports.reduce<Set<number>>((acc, current) => {
24+
acc.add(current.year);
25+
return acc;
26+
}, new Set([])),
27+
[reports]
28+
);
29+
30+
const years = useMemo(
31+
() =>
32+
Array.from(new Set(yearsSet))
33+
.sort((a, b) => a - b)
34+
.map((year) => ({
35+
key: year,
36+
value: year,
37+
})),
38+
[yearsSet]
39+
);
40+
41+
const monthsSet = useMemo(
42+
() =>
43+
reports.reduce<Set<string>>((acc, current) => {
44+
if (current.month) {
45+
acc.add(current.month);
46+
}
47+
return acc;
48+
}, new Set([])),
49+
[reports]
50+
);
51+
52+
const months = useMemo(
53+
() =>
54+
Array.from(new Set(monthsSet))
55+
.sort((a, b) => monthOrder.indexOf(a) - monthOrder.indexOf(b))
56+
.map((month) => ({
57+
key: month,
58+
value: month,
59+
})),
60+
[monthsSet]
61+
);
62+
63+
const isMonthInfo = months.length !== 0;
64+
65+
useEffect(() => {
66+
const selectedReport = reports.find(
67+
(report) =>
68+
(isMonthInfo ? report.month === month : true) && report.year === year
69+
);
70+
setReportUrl(selectedReport?.url);
71+
}, [month, year]);
72+
73+
return (
74+
<div className="flex flex-col md:flex-row gap-8 items-start md:items-center">
75+
<div className="flex gap-4 items-center">
76+
<label className="text-lg text-secondary-text">
77+
{yearDropdownLabel}
78+
</label>
79+
<Dropdown
80+
items={years}
81+
value={year}
82+
onChange={(val) => setYear(Number(val))}
83+
/>
84+
</div>
85+
{isMonthInfo ? (
86+
<div className="flex gap-4 items-center">
87+
<label className="text-lg text-secondary-text">
88+
{monthDropdownLabel}
89+
</label>
90+
<Dropdown
91+
items={months}
92+
value={month}
93+
onChange={(val) => setMonth(val.toString())}
94+
/>
95+
</div>
96+
) : null}
97+
</div>
98+
);
99+
};
100+
101+
const monthOrder = [
102+
"January",
103+
"February",
104+
"March",
105+
"April",
106+
"May",
107+
"June",
108+
"July",
109+
"August",
110+
"September",
111+
"October",
112+
"November",
113+
"December",
114+
];
115+
export default DropdownContainer;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import Image from "next/image";
2+
3+
import Button from "@/components/Button";
4+
import { Report } from "@/queries/cooperative/report-section";
5+
import { useState } from "react";
6+
import DropdownContainer from "./DropdownContainer";
7+
import Link from "next/link";
8+
9+
export type Reports = {
10+
url: string;
11+
month?: string;
12+
year: number;
13+
}[];
14+
15+
interface IReportCard extends Report {
16+
reports: Reports;
17+
}
18+
const ReportCard: React.FC<IReportCard> = ({
19+
title,
20+
subtitle,
21+
icon,
22+
reports,
23+
yearDropdownLabel,
24+
monthDropdownLabel,
25+
downloadButtonText,
26+
}) => {
27+
const [reportUrl, setReportUrl] = useState<string>();
28+
29+
return (
30+
<div className="bg-background-2 flex flex-col md:flex-row gap-16 pb-7 justify-between">
31+
<div className="flex flex-col gap-8 items-start">
32+
<h2 className="text-2xl md:text-3xl font-medium text-primary-text">
33+
{title}
34+
</h2>
35+
<p className="text-lg text-secondary-text">{subtitle}</p>
36+
37+
<DropdownContainer
38+
{...{
39+
reports,
40+
setReportUrl,
41+
yearDropdownLabel,
42+
monthDropdownLabel,
43+
}}
44+
/>
45+
46+
<Link href={reportUrl ?? ""} target="_blank" rel="noreferrer noopenner">
47+
<Button variant="primary" className="text-background-1">
48+
{downloadButtonText}
49+
</Button>
50+
</Link>
51+
</div>
52+
53+
<div className="relative w-32 h-32 md:w-56 md:h-56 flex-shrink-0">
54+
<Image src={icon.url} alt={icon.name} fill className="object-contain" />
55+
</div>
56+
</div>
57+
);
58+
};
59+
export default ReportCard;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import ReportCard from "./ReportCard";
2+
3+
import {
4+
CooperativePageReportQueryType,
5+
ReportType,
6+
} from "@/queries/cooperative/report-section";
7+
8+
interface IReportSection {
9+
reportsData: CooperativePageReportQueryType;
10+
}
11+
12+
const ReportSection: React.FC<IReportSection> = ({ reportsData }) => {
13+
const getReports = (reportType: ReportType) => {
14+
switch (reportType) {
15+
case "annual":
16+
return reportsData.annualReports;
17+
case "risk":
18+
return reportsData.riskReports;
19+
default:
20+
return reportsData.treasuryReports;
21+
}
22+
};
23+
return (
24+
<div className="bg-background-2 py-12 lg:py-24 px-6 lg:px-32 flex flex-col gap-24">
25+
{reportsData.cooperativePageReportSection.reports.map((report, i) => (
26+
<ReportCard
27+
key={i}
28+
{...report}
29+
reports={getReports(report.reportType)}
30+
/>
31+
))}
32+
</div>
33+
);
34+
};
35+
36+
export default ReportSection;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React from "react";
2+
3+
import Image from "next/image";
4+
import Link from "next/link";
5+
6+
import ExternalLink from "../ExternalLink";
7+
8+
import Button from "@/components/Button";
9+
import { HeroQueryType } from "@/queries/cooperative/hero";
10+
11+
interface IHero {
12+
heroData: HeroQueryType["cooperativePageHero"];
13+
}
14+
15+
const Hero: React.FC<IHero> = ({ heroData }) => {
16+
const { header, subtitle, buttons, arrowLink, background } = heroData;
17+
return (
18+
<div className="relative pt-52 pb-52 lg:pb-56 px-6 lg:px-32">
19+
<div className="space-y-8">
20+
<h1 className="text-3xl lg:text-4xl font-medium">{header}</h1>
21+
<p className="text-lg max-w-[685px]">{subtitle}</p>
22+
<div className="flex flex-wrap gap-6 items-center">
23+
{buttons.map((button) => (
24+
<Link
25+
key={button.text}
26+
href={button.link.url}
27+
target="_blank"
28+
rel="noopener noreferrer"
29+
>
30+
<Button
31+
variant="secondary"
32+
className=" hover:!bg-primary-blue hover:!border-primary-blue hover:!text-background-2"
33+
>
34+
<span>{button.text}</span>
35+
</Button>
36+
</Link>
37+
))}
38+
</div>
39+
<ExternalLink
40+
url={arrowLink.link.url}
41+
text={arrowLink.text}
42+
className="[&>span]:text-primary-text [&>span]:text-base"
43+
/>
44+
</div>
45+
<Image
46+
src={background.url}
47+
alt="Hero Image Background"
48+
fill
49+
className="absolute top-0 left-0 h-full z-[-1] object-cover"
50+
/>
51+
</div>
52+
);
53+
};
54+
55+
export default Hero;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import clsx from "clsx";
2+
import { DropdownItem } from ".";
3+
4+
const dropwdownItemBaseStyle = clsx(
5+
"w-full rounded-lg text-secondary-text text-left py-3 px-4"
6+
);
7+
const selectedStyle = clsx("!text-primary-blue bg-background-2");
8+
const dropdownItemHoverStyle = clsx(
9+
"hover:text-primary-blue hover:bg-background-2 cursor-pointer"
10+
);
11+
12+
interface IDropdownItem {
13+
item: DropdownItem;
14+
value?: DropdownItem["value"];
15+
handleClick: (val: DropdownItem["value"]) => void;
16+
}
17+
const DropdownItemButton: React.FC<IDropdownItem> = ({
18+
item,
19+
value,
20+
handleClick,
21+
}) => (
22+
<button
23+
className={clsx(
24+
dropwdownItemBaseStyle,
25+
dropdownItemHoverStyle,
26+
value === item.value ? selectedStyle : ""
27+
)}
28+
onClick={() => handleClick(item.value)}
29+
>
30+
{item.key}
31+
</button>
32+
);
33+
34+
export default DropdownItemButton;

0 commit comments

Comments
 (0)