Skip to content

Commit 39c53f5

Browse files
author
Nick Lionis
authored
Chore/leaderboard improvements (#78)
* fix: sorting bug after changing pages * feat: adds share to twitter btn on voting interface * added changeset
1 parent 9f371ae commit 39c53f5

File tree

8 files changed

+92
-20
lines changed

8 files changed

+92
-20
lines changed

.changeset/nine-cars-relate.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@gitcoin/ui": patch
3+
---
4+
5+
chore: improve leaderboard sorting
6+
feat: add share to twitter btn after submitting the ballot

packages/ui/src/features/retrofunding/components/BallotForm/BallotForm.stories.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,11 @@ export const AlreadyVoted: Story = {
9090
},
9191
},
9292
};
93+
94+
export const ShareBallot: Story = {
95+
args: {
96+
...AlreadyVoted.args,
97+
name: "shareBallot-metrics",
98+
onShare: action("onShare"),
99+
},
100+
};

packages/ui/src/features/retrofunding/components/BallotForm/BallotForm.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ interface BallotFormProps {
3434
maxAllocation?: number;
3535
onSubmit: (values: BallotValues[]) => void;
3636
onChange?: (values: BallotValues[]) => void;
37+
onShare?: () => void;
3738
}
3839

3940
const getTotalAllocation = (items: BallotItemsMap) =>
@@ -52,6 +53,7 @@ export const BallotForm: React.FC<BallotFormProps> = ({
5253
maxAllocation = 100,
5354
onSubmit,
5455
onChange,
56+
onShare,
5557
}) => {
5658
const { getValue, setValue, isReady } = useIndexedDB({
5759
dbName: DB_NAME,
@@ -182,7 +184,10 @@ export const BallotForm: React.FC<BallotFormProps> = ({
182184

183185
return (
184186
<div className={cn("flex flex-col gap-6", className)}>
185-
<AlreadyVotedBadge submittedAt={submittedBallot?.submittedAt} />
187+
<AlreadyVotedBadge
188+
submittedAt={submittedBallot?.submittedAt}
189+
onShare={onShare}
190+
/>
186191
<div className="w-[720px] space-y-4 rounded-xl border border-grey-300 bg-grey-50 p-10">
187192
<BallotHeader sortOrder={sortOrder ?? DEFAULT_SORT_ORDER} setSortOrder={setSortOrder} />
188193
<div>
Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
11
import moment from "moment";
22

3-
export const AlreadyVotedBadge = ({ submittedAt }: { submittedAt?: string }) => {
3+
import { Button } from "@/primitives";
4+
import { IconType, Icon } from "@/primitives";
5+
6+
export const AlreadyVotedBadge = ({
7+
submittedAt,
8+
onShare,
9+
}: {
10+
submittedAt?: string;
11+
onShare?: () => void;
12+
}) => {
413
if (!submittedAt) return null;
514
return (
6-
<p className="rounded-xl bg-moss-100 p-4 text-sm font-medium text-moss-300">
7-
{`Your ballot was submitted on ${moment(submittedAt).format(
8-
"MMMM D, YYYY [at] HH:mm [UTC]",
9-
)}.`}
10-
</p>
15+
<div className="flex items-center justify-between rounded-xl bg-moss-100 p-4">
16+
<p className="text-sm font-medium text-moss-700">
17+
{`Your ballot was submitted on ${moment(submittedAt).format(
18+
"MMMM D, YYYY [at] HH:mm [UTC]",
19+
)}.`}
20+
</p>
21+
{onShare && (
22+
<Button
23+
value="Share on"
24+
icon={<Icon type={IconType.TWITTER} className="size-4 fill-white" />}
25+
iconPosition="right"
26+
onClick={onShare}
27+
/>
28+
)}
29+
</div>
1130
);
1231
};

packages/ui/src/features/retrofunding/components/Leaderboard/Leaderboard.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { useMediaQuery } from "usehooks-ts";
88
import { cn } from "@/lib/utils";
99

1010
import { DesktopLeaderboard, MobileLeaderboard } from "./components";
11-
import { LeaderboardProps } from "./types";
11+
import { LeaderboardProps, SortConfig } from "./types";
1212

1313
const leaderboardVariants = tv({
1414
base: "leaderboard-container",
@@ -44,7 +44,7 @@ const leaderboardVariants = tv({
4444

4545
interface LeaderboardPropsWithVariants
4646
extends VariantProps<typeof leaderboardVariants>,
47-
Omit<LeaderboardProps, "expandedProject" | "setExpandedProject" | "paginationProps"> {}
47+
Omit<LeaderboardProps, "expandedProject" | "setExpandedProject" | "paginationProps" | "sortConfig" | "setSortConfig"> {}
4848

4949
export const Leaderboard = ({ projects, metrics, ...props }: LeaderboardPropsWithVariants) => {
5050
const leaderboardClassNames = leaderboardVariants({
@@ -53,6 +53,7 @@ export const Leaderboard = ({ projects, metrics, ...props }: LeaderboardPropsWit
5353
const [currentPage, setCurrentPage] = useState(1);
5454
const [itemsPerPage, setItemsPerPage] = useState(10);
5555
const [expandedProject, setExpandedProject] = useState<number | null>(null);
56+
const [sortConfig, setSortConfig] = useState<SortConfig>({ key: "rank", direction: "asc" });
5657
const isDesktopView = useMediaQuery("(min-width: 768px)");
5758

5859
const totalProjects = Object.keys(projects).length;
@@ -115,6 +116,8 @@ export const Leaderboard = ({ projects, metrics, ...props }: LeaderboardPropsWit
115116
expandedProject={expandedProject}
116117
setExpandedProject={setExpandedProject}
117118
parentWidth={parentWidth}
119+
sortConfig={sortConfig}
120+
setSortConfig={setSortConfig}
118121
/>
119122
) : (
120123
<MobileLeaderboard
@@ -130,6 +133,8 @@ export const Leaderboard = ({ projects, metrics, ...props }: LeaderboardPropsWit
130133
}}
131134
expandedProject={expandedProject}
132135
setExpandedProject={setExpandedProject}
136+
sortConfig={sortConfig}
137+
setSortConfig={setSortConfig}
133138
/>
134139
)}
135140
</div>

packages/ui/src/features/retrofunding/components/Leaderboard/components/DesktopLeaderboard.tsx

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export const DesktopLeaderboard = ({
3535
expandedProject,
3636
setExpandedProject,
3737
parentWidth,
38+
sortConfig,
39+
setSortConfig,
3840
}: LeaderboardProps & { parentWidth: number }) => {
3941
const {
4042
headerText,
@@ -46,7 +48,6 @@ export const DesktopLeaderboard = ({
4648
icon,
4749
tooltipText,
4850
} = desktopLeaderboard();
49-
const [sortConfig, setSortConfig] = useState<SortConfig>({ key: "rank", direction: "asc" });
5051
const ranks = Object.keys(projects).map(Number);
5152
const metricIds = Object.keys(metrics);
5253

@@ -77,14 +78,9 @@ export const DesktopLeaderboard = ({
7778
);
7879

7980
const handleSort = (key: "rank" | string) => {
80-
setSortConfig((currentConfig) => {
81-
if (currentConfig.key === key) {
82-
return {
83-
key,
84-
direction: currentConfig.direction === "asc" ? "desc" : "asc",
85-
};
86-
}
87-
return { key, direction: "desc" };
81+
setSortConfig({
82+
key,
83+
direction: sortConfig.key === key && sortConfig.direction === "asc" ? "desc" : "asc",
8884
});
8985
};
9086

packages/ui/src/features/retrofunding/components/Leaderboard/components/MobileLeaderboard.tsx

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ export const MobileLeaderboard = ({
2929
paginationProps,
3030
expandedProject,
3131
setExpandedProject,
32+
sortConfig,
33+
setSortConfig,
3234
}: LeaderboardProps) => {
3335
const {
3436
rankBadge,
@@ -51,12 +53,33 @@ export const MobileLeaderboard = ({
5153
...projects[rank],
5254
}))
5355
.sort((a, b) => {
54-
return a.originalRank - b.originalRank;
56+
if (sortConfig.key === "rank") {
57+
return sortConfig.direction === "asc"
58+
? a.originalRank - b.originalRank
59+
: b.originalRank - a.originalRank;
60+
}
61+
62+
const aValue = a.metrics[sortConfig.key];
63+
const bValue = b.metrics[sortConfig.key];
64+
65+
if (sortConfig.direction === "asc") {
66+
return aValue - bValue;
67+
}
68+
return bValue - aValue;
5569
});
70+
5671
const paginatedProjects = sortedProjects.slice(
5772
(paginationProps.currentPage - 1) * paginationProps.rowsPerPage,
5873
paginationProps.currentPage * paginationProps.rowsPerPage,
5974
);
75+
76+
const handleSort = (key: "rank" | string) => {
77+
setSortConfig({
78+
key,
79+
direction: sortConfig.key === key && sortConfig.direction === "asc" ? "desc" : "asc",
80+
});
81+
};
82+
6083
return (
6184
<div className="space-y-4 p-1">
6285
{paginatedProjects.map((projectData) => {
@@ -74,6 +97,7 @@ export const MobileLeaderboard = ({
7497
originalRank === 1 && firstRankBadge(),
7598
originalRank === 2 && secondRankBadge(),
7699
)}
100+
onClick={() => handleSort("rank")}
77101
>
78102
{originalRank}
79103
</span>
@@ -102,7 +126,9 @@ export const MobileLeaderboard = ({
102126
{metricIds.map((metricId) => (
103127
<div key={metricId} className="space-y-1">
104128
<div className="flex items-center gap-1">
105-
<span className={metricLabel()}>{metrics[metricId].name}</span>
129+
<span className={metricLabel()} onClick={() => handleSort(metricId)}>
130+
{metrics[metricId].name}
131+
</span>
106132
{metrics[metricId].description && (
107133
<IconWithTooltip
108134
iconType={IconType.INFORMATION_CIRCLE}
@@ -111,6 +137,11 @@ export const MobileLeaderboard = ({
111137
tooltipClassName={tooltipText()}
112138
/>
113139
)}
140+
<Icon
141+
type={IconType.SORT}
142+
className={cn(icon())}
143+
onClick={() => handleSort(metricId)}
144+
/>
114145
</div>
115146
<div className={metricValue()}>{projectMetrics[metricId]}</div>
116147
</div>

packages/ui/src/features/retrofunding/components/Leaderboard/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export interface LeaderboardProps {
3131
};
3232
expandedProject: number | null;
3333
setExpandedProject: (project: number | null) => void;
34+
sortConfig: SortConfig;
35+
setSortConfig: (config: SortConfig) => void;
3436
}
3537

3638
export interface SortConfig {

0 commit comments

Comments
 (0)