refactor(web): replace preloadQuery with fetchQuery

This commit is contained in:
Aman Varshney
2025-08-29 16:28:14 +05:30
parent 11fd8eddcb
commit 33a08d6791
8 changed files with 82 additions and 65 deletions

View File

@@ -1,5 +1,12 @@
"use client";
import { Check, ChevronDown, ChevronRight, Copy, Terminal } from "lucide-react";
import {
Check,
ChevronDown,
ChevronRight,
Copy,
Terminal,
Zap,
} from "lucide-react";
import Link from "next/link";
import { useState } from "react";
import {
@@ -28,7 +35,7 @@ export default function CommandSection() {
};
return (
<div className="mb-8 grid grid-cols-1 gap-4 lg:grid-cols-2">
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
<div className="flex h-full flex-col justify-between rounded border border-border p-4">
<div className="mb-4 flex items-center justify-between">
<div className="flex items-center gap-2">
@@ -104,7 +111,7 @@ export default function CommandSection() {
<div className="space-y-3">
<div className="flex items-center justify-between rounded border border-border p-3">
<div className="flex items-center gap-2 text-sm">
<span className="text-primary"></span>
<Zap className="h-4 w-4 text-primary" />
<span className="text-foreground">
Interactive configuration wizard
</span>

View File

@@ -2,7 +2,7 @@ import NpmPackage from "./npm-package";
export default function HeroSection() {
return (
<>
<div>
<div className="mb-8 flex items-center justify-center">
<div className="flex flex-wrap items-center justify-center gap-2 sm:gap-4 md:gap-6">
<pre className="ascii-art text-primary text-xs leading-tight sm:text-sm">
@@ -47,15 +47,12 @@ export default function HeroSection() {
</div>
</div>
<div className="mb-6 text-center">
<div className="text-center">
<p className="mx-auto text-lg text-muted-foreground">
Modern CLI for scaffolding end-to-end type-safe TypeScript projects
</p>
<p className="mx-auto mt-2 max-w-2xl text-muted-foreground text-sm">
Production-ready Customizable Best practices included
</p>
<NpmPackage />
</div>
</>
</div>
);
}

View File

@@ -1,6 +1,4 @@
"use client";
import type { api } from "@better-t-stack/backend/convex/_generated/api";
import { type Preloaded, usePreloadedQuery } from "convex/react";
import {
ChevronDown,
ChevronUp,
@@ -26,17 +24,33 @@ import {
sortSponsors,
} from "@/lib/sponsor-utils";
export default function SponsorsSection({
preloadedSponsors,
}: {
preloadedSponsors: Preloaded<typeof api.sponsors.getSponsors>;
}) {
const sponsorsData = usePreloadedQuery(preloadedSponsors);
type SponsorEntry = {
sponsor: {
login: string;
name: string;
avatarUrl: string;
websiteUrl?: string;
linkUrl: string;
customLogoUrl?: string;
type: string;
};
isOneTime: boolean;
monthlyDollars: number;
privacyLevel: string;
tierName: string;
createdAt: string;
provider: string;
};
export default function SponsorsSection({
sponsors,
}: {
sponsors: Array<SponsorEntry>;
}) {
const [showPastSponsors, setShowPastSponsors] = useState(false);
const sponsors =
sponsorsData.map((sponsor) => ({
const sponsorsData =
sponsors.map((sponsor) => ({
...sponsor,
sponsor: {
...sponsor.sponsor,
@@ -44,16 +58,16 @@ export default function SponsorsSection({
},
})) || [];
const visibleSponsors = filterVisibleSponsors(sponsors);
const visibleSponsors = filterVisibleSponsors(sponsorsData);
const sortedSponsors = sortSponsors(visibleSponsors);
const currentSponsors = filterCurrentSponsors(sortedSponsors);
const pastSponsors = filterPastSponsors(sortSponsors(sponsors));
const pastSponsors = filterPastSponsors(sortSponsors(sponsorsData));
const specialSponsors = sortSpecialSponsors(
filterSpecialSponsors(currentSponsors),
);
return (
<div className="mb-12">
<div className="">
<div className="mb-6 flex flex-wrap items-center justify-between gap-2 sm:flex-nowrap">
<div className="flex items-center gap-2">
<Terminal className="h-5 w-5 text-primary" />

View File

@@ -33,7 +33,7 @@ export default function StatsSection({
const liveNpmDownloadCount = useNpmDownloadCounter(npmPackages);
return (
<div className="mb-8 grid grid-cols-1 gap-4 sm:mb-12 sm:grid-cols-2 lg:grid-cols-3">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
<Link href="/analytics">
<div className="cursor-pointer rounded border border-border p-4 transition-colors hover:bg-muted/10">
<div className="mb-3 flex items-center gap-2">

View File

@@ -1,7 +1,5 @@
"use client";
import type { api } from "@better-t-stack/backend/convex/_generated/api";
import { type Preloaded, usePreloadedQuery } from "convex/react";
import { Play, Terminal } from "lucide-react";
import { motion } from "motion/react";
import Image from "next/image";
@@ -99,14 +97,13 @@ const TweetCard = ({ tweetId, index }: { tweetId: string; index: number }) => (
);
export default function Testimonials({
preloadedTestimonialsTweet,
preloadedTestimonialsVideos,
videos,
tweets,
}: {
preloadedTestimonialsTweet: Preloaded<typeof api.testimonials.getTweets>;
preloadedTestimonialsVideos: Preloaded<typeof api.testimonials.getVideos>;
videos: Array<{ embedId: string; title: string }>;
tweets: Array<{ tweetId: string }>;
}) {
const videos = usePreloadedQuery(preloadedTestimonialsVideos).reverse();
const tweets = usePreloadedQuery(preloadedTestimonialsTweet);
const videosReversed = [...videos].reverse();
const getResponsiveColumns = (numCols: number) => {
const columns: string[][] = Array(numCols)
@@ -138,7 +135,7 @@ export default function Testimonials({
};
return (
<div className="mb-12 w-full max-w-full overflow-hidden px-4">
<div className="w-full max-w-full overflow-hidden px-4">
<div className="mb-8">
<div className="mb-6 flex flex-wrap items-center justify-between gap-2 sm:flex-nowrap">
<div className="flex items-center gap-2">
@@ -149,7 +146,7 @@ export default function Testimonials({
</div>
<div className="hidden h-px flex-1 bg-border sm:block" />
<span className="w-full text-right text-muted-foreground text-xs sm:w-auto sm:text-left">
[{videos.length} ENTRIES]
[{videosReversed.length} ENTRIES]
</span>
</div>
@@ -160,7 +157,7 @@ export default function Testimonials({
initial="hidden"
animate="visible"
>
{videos.map((video, index) => (
{videosReversed.map((video, index) => (
<VideoCard
key={`video-${video.embedId}`}
video={video}
@@ -177,7 +174,7 @@ export default function Testimonials({
initial="hidden"
animate="visible"
>
{videos.map((video, index) => (
{videosReversed.map((video, index) => (
<VideoCard
key={`video-${video.embedId}`}
video={video}

View File

@@ -1,5 +1,5 @@
import { api } from "@better-t-stack/backend/convex/_generated/api";
import { preloadQuery } from "convex/nextjs";
import { fetchQuery } from "convex/nextjs";
import CommandSection from "./_components/command-section";
import Footer from "./_components/footer";
import HeroSection from "./_components/hero-section";
@@ -8,13 +8,14 @@ import StatsSection from "./_components/stats-section";
import Testimonials from "./_components/testimonials";
export default async function HomePage() {
const preloadedSponsors = await preloadQuery(api.sponsors.getSponsors);
const preloadedTestimonialsTweet = await preloadQuery(
api.testimonials.getTweets,
);
const preloadedTestimonialsVideos = await preloadQuery(
api.testimonials.getVideos,
);
const sponsors = await fetchQuery(api.sponsors.getSponsors);
const fetchedTweets = await fetchQuery(api.testimonials.getTweets);
const fetchedVideos = await fetchQuery(api.testimonials.getVideos);
const videos = fetchedVideos.map((v) => ({
embedId: v.embedId,
title: v.title,
}));
const tweets = fetchedTweets.map((t) => ({ tweetId: t.tweetId }));
const minimalAnalytics = await fetch(
"https://r2.better-t-stack.dev/analytics-minimal.json",
@@ -23,18 +24,15 @@ export default async function HomePage() {
const minimalAnalyticsData = await minimalAnalytics.json();
return (
<div className="mx-auto min-h-svh max-w-[1280px]">
<main className="mx-auto px-4 pt-12">
<main className="mx-auto min-h-svh max-w-[1280px]">
<div className="mx-auto flex flex-col gap-8 px-4 pt-12">
<HeroSection />
<CommandSection />
<StatsSection analyticsData={minimalAnalyticsData} />
<SponsorsSection preloadedSponsors={preloadedSponsors} />
<Testimonials
preloadedTestimonialsTweet={preloadedTestimonialsTweet}
preloadedTestimonialsVideos={preloadedTestimonialsVideos}
/>
</main>
<SponsorsSection sponsors={sponsors} />
<Testimonials tweets={tweets} videos={videos} />
</div>
<Footer />
</div>
</main>
);
}

View File

@@ -1,18 +1,24 @@
"use client";
import type { api } from "@better-t-stack/backend/convex/_generated/api";
import { type Preloaded, usePreloadedQuery } from "convex/react";
import { Terminal } from "lucide-react";
import Footer from "../../_components/footer";
import ShowcaseItem from "../_components/ShowcaseItem";
export default function ShowcasePage({
preloadedShowcase,
}: {
preloadedShowcase: Preloaded<typeof api.showcase.getShowcaseProjects>;
}) {
const showcaseProjects = usePreloadedQuery(preloadedShowcase);
type ShowcaseProject = {
_id: string;
_creationTime: number;
title: string;
description: string;
imageUrl: string;
liveUrl: string;
tags: string[];
};
export default function ShowcasePage({
showcaseProjects,
}: {
showcaseProjects: Array<ShowcaseProject>;
}) {
return (
<main className="mx-auto min-h-svh max-w-[1280px]">
<div className="container mx-auto space-y-8 px-4 py-8 pt-16">

View File

@@ -1,10 +1,8 @@
import { api } from "@better-t-stack/backend/convex/_generated/api";
import { preloadQuery } from "convex/nextjs";
import { fetchQuery } from "convex/nextjs";
import ShowcasePage from "./_components/showcase-page";
export default async function Showcase() {
const preloadedShowcase = await preloadQuery(
api.showcase.getShowcaseProjects,
);
return <ShowcasePage preloadedShowcase={preloadedShowcase} />;
const showcaseProjects = await fetchQuery(api.showcase.getShowcaseProjects);
return <ShowcasePage showcaseProjects={showcaseProjects} />;
}