mirror of
https://github.com/lukevella/rallly.git
synced 2025-07-04 18:17:25 +02:00
Update
This commit is contained in:
parent
8e778a40ec
commit
dc9940b390
5 changed files with 77 additions and 39 deletions
|
@ -278,7 +278,8 @@
|
||||||
"1month": "1 month",
|
"1month": "1 month",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
"cancelAnytime": "Cancel anytime from your <a>billing page</a>.",
|
"cancelAnytime": "Cancel anytime from your <a>billing page</a>.",
|
||||||
"copiedToClipboard": "Copied to clipboard",
|
|
||||||
"viewAll": "View All",
|
"viewAll": "View All",
|
||||||
"pending": "Pending"
|
"pending": "Pending",
|
||||||
|
"copyLink": "Copy link",
|
||||||
|
"viewResults": "View results"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { PollStatus } from "@rallly/database";
|
import { PollStatus } from "@rallly/database";
|
||||||
import { RadioCards, RadioCardsItem } from "@rallly/ui/radio-pills";
|
import { RadioCards, RadioCardsItem } from "@rallly/ui/radio-pills";
|
||||||
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
|
||||||
import { CalendarPlusIcon } from "lucide-react";
|
import { CalendarPlusIcon } from "lucide-react";
|
||||||
import { useSearchParams } from "next/navigation";
|
import { useSearchParams } from "next/navigation";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
@ -29,6 +28,7 @@ function FilteredPolls({ status }: { status: PollStatus }) {
|
||||||
limit: 30,
|
limit: 30,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
suspense: true,
|
||||||
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
||||||
keepPreviousData: true,
|
keepPreviousData: true,
|
||||||
},
|
},
|
||||||
|
@ -59,7 +59,7 @@ function FilteredPolls({ status }: { status: PollStatus }) {
|
||||||
<ol className="space-y-4">
|
<ol className="space-y-4">
|
||||||
{data.pages.map((page, i) => (
|
{data.pages.map((page, i) => (
|
||||||
<li key={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) => (
|
{page.polls.map((poll) => (
|
||||||
<GroupPollCard
|
<GroupPollCard
|
||||||
key={poll.id}
|
key={poll.id}
|
||||||
|
@ -93,7 +93,9 @@ function PollStatusMenu({
|
||||||
onStatusChange?: (status: PollStatus) => void;
|
onStatusChange?: (status: PollStatus) => void;
|
||||||
}) {
|
}) {
|
||||||
const { data: countByStatus, isFetching } =
|
const { data: countByStatus, isFetching } =
|
||||||
trpc.polls.getCountByStatus.useQuery();
|
trpc.polls.getCountByStatus.useQuery(undefined, {
|
||||||
|
suspense: true,
|
||||||
|
});
|
||||||
|
|
||||||
if (!countByStatus) {
|
if (!countByStatus) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export function GridCardFooter({ children }: React.PropsWithChildren) {
|
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) {
|
export function GridCardHeader({ children }: React.PropsWithChildren) {
|
||||||
|
@ -8,6 +8,6 @@ export function GridCardHeader({ children }: React.PropsWithChildren) {
|
||||||
|
|
||||||
export const GridCard = ({ children }: { children: React.ReactNode }) => {
|
export const GridCard = ({ children }: { children: React.ReactNode }) => {
|
||||||
return (
|
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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,16 +2,17 @@
|
||||||
|
|
||||||
import { PollStatus } from "@rallly/database";
|
import { PollStatus } from "@rallly/database";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import { useToast } from "@rallly/ui/hooks/use-toast";
|
|
||||||
import { Icon } from "@rallly/ui/icon";
|
import { Icon } from "@rallly/ui/icon";
|
||||||
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@rallly/ui/tooltip";
|
||||||
import {
|
import {
|
||||||
BarChart2Icon,
|
BarChart2Icon,
|
||||||
CalendarIcon,
|
CalendarIcon,
|
||||||
|
CheckIcon,
|
||||||
Link2Icon,
|
Link2Icon,
|
||||||
User2Icon,
|
User2Icon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useTranslation } from "react-i18next";
|
import React from "react";
|
||||||
import { useCopyToClipboard } from "react-use";
|
import { useCopyToClipboard } from "react-use";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -26,6 +27,45 @@ import { Trans } from "@/components/trans";
|
||||||
import { useLocalizeTime } from "@/utils/dayjs";
|
import { useLocalizeTime } from "@/utils/dayjs";
|
||||||
import { getRange } from "@/utils/get-range";
|
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({
|
export function GroupPollCard({
|
||||||
status,
|
status,
|
||||||
pollId,
|
pollId,
|
||||||
|
@ -45,10 +85,6 @@ export function GroupPollCard({
|
||||||
}) {
|
}) {
|
||||||
const localizeTime = useLocalizeTime();
|
const localizeTime = useLocalizeTime();
|
||||||
|
|
||||||
const { t } = useTranslation("app");
|
|
||||||
const [, copy] = useCopyToClipboard();
|
|
||||||
const { toast } = useToast();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GridCard key={pollId}>
|
<GridCard key={pollId}>
|
||||||
<GridCardHeader>
|
<GridCardHeader>
|
||||||
|
@ -56,7 +92,10 @@ export function GroupPollCard({
|
||||||
<GroupPollIcon size="xs" />
|
<GroupPollIcon size="xs" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="truncate font-medium">
|
<h3 className="truncate font-medium">
|
||||||
<Link className="focus:underline" href={`/poll/${pollId}`}>
|
<Link
|
||||||
|
className="hover:underline focus:text-gray-900"
|
||||||
|
href={`/poll/${pollId}`}
|
||||||
|
>
|
||||||
{title}
|
{title}
|
||||||
</Link>
|
</Link>
|
||||||
</h3>
|
</h3>
|
||||||
|
@ -82,22 +121,10 @@ export function GroupPollCard({
|
||||||
</Pill>
|
</Pill>
|
||||||
</PillList>
|
</PillList>
|
||||||
<GridCardFooter>
|
<GridCardFooter>
|
||||||
<Button
|
<div className="flex justify-end gap-1">
|
||||||
variant="ghost"
|
<CopyLinkButton link={inviteLink} />
|
||||||
onClick={() => {
|
<Tooltip>
|
||||||
copy(inviteLink);
|
<TooltipTrigger asChild>
|
||||||
toast({
|
|
||||||
title: t("copiedToClipboard", {
|
|
||||||
ns: "app",
|
|
||||||
defaultValue: "Copied to clipboard",
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon>
|
|
||||||
<Link2Icon />
|
|
||||||
</Icon>
|
|
||||||
</Button>
|
|
||||||
<Button variant="ghost" asChild>
|
<Button variant="ghost" asChild>
|
||||||
<Link href={`/poll/${pollId}`}>
|
<Link href={`/poll/${pollId}`}>
|
||||||
<Icon>
|
<Icon>
|
||||||
|
@ -105,6 +132,12 @@ export function GroupPollCard({
|
||||||
</Icon>
|
</Icon>
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<Trans i18nKey="viewResults" defaults="View results" />
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
</GridCardFooter>
|
</GridCardFooter>
|
||||||
</GridCard>
|
</GridCard>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,7 +9,7 @@ export function Heading({
|
||||||
return (
|
return (
|
||||||
<h1
|
<h1
|
||||||
className={cn(
|
className={cn(
|
||||||
"text-xl font-semibold text-gray-900",
|
"text-2xl font-semibold text-gray-900",
|
||||||
heading.className,
|
heading.className,
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
|
@ -24,6 +24,8 @@ export function Subheading({
|
||||||
className,
|
className,
|
||||||
}: React.PropsWithChildren<{ className?: string }>) {
|
}: React.PropsWithChildren<{ className?: string }>) {
|
||||||
return (
|
return (
|
||||||
<h2 className={cn("text-base font-semibold", className)}>{children}</h2>
|
<h2 className={cn("text-lg font-semibold text-gray-900", className)}>
|
||||||
|
{children}
|
||||||
|
</h2>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue