Skip to content

Commit

Permalink
✨ Add loading pages
Browse files Browse the repository at this point in the history
  • Loading branch information
lukevella committed Jan 13, 2024
1 parent a1bac0c commit 282615e
Show file tree
Hide file tree
Showing 14 changed files with 388 additions and 242 deletions.
53 changes: 53 additions & 0 deletions apps/web/src/app/[locale]/(admin)/polls/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Button } from "@rallly/ui/button";
import { PenBoxIcon } from "lucide-react";
import Link from "next/link";
import { Trans } from "react-i18next/TransWithoutContext";

import {
PageContainer,
PageContent,
PageHeader,
PageTitle,
} from "@/app/components/page-layout";
import { getTranslation } from "@/app/i18n";

export default async function Layout({
params,
children,
}: {
children: React.ReactNode;
params: { locale: string };
}) {
const { t } = await getTranslation(params.locale);
return (
<PageContainer>
<PageHeader>
<div className="flex justify-between items-center gap-x-4">
<PageTitle>
<Trans t={t} i18nKey="polls" />
</PageTitle>
<Button asChild>
<Link href="/new">
<PenBoxIcon className="w-4 text-muted-foreground h-4" />
<span className="hidden sm:inline">
<Trans t={t} i18nKey="newPoll" />
</span>
</Link>
</Button>
</div>
</PageHeader>
<PageContent>{children}</PageContent>
</PageContainer>
);
}

export async function generateMetadata({
params,
}: {
params: { locale: string };
}) {
const { t } = await getTranslation(params.locale);
return {
title: t("polls"),
};
}
31 changes: 31 additions & 0 deletions apps/web/src/app/[locale]/(admin)/polls/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Skeleton } from "@/components/skeleton";

function Row() {
return (
<div className="flex first:pt-0 py-4 items-center gap-x-4">
<div className="grow">
<Skeleton className="w-48 h-5 mb-2" />
<Skeleton className="w-24 h-4" />
</div>
<div className="pr-8">
<Skeleton className="w-24 h-4" />
</div>
<div className="pr-8">
<Skeleton className="w-24 h-4" />
</div>
<div className="pr-8">
<Skeleton className="w-12 h-4" />
</div>
</div>
);
}
export default async function Page() {
return (
<div className="divide-y divide-gray-100">
<Row />
<Row />
<Row />
<Row />
</div>
);
}
44 changes: 7 additions & 37 deletions apps/web/src/app/[locale]/(admin)/polls/page.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,14 @@
import { Button } from "@rallly/ui/button";
import { PenBoxIcon } from "lucide-react";
import Link from "next/link";
import { Trans } from "react-i18next/TransWithoutContext";

import {
PageContainer,
PageContent,
PageHeader,
PageTitle,
} from "@/app/components/page-layout";
import { getTranslation } from "@/app/i18n";

import { PollsList } from "./polls-list";

