Skip to content

Commit 06c695d

Browse files
Resolve shot's comments (#205)
* feat: add name and tag validation to create * feat: add no activity data in activity tab * add coming soon sections for profile page * feat: clicking on leaderboard feed hashtag will redirect to that feed * fix: keeps name on start when disable feed names collapse * fix: rsbuild * fix: add routegen to prettier ignore * fix: add ability to navigate to collapsed feeds in leaderboard * add ability to expand or collapse all * fix: rsbuild * adjustments * nitpicks --------- Co-authored-by: Elliot Braem <elliot@ejlbraem.com>
1 parent 713ec36 commit 06c695d

File tree

10 files changed

+163
-33
lines changed

10 files changed

+163
-33
lines changed

apps/app/src/components/Leaderboard.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from "react";
2+
import { ChevronDown, ChevronUp } from "lucide-react";
23
import { LeaderboardEntry } from "../lib/api";
34
import { Container } from "./Container";
45
import { Hero } from "./Hero";
@@ -33,6 +34,8 @@ export default React.memo(function Leaderboard({
3334
handleTimeDropdownToggle,
3435
handleFeedDropdownClose,
3536
handleTimeDropdownClose,
37+
expandAllRows,
38+
collapseAllRows,
3639
feedDropdownRef,
3740
timeDropdownRef,
3841
table,
@@ -63,6 +66,25 @@ export default React.memo(function Leaderboard({
6366
timeDropdownRef={timeDropdownRef}
6467
/>
6568

69+
{hasData && (
70+
<div className="flex justify-end gap-2 mb-4">
71+
<button
72+
onClick={expandAllRows}
73+
className="flex items-center gap-1.5 px-3 py-2 text-sm border border-neutral-300 rounded-md bg-white hover:bg-neutral-50 transition-colors text-[#111111]"
74+
>
75+
<ChevronDown className="h-4 w-4" />
76+
Expand All
77+
</button>
78+
<button
79+
onClick={collapseAllRows}
80+
className="flex items-center gap-1.5 px-3 py-2 text-sm border border-neutral-300 rounded-md bg-white hover:bg-neutral-50 transition-colors text-[#111111]"
81+
>
82+
<ChevronUp className="h-4 w-4" />
83+
Collapse All
84+
</button>
85+
</div>
86+
)}
87+
6688
<LeaderboardTable
6789
table={table}
6890
isLoading={isLoading}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Clock, Sparkles } from "lucide-react";
2+
import { Card } from "./ui/card";
3+
import { Badge } from "./ui/badge";
4+
5+
interface ComingSoonProps {
6+
title: string;
7+
description?: string;
8+
features?: string[];
9+
}
10+
11+
export function ComingSoon({ title, description, features }: ComingSoonProps) {
12+
return (
13+
<Card className="p-6 space-y-6">
14+
<div className="text-center space-y-4">
15+
<div className="flex items-center justify-center space-x-2">
16+
<Sparkles className="h-8 w-8" />
17+
<h2 className="text-2xl font-semibold">{title}</h2>
18+
</div>
19+
20+
<Badge
21+
variant="secondary"
22+
className="flex items-center space-x-1 w-fit mx-auto"
23+
>
24+
<Clock className="h-3 w-3" />
25+
<span>Coming Soon</span>
26+
</Badge>
27+
28+
{description && (
29+
<p className="text-gray-600 dark:text-gray-400 max-w-md mx-auto">
30+
{description}
31+
</p>
32+
)}
33+
</div>
34+
35+
{features && features.length > 0 && (
36+
<div className="space-y-3">
37+
<h3 className="text-lg font-medium text-center">What to expect:</h3>
38+
<ul className="space-y-2 max-w-md mx-auto">
39+
{features.map((feature, index) => (
40+
<li
41+
key={index}
42+
className="flex items-center space-x-2 text-sm text-gray-600 dark:text-gray-400"
43+
>
44+
<div className="w-1.5 h-1.5 bg-blue-500 rounded-full flex-shrink-0" />
45+
<span>{feature}</span>
46+
</li>
47+
))}
48+
</ul>
49+
</div>
50+
)}
51+
</Card>
52+
);
53+
}

apps/app/src/components/leaderboard/LeaderboardColumns.tsx

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ChevronUp } from "lucide-react";
22
import { createColumnHelper } from "@tanstack/react-table";
33
import { LeaderboardEntry } from "../../lib/api";
44
import { UserLink } from "../FeedItem";
5+
import { Link } from "@tanstack/react-router";
56

67
export interface ExtendedLeaderboardEntry extends LeaderboardEntry {
78
originalRank: number;
@@ -88,14 +89,20 @@ export function createLeaderboardColumns(
8889
<div className="flex flex-col min-h-[32px] justify-center">
8990
<div className="flex items-center gap-2">
9091
{feedSubmissions && feedSubmissions.length > 0 && (
91-
<div className="flex items-center justify-between gap-1 border border-neutral-400 px-2 py-1 rounded-md w-[150px] min-w-0">
92-
<span className="text-sm truncate flex-shrink">
93-
#{feedSubmissions[0].feedId}
94-
</span>
95-
<span className="text-sm whitespace-nowrap flex-shrink-0">
96-
{feedSubmissions[0].count}/{feedSubmissions[0].totalInFeed}
97-
</span>
98-
</div>
92+
<Link
93+
to={"/feed/$feedId"}
94+
params={{ feedId: feedSubmissions[0].feedId }}
95+
>
96+
<div className="flex items-center justify-between gap-1 border border-neutral-400 px-2 py-1 rounded-md w-[150px] min-w-0">
97+
<span className="text-sm truncate flex-shrink">
98+
#{feedSubmissions[0].feedId}
99+
</span>
100+
<span className="text-sm whitespace-nowrap flex-shrink-0">
101+
{feedSubmissions[0].count}/
102+
{feedSubmissions[0].totalInFeed}
103+
</span>
104+
</div>
105+
</Link>
99106
)}
100107

101108
{feedSubmissions && feedSubmissions.length > 1 && (
@@ -118,14 +125,16 @@ export function createLeaderboardColumns(
118125
<div className="flex flex-col gap-2 mt-2 pl-0">
119126
{feedSubmissions.slice(1).map((feed, feedIndex) => (
120127
<div key={feedIndex} className="flex items-center">
121-
<div className="flex items-center gap-1 border border-neutral-400 px-2 py-1 rounded-md justify-between w-[150px] min-w-0">
122-
<span className="text-sm truncate flex-shrink">
123-
#{feed.feedId}
124-
</span>
125-
<span className="text-sm whitespace-nowrap flex-shrink-0">
126-
{feed.count}/{feed.totalInFeed}
127-
</span>
128-
</div>
128+
<Link to={"/feed/$feedId"} params={{ feedId: feed.feedId }}>
129+
<div className="flex items-center gap-1 border border-neutral-400 px-2 py-1 rounded-md justify-between w-[150px] min-w-0">
130+
<span className="text-sm truncate flex-shrink">
131+
#{feed.feedId}
132+
</span>
133+
<span className="text-sm whitespace-nowrap flex-shrink-0">
134+
{feed.count}/{feed.totalInFeed}
135+
</span>
136+
</div>
137+
</Link>
129138
</div>
130139
))}
131140
</div>

apps/app/src/components/leaderboard/LeaderboardFilters.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export function LeaderboardFilters({
4646
timeDropdownRef,
4747
}: LeaderboardFiltersProps) {
4848
return (
49-
<div className="flex flex-col md:flex-row max-w-[400px] md:max-w-screen-xl md:w-full mx-auto justify-between items-center mb-6 gap-4 py-8">
49+
<div className="flex flex-col md:flex-row max-w-[400px] md:max-w-screen-xl md:w-full mx-auto justify-between items-center gap-4 pt-8 pb-4">
5050
<div className="relative w-full md:w-auto">
5151
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-[#a3a3a3] h-4 w-4" />
5252
<input

apps/app/src/components/leaderboard/LeaderboardTable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export function LeaderboardTable({
8484
{row.getVisibleCells().map((cell) => (
8585
<TableCell
8686
key={cell.id}
87-
className="py-2 px-2 align-middle"
87+
className="py-2 px-2 align-baseline"
8888
>
8989
{flexRender(
9090
cell.column.columnDef.cell,

apps/app/src/components/profile/activity/index.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export function ProfileActivity() {
8080
// );
8181

8282
// const transformedActivity = userActivity?.map(transformActivityData);
83+
const hasData = false; // Currently no data is loaded
8384

8485
return (
8586
<div>
@@ -94,10 +95,15 @@ export function ProfileActivity() {
9495
</div>
9596
<div className="w-full border-t border-dashed border-neutral-300 my-1"></div>
9697
{/* <ActivityTable data={transformedActivity} /> */}
98+
{!hasData && (
99+
<div className="p-8 text-center text-gray-500">
100+
No activity data available
101+
</div>
102+
)}
97103
</CardContent>
98104
</Card>
99105

100-
<PaginationControls />
106+
{hasData && <PaginationControls />}
101107
</div>
102108
);
103109
}

apps/app/src/hooks/useLeaderboard.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ export function useLeaderboard(
8686
);
8787
}, []);
8888

89+
const collapseAllRows = useCallback(() => {
90+
setExpandedRows([]);
91+
}, []);
92+
8993
const handleSearch = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
9094
setSearchQuery(e.target.value);
9195
}, []);
@@ -137,6 +141,15 @@ export function useLeaderboard(
137141
});
138142
}, [filteredLeaderboard, leaderboard]);
139143

144+
const expandAllRows = useCallback(() => {
145+
if (!filteredLeaderboardWithRanks) return;
146+
const allRowIndices = Array.from(
147+
{ length: filteredLeaderboardWithRanks.length },
148+
(_, i) => i,
149+
);
150+
setExpandedRows(allRowIndices);
151+
}, [filteredLeaderboardWithRanks]);
152+
140153
const columns = useMemo(() => {
141154
return createLeaderboardColumns(expandedRows, toggleRow);
142155
}, [expandedRows, toggleRow]);
@@ -159,13 +172,16 @@ export function useLeaderboard(
159172
showTimeDropdown,
160173
feeds,
161174
timeOptions,
175+
expandedRows,
162176

163177
// Handlers
164178
handleSearch,
165179
handleFeedDropdownToggle,
166180
handleTimeDropdownToggle,
167181
handleFeedDropdownClose,
168182
handleTimeDropdownClose,
183+
expandAllRows,
184+
collapseAllRows,
169185

170186
// Refs
171187
feedDropdownRef,

apps/app/src/routes/_layout/create/feed/index.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { zodResolver } from "@hookform/resolvers/zod";
22
import { useForm } from "react-hook-form";
3+
import { useState } from "react";
34
import { ImageUpload } from "@/components/ImageUpload";
45
import { Button } from "@/components/ui/button";
56
import {
@@ -43,6 +44,7 @@ function BasicInformationComponent() {
4344
const search = Route.useSearch();
4445
const { feedConfig, setValues } = useFeedCreationStore();
4546
const queryClient = useQueryClient();
47+
const [isValidatingId, setIsValidatingId] = useState(false);
4648

4749
const form = useForm<FormValues>({
4850
resolver: zodResolver(BasicInformationFormSchema),
@@ -66,6 +68,7 @@ function BasicInformationComponent() {
6668
form.clearErrors("id");
6769
return;
6870
}
71+
setIsValidatingId(true);
6972
try {
7073
const data = await queryClient.fetchQuery({
7174
queryKey: ["feed-details", id],
@@ -83,6 +86,8 @@ function BasicInformationComponent() {
8386
}
8487
} catch {
8588
form.clearErrors("id");
89+
} finally {
90+
setIsValidatingId(false);
8691
}
8792
};
8893

@@ -173,8 +178,15 @@ function BasicInformationComponent() {
173178
)}
174179
/>
175180
<div className="flex justify-end">
176-
<Button type="submit" disabled={form.formState.isSubmitting}>
177-
{form.formState.isSubmitting ? "..." : "Next"}
181+
<Button
182+
type="submit"
183+
disabled={form.formState.isSubmitting || isValidatingId}
184+
>
185+
{form.formState.isSubmitting
186+
? "..."
187+
: isValidatingId
188+
? "Validating..."
189+
: "Next"}
178190
</Button>
179191
</div>
180192
</form>
Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createFileRoute } from "@tanstack/react-router";
2-
import { Card } from "../../../../components/ui/card";
2+
import { ComingSoon } from "@/components/coming-soon";
33

44
export const Route = createFileRoute("/_layout/profile/settings/notifications")(
55
{
@@ -9,10 +9,16 @@ export const Route = createFileRoute("/_layout/profile/settings/notifications")(
99

1010
function NotificationsComponent() {
1111
return (
12-
<Card className="p-6 space-y-6">
13-
<h2 className="text-2xl font-semibold">Notification Settings</h2>
14-
<p>Manage your notification preferences here.</p>
15-
{/* Add notification settings form or options here */}
16-
</Card>
12+
<ComingSoon
13+
title="Notification Settings"
14+
description="Stay in the loop with customizable notifications for your curated content and community activity."
15+
features={[
16+
"Email notifications for new submissions and approvals",
17+
"Push notifications for real-time updates",
18+
"Digest settings for weekly summaries",
19+
"Custom notification schedules",
20+
"Fine-grained notification categories",
21+
]}
22+
/>
1723
);
1824
}
Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
import { createFileRoute } from "@tanstack/react-router";
2-
import { Card } from "../../../../components/ui/card";
2+
import { ComingSoon } from "@/components/coming-soon";
33

44
export const Route = createFileRoute("/_layout/profile/settings/preferences")({
55
component: PreferencesComponent,
66
});
77

88
function PreferencesComponent() {
99
return (
10-
<Card className="p-6 space-y-6">
11-
<h2 className="text-2xl font-semibold">User Preferences</h2>
12-
<p>Set your preferences for the application.</p>
13-
{/* Add user preferences form or options here */}
14-
</Card>
10+
<ComingSoon
11+
title="Preferences Settings"
12+
description="Customize your experience with personalized preferences for content, privacy, and accessibility settings."
13+
features={[
14+
"Content preferences for personalized feeds",
15+
"Notification preferences for updates",
16+
"Privacy settings for your account",
17+
"Language and region settings",
18+
"Accessibility options",
19+
]}
20+
/>
1521
);
1622
}

0 commit comments

Comments
 (0)