This commit is contained in:
Luke Vella 2024-09-28 22:53:39 +01:00
parent 8e778a40ec
commit dc9940b390
No known key found for this signature in database
GPG key ID: 469CAD687F0D784C
5 changed files with 77 additions and 39 deletions

View file

@ -278,7 +278,8 @@
"1month": "1 month",
"subscribe": "Subscribe",
"cancelAnytime": "Cancel anytime from your <a>billing page</a>.",
"copiedToClipboard": "Copied to clipboard",
"viewAll": "View All",
"pending": "Pending"
"pending": "Pending",
"copyLink": "Copy link",
"viewResults": "View results"
}

View file

@ -1,7 +1,6 @@
"use client";
import { PollStatus } from "@rallly/database";
import { RadioCards, RadioCardsItem } from "@rallly/ui/radio-pills";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { CalendarPlusIcon } from "lucide-react";
import { useSearchParams } from "next/navigation";
import { z } from "zod";
@ -29,6 +28,7 @@ function FilteredPolls({ status }: { status: PollStatus }) {
limit: 30,
},
{
suspense: true,
getNextPageParam: (lastPage) => lastPage.nextCursor,
keepPreviousData: true,
},
@ -59,7 +59,7 @@ function FilteredPolls({ status }: { status: PollStatus }) {
<ol className="space-y-4">
{data.pages.map((page, i) => (
<li key={i}>
<div className="grid gap-3 sm:gap-4 md:grid-cols-3">
<div className="grid gap-4 md:grid-cols-3">
{page.polls.map((poll) => (
<GroupPollCard
key={poll.id}
@ -93,7 +93,9 @@ function PollStatusMenu({
onStatusChange?: (status: PollStatus) => void;
}) {
const { data: countByStatus, isFetching } =
trpc.polls.getCountByStatus.useQuery();
trpc.polls.getCountByStatus.useQuery(undefined, {
suspense: true,
});
if (!countByStatus) {
return null;

View file

@ -1,5 +1,5 @@
export function GridCardFooter({ children }: React.PropsWithChildren) {
return <div className="relative z-10 mt-6 flex gap-1">{children}</div>;
return <div className="relative z-10 mt-6">{children}</div>;
}
export function GridCardHeader({ children }: React.PropsWithChildren) {
@ -8,6 +8,6 @@ export function GridCardHeader({ children }: React.PropsWithChildren) {
export const GridCard = ({ children }: { children: React.ReactNode }) => {
return (
<div className="relative rounded-lg border bg-white p-4">{children}</div>
<div className="relative rounded-xl border bg-white p-4">{children}</div>
);
};

View file

@ -2,16 +2,17 @@
import { PollStatus } from "@rallly/database";
import { Button } from "@rallly/ui/button";
import { useToast } from "@rallly/ui/hooks/use-toast";
import { Icon } from "@rallly/ui/icon";
import { Tooltip, TooltipContent, TooltipTrigger } from "@rallly/ui/tooltip";
import {
BarChart2Icon,
CalendarIcon,
CheckIcon,
Link2Icon,
User2Icon,
} from "lucide-react";
import Link from "next/link";
import { useTranslation } from "react-i18next";
import React from "react";
import { useCopyToClipboard } from "react-use";
import {
@ -26,6 +27,45 @@ import { Trans } from "@/components/trans";
import { useLocalizeTime } from "@/utils/dayjs";
import { getRange } from "@/utils/get-range";
function CopyLinkButton({ link, ...forwardProps }: { link: string }) {
const [, copy] = useCopyToClipboard();
const [isCopied, setIsCopied] = React.useState(false);
return (
<Tooltip open={isCopied ? true : undefined}>
<TooltipTrigger asChild>
<Button
{...forwardProps}
variant="ghost"
onClick={() => {
copy(link);
React.startTransition(() => {
setIsCopied(true);
});
setTimeout(() => {
setIsCopied(false);
}, 2000);
}}
>
<Icon>
<Link2Icon />
</Icon>
</Button>
</TooltipTrigger>
<TooltipContent>
{isCopied ? (
<p>
<CheckIcon className="mr-2 inline-block size-4 text-green-500" />
<Trans i18nKey="copied" defaults="Copied" />
</p>
) : (
<Trans i18nKey="copyLink" defaults="Copy link" />
)}
</TooltipContent>
</Tooltip>
);
}
export function GroupPollCard({
status,
pollId,
@ -45,10 +85,6 @@ export function GroupPollCard({
}) {
const localizeTime = useLocalizeTime();
const { t } = useTranslation("app");
const [, copy] = useCopyToClipboard();
const { toast } = useToast();
return (
<GridCard key={pollId}>
<GridCardHeader>
@ -56,7 +92,10 @@ export function GroupPollCard({
<GroupPollIcon size="xs" />
</div>
<h3 className="truncate font-medium">
<Link className="focus:underline" href={`/poll/${pollId}`}>
<Link
className="hover:underline focus:text-gray-900"
href={`/poll/${pollId}`}
>
{title}
</Link>
</h3>
@ -82,29 +121,23 @@ export function GroupPollCard({
</Pill>
</PillList>
<GridCardFooter>
<Button
variant="ghost"
onClick={() => {
copy(inviteLink);
toast({
title: t("copiedToClipboard", {
ns: "app",
defaultValue: "Copied to clipboard",
}),
});
}}
>
<Icon>
<Link2Icon />
</Icon>
</Button>
<Button variant="ghost" asChild>
<Link href={`/poll/${pollId}`}>
<Icon>
<BarChart2Icon />
</Icon>
</Link>
</Button>
<div className="flex justify-end gap-1">
<CopyLinkButton link={inviteLink} />
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" asChild>
<Link href={`/poll/${pollId}`}>
<Icon>
<BarChart2Icon />
</Icon>
</Link>
</Button>
</TooltipTrigger>
<TooltipContent>
<Trans i18nKey="viewResults" defaults="View results" />
</TooltipContent>
</Tooltip>
</div>
</GridCardFooter>
</GridCard>
);

View file

@ -9,7 +9,7 @@ export function Heading({
return (
<h1
className={cn(
"text-xl font-semibold text-gray-900",
"text-2xl font-semibold text-gray-900",
heading.className,
className,
)}
@ -24,6 +24,8 @@ export function Subheading({
className,
}: React.PropsWithChildren<{ className?: string }>) {
return (
<h2 className={cn("text-base font-semibold", className)}>{children}</h2>
<h2 className={cn("text-lg font-semibold text-gray-900", className)}>
{children}
</h2>
);
}