export default async function Page({ params }: { params: { locale: string } }) {
const { t } = await getTranslation(params.locale);
return (
<PageContainer>
<PageHeader>
<div className="flex justify-between items-center gap-x-4">
<PageTitle>
<Trans t={t} i18nKey="polls" />
</PageTitle>
<Button asChild>
<Link href="/new">
<PenBoxIcon className="w-4 text-muted-foreground h-4" />
<span className="hidden sm:inline">
<Trans t={t} i18nKey="newPoll" />
</span>
</Link>
</Button>
</div>
</PageHeader>
<PageContent>
<div className="space-y-6">
<PollsList />
</div>
</PageContent>
</PageContainer>
);
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

export default async function Page() {
await sleep(1000);
return <PollsList />;
}

export async function generateMetadata({
Expand Down
5 changes: 4 additions & 1 deletion apps/web/src/app/[locale]/(admin)/polls/polls-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,10 @@ export function PollsList() {
[adjustTimeZone],
);

if (!data) return null;
if (!data) {
// return a table using <Skeleton /> components
return null;
}

if (data.total === 0) return <EmptyState />;

Expand Down
104 changes: 104 additions & 0 deletions apps/web/src/app/[locale]/invite/[urlId]/invite-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"use client";
import { Button } from "@rallly/ui/button";
import { ArrowUpLeftIcon } from "lucide-react";
import Head from "next/head";
import Link from "next/link";
import { useParams, useSearchParams } from "next/navigation";
import React from "react";

import { PageHeader } from "@/app/components/page-layout";
import { Poll } from "@/components/poll";
import { LegacyPollContextProvider } from "@/components/poll/poll-context-provider";
import { Trans } from "@/components/trans";
import { UserDropdown } from "@/components/user-dropdown";
import { useUser } from "@/components/user-provider";
import { VisibilityProvider } from "@/components/visibility";
import { PermissionsContext } from "@/contexts/permissions";
import { usePoll } from "@/contexts/poll";
import { trpc } from "@/utils/trpc/client";

const Prefetch = ({ children }: React.PropsWithChildren) => {
const searchParams = useSearchParams();
const token = searchParams?.get("token") as string;
const params = useParams<{ urlId: string }>();
const urlId = params?.urlId as string;
const { data: permission } = trpc.auth.getUserPermission.useQuery(
{ token },
{
enabled: !!token,
},
);

const { data: poll, error } = trpc.polls.get.useQuery(
{ urlId },
{
retry: false,
},
);

const { data: participants } = trpc.polls.participants.list.useQuery({
pollId: urlId,
});

if (error?.data?.code === "NOT_FOUND") {
return <div>Not found</div>;
}
if (!poll || !participants) {
return null;
}

return (
<PermissionsContext.Provider value={{ userId: permission?.userId ?? null }}>
<Head>
<title>{poll.title}</title>
</Head>
{children}
</PermissionsContext.Provider>
);
};

const GoToApp = () => {
const poll = usePoll();
const { user } = useUser();

return (
<PageHeader variant="ghost">
<div className="flex justify-between">
<div>
<Button
variant="ghost"
asChild
className={poll.userId !== user.id ? "hidden" : ""}
>
<Link href={`/poll/${poll.id}`}>
<ArrowUpLeftIcon className="h-4 w-4 text-muted-foreground" />
<Trans i18nKey="manage" />
</Link>
</Button>
</div>
<div>
<UserDropdown />
</div>
</div>
</PageHeader>
);
};

export function InvitePage() {
return (
<Prefetch>
<LegacyPollContextProvider>
<VisibilityProvider>
<GoToApp />
<div className="lg:px-6 lg:py-5 p-3">
<div className="max-w-4xl mx-auto">
<div className="-mx-1">
<Poll />
</div>
</div>
</div>
</VisibilityProvider>
</LegacyPollContextProvider>
</Prefetch>
);
}
66 changes: 0 additions & 66 deletions apps/web/src/app/[locale]/invite/[urlId]/layout.tsx

This file was deleted.

24 changes: 24 additions & 0 deletions apps/web/src/app/[locale]/invite/[urlId]/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {
PageContainer,
PageContent,
PageHeader,
} from "@/app/components/page-layout";
import { Skeleton } from "@/components/skeleton";

export default function Loading() {
return (
<PageContainer>
<PageHeader className="justify-end flex" variant="ghost">
<Skeleton className="w-32 h-9" />
</PageHeader>
<PageContent>
<div className="max-w-4xl mx-auto space-y-6">
<Skeleton className="h-72 w-full" />
<Skeleton className="h-96 w-full" />
<hr />
<Skeleton className="h-64 w-full" />
</div>
</PageContent>
</PageContainer>
);
}
37 changes: 37 additions & 0 deletions apps/web/src/app/[locale]/invite/[urlId]/nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use client";
import { Button } from "@rallly/ui/button";
import { ArrowUpLeftIcon } from "lucide-react";
import Link from "next/link";

import { PageHeader } from "@/app/components/page-layout";
import { Trans } from "@/components/trans";
import { UserDropdown } from "@/components/user-dropdown";
import { useUser } from "@/components/user-provider";
import { usePoll } from "@/contexts/poll";

export const Nav = () => {
const poll = usePoll();
const { user } = useUser();

return (
<PageHeader variant="ghost">
<div className="flex justify-between">
<div>
<Button
variant="ghost"
asChild
className={poll.userId !== user.id ? "hidden" : ""}
>
<Link href={`/poll/${poll.id}`}>
<ArrowUpLeftIcon className="h-4 w-4 text-muted-foreground" />
<Trans i18nKey="manage" />
</Link>
</Button>
</div>
<div>
<UserDropdown />
</div>
</div>
</PageHeader>
);
};
Loading

0 comments on commit 282615e

Please sign in to comment.