From feb80916ccb1652d0e93a2084e0c10f9ac3eb7ff Mon Sep 17 00:00:00 2001 From: Ategon <benjamin@barbeau.net> Date: Mon, 20 Jan 2025 00:37:30 -0500 Subject: [PATCH] Add post times --- next.config.ts | 12 ++- src/components/posts/index.tsx | 170 ++++++++++++++++++++++++++++--- src/components/streams/index.tsx | 7 +- src/types/PostSort.ts | 2 +- src/types/PostTimes.ts | 13 +++ 5 files changed, 188 insertions(+), 16 deletions(-) create mode 100644 src/types/PostTimes.ts diff --git a/next.config.ts b/next.config.ts index e9ffa30..c57540f 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,17 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "static-cdn.jtvnw.net", + port: "", + pathname: "/**", + search: "", + }, + ], + }, }; export default nextConfig; diff --git a/src/components/posts/index.tsx b/src/components/posts/index.tsx index 0b05471..d4c1665 100644 --- a/src/components/posts/index.tsx +++ b/src/components/posts/index.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useState } from "react"; +import { ReactNode, useEffect, useState } from "react"; import PostCard from "./PostCard"; import { PostType } from "@/types/PostType"; import { @@ -14,12 +14,31 @@ import { PostSort } from "@/types/PostSort"; import { PostStyle } from "@/types/PostStyle"; import { getCookie } from "@/helpers/cookie"; import { UserType } from "@/types/UserType"; -import { LoaderCircle } from "lucide-react"; +import { + Calendar, + Calendar1, + CalendarArrowDown, + CalendarCog, + CalendarDays, + CalendarFold, + CalendarRange, + Clock1, + Clock2, + Clock3, + Clock4, + ClockArrowDown, + ClockArrowUp, + LoaderCircle, + Sparkles, + Trophy, +} from "lucide-react"; import { toast } from "react-toastify"; +import { PostTime } from "@/types/PostTimes"; export default function Posts() { const [posts, setPosts] = useState<PostType[]>(); const [sort, setSort] = useState<PostSort>("newest"); + const [time, setTime] = useState<PostTime>("all"); const [style, setStyle] = useState<PostStyle>("cozy"); const [user, setUser] = useState<UserType>(); const [loading, setLoading] = useState<boolean>(true); @@ -45,8 +64,8 @@ export default function Posts() { // Fetch posts with userSlug if user is available const postsResponse = await fetch( process.env.NEXT_PUBLIC_MODE === "PROD" - ? `https://d2jam.com/api/v1/posts?sort=${sort}&user=${userData.slug}` - : `http://localhost:3005/api/v1/posts?sort=${sort}&user=${userData.slug}` + ? `https://d2jam.com/api/v1/posts?sort=${sort}&user=${userData.slug}&time=${time}` + : `http://localhost:3005/api/v1/posts?sort=${sort}&user=${userData.slug}&time=${time}` ); setPosts(await postsResponse.json()); setLoading(false); @@ -56,8 +75,8 @@ export default function Posts() { // Fetch posts without userSlug if user is not available const postsResponse = await fetch( process.env.NEXT_PUBLIC_MODE === "PROD" - ? `https://d2jam.com/api/v1/posts?sort=${sort}` - : `http://localhost:3005/api/v1/posts?sort=${sort}` + ? `https://d2jam.com/api/v1/posts?sort=${sort}&time=${time}` + : `http://localhost:3005/api/v1/posts?sort=${sort}&time=${time}` ); setPosts(await postsResponse.json()); setLoading(false); @@ -65,7 +84,94 @@ export default function Posts() { }; loadUserAndPosts(); - }, [sort]); + }, [sort, time]); + + const sorts: Record< + PostSort, + { name: string; icon: ReactNode; description: string } + > = { + top: { + name: "Top", + icon: <Trophy />, + description: "Shows the most liked posts first", + }, + newest: { + name: "Newest", + icon: <ClockArrowUp />, + description: "Shows the newest posts first", + }, + oldest: { + name: "Oldest", + icon: <ClockArrowDown />, + description: "Shows the oldest posts first", + }, + }; + + const times: Record< + PostTime, + { name: string; icon: ReactNode; description: string } + > = { + hour: { + name: "Hour", + icon: <Clock1 />, + description: "Shows posts from the last hour", + }, + three_hours: { + name: "Three Hours", + icon: <Clock2 />, + description: "Shows posts from the last three hours", + }, + six_hours: { + name: "Six Hours", + icon: <Clock3 />, + description: "Shows posts from the last six hours", + }, + twelve_hours: { + name: "Twelve Hours", + icon: <Clock4 />, + description: "Shows posts from the last twelve hours", + }, + day: { + name: "Day", + icon: <Calendar />, + description: "Shows posts from the last day", + }, + week: { + name: "Week", + icon: <CalendarDays />, + description: "Shows posts from the last week", + }, + month: { + name: "Month", + icon: <CalendarRange />, + description: "Shows posts from the last month", + }, + three_months: { + name: "Three Months", + icon: <CalendarFold />, + description: "Shows posts from the last three months", + }, + six_months: { + name: "Six Months", + icon: <CalendarCog />, + description: "Shows posts from the last six months", + }, + nine_months: { + name: "Nine Months", + icon: <CalendarArrowDown />, + description: "Shows posts from the last nine months", + }, + year: { + name: "Year", + icon: <Calendar1 />, + description: "Shows posts from the last year", + }, + all: { + name: "All Times", + icon: <Sparkles />, + description: "Shows all posts", + }, + }; return ( <div> @@ -78,7 +184,7 @@ export default function Posts() { className="text-xs bg-white dark:bg-[#252525] !duration-250 !ease-linear !transition-all text-[#333] dark:text-white" variant="faded" > - {sort.charAt(0).toUpperCase() + sort.slice(1)} + {sorts[sort]?.name} </Button> </DropdownTrigger> <DropdownMenu @@ -87,9 +193,42 @@ export default function Posts() { }} className="text-[#333] dark:text-white" > - <DropdownItem key="newest">Newest</DropdownItem> - <DropdownItem key="top">Top</DropdownItem> - <DropdownItem key="oldest">Oldest</DropdownItem> + {Object.entries(sorts).map(([key, sort]) => ( + <DropdownItem + key={key} + startContent={sort.icon} + description={sort.description} + > + {sort.name} + </DropdownItem> + ))} + </DropdownMenu> + </Dropdown> + <Dropdown> + <DropdownTrigger> + <Button + size="sm" + className="text-xs bg-white dark:bg-[#252525] !duration-250 !ease-linear !transition-all text-[#333] dark:text-white" + variant="faded" + > + {times[time]?.name} + </Button> + </DropdownTrigger> + <DropdownMenu + onAction={(key) => { + setTime(key as PostTime); + }} + className="text-[#333] dark:text-white" + > + {Object.entries(times).map(([key, sort]) => ( + <DropdownItem + key={key} + startContent={sort.icon} + description={sort.description} + > + {sort.name} + </DropdownItem> + ))} </DropdownMenu> </Dropdown> <Button @@ -138,10 +277,15 @@ export default function Posts() { </div> ) : ( <div className="flex flex-col gap-3 p-4"> - {posts && + {posts && posts.length > 0 ? ( posts.map((post) => ( <PostCard key={post.id} post={post} style={style} user={user} /> - ))} + )) + ) : ( + <p className="text-center text-[#333] dark:text-white transition-color duration-250 ease-linear"> + No posts match your filters + </p> + )} </div> )} </div> diff --git a/src/components/streams/index.tsx b/src/components/streams/index.tsx index 9029056..5d51fc4 100644 --- a/src/components/streams/index.tsx +++ b/src/components/streams/index.tsx @@ -2,6 +2,8 @@ import { useEffect, useState } from "react"; import { FeaturedStreamerType } from "@/types/FeaturedStreamerType"; +import { Image } from "@nextui-org/react"; +import NextImage from "next/image"; export default function Streams() { const [streamers, setStreamers] = useState<FeaturedStreamerType[]>([]); @@ -64,10 +66,13 @@ export default function Streams() { margin: "0 auto", }} > - <img + <Image + as={NextImage} src={currentStreamer.thumbnailUrl} alt={`${currentStreamer.userName}'s thumbnail`} style={{ width: "100%", borderRadius: "4px", marginBottom: "10px" }} + width={320} + height={180} /> <a href={`https://twitch.tv/${currentStreamer.userName}`} diff --git a/src/types/PostSort.ts b/src/types/PostSort.ts index ac07621..22c0a2e 100644 --- a/src/types/PostSort.ts +++ b/src/types/PostSort.ts @@ -1 +1 @@ -export type PostSort = "newest" | "oldest"; +export type PostSort = "newest" | "oldest" | "top"; diff --git a/src/types/PostTimes.ts b/src/types/PostTimes.ts new file mode 100644 index 0000000..d228d72 --- /dev/null +++ b/src/types/PostTimes.ts @@ -0,0 +1,13 @@ +export type PostTime = + | "hour" + | "three_hours" + | "six_hours" + | "twelve_hours" + | "day" + | "week" + | "month" + | "three_months" + | "six_months" + | "nine_months" + | "year" + | "all";