|
1 | | -// "use client" |
2 | | -// import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" |
3 | | -// import { ArrowLeft, Copy, Pen, RefreshCcw, Search, X } from "lucide-react" |
4 | | -// import Link from "next/link" |
5 | | -// import { useState } from "react" |
6 | | -// import { toast } from "sonner" |
7 | | -// import { Badge } from "@/components/ui/badge" |
8 | | -// import { Button } from "@/components/ui/button" |
9 | | -// import { Input } from "@/components/ui/input" |
10 | | -// import { Label } from "@/components/ui/label" |
11 | | -// import { useTRPC } from "@/server/trpc" |
12 | | -// import type { ApiOutput } from "@/server/trpc/types" |
13 | | -// |
14 | | -// type Groups = ApiOutput["tg"]["groups"]["search"]["groups"] |
15 | | -// |
16 | | -// export default function TgGroups() { |
17 | | -// const [query, setQuery] = useState("") |
18 | | -// |
19 | | -// const trpc = useTRPC() |
20 | | -// const qc = useQueryClient() |
21 | | -// const queryOpts = trpc.tg.groups.search.queryOptions({ query, limit: 20, showHidden: true }) |
22 | | -// const { data: allGroups, isLoading, refetch } = useQuery(trpc.tg.groups.getAll.queryOptions()) |
23 | | -// |
24 | | -// const [rows, setRows] = useState<Groups>(!isLoading ? (allGroups ?? []) : []) |
25 | | -// |
26 | | -// async function search() { |
27 | | -// const res = await qc.fetchQuery(queryOpts) |
28 | | -// setRows(res.groups) |
29 | | -// return res |
30 | | -// } |
31 | | -// |
32 | | -// async function invalidate() { |
33 | | -// await qc.invalidateQueries(queryOpts) |
34 | | -// refetch() |
35 | | -// await search() |
36 | | -// } |
37 | | -// |
38 | | -// async function submit(e: React.FormEvent<HTMLFormElement>) { |
39 | | -// e.preventDefault() |
40 | | -// |
41 | | -// const res = await search() |
42 | | -// if (res.count === 0) toast.warning("No groups found with this query") |
43 | | -// else toast.info(`Found ${res.count} groups`) |
44 | | -// } |
45 | | -// |
46 | | -// function reset() { |
47 | | -// setRows(allGroups ?? []) |
48 | | -// setQuery("") |
49 | | -// } |
50 | | -// |
51 | | -// return ( |
52 | | -// <div className="container p-8"> |
53 | | -// <Link href="/dashboard/telegram" className="flex gap-1 items-center text-muted-foreground mb-2 hover:underline"> |
54 | | -// <ArrowLeft size={16} /> Back |
55 | | -// </Link> |
56 | | -// <form onSubmit={submit} className="pt-2 gap-y-4 flex flex-col justify-start items-start"> |
57 | | -// <div className="flex gap-2 flex-col items-start justify-start"> |
58 | | -// <Label htmlFor="email" className="text-base"> |
59 | | -// Search |
60 | | -// </Label> |
61 | | -// <div className="flex gap-2 items-center justify-start"> |
62 | | -// <Input |
63 | | -// id="group-query" |
64 | | -// type="text" |
65 | | -// placeholder="Group name" |
66 | | -// className="bg-card w-auto" |
67 | | -// required |
68 | | -// onChange={(e) => { |
69 | | -// setQuery(e.target.value) |
70 | | -// }} |
71 | | -// value={query} |
72 | | -// /> |
73 | | -// <Button type="submit" size="icon"> |
74 | | -// <Search /> |
75 | | -// </Button> |
76 | | -// {rows.length > 0 && ( |
77 | | -// <Button variant="outline" onClick={reset}> |
78 | | -// <X /> |
79 | | -// Reset |
80 | | -// </Button> |
81 | | -// )} |
82 | | -// <Button variant="outline" onClick={invalidate}> |
83 | | -// <RefreshCcw /> |
84 | | -// Refresh |
85 | | -// </Button> |
86 | | -// </div> |
87 | | -// <span className="text-muted-foreground text-xs">Max results: 20</span> |
88 | | -// </div> |
89 | | -// </form> |
90 | | -// <div className="flex flex-col w-full items-start justify-start py-4"> |
91 | | -// <div className="grid gap-4 items-center grid-cols-5 w-full border-b py-2"> |
92 | | -// <p>telegram ID</p> |
93 | | -// <p>Title</p> |
94 | | -// <p>Tag</p> |
95 | | -// <p>Invite Link</p> |
96 | | -// <p>Hide</p> |
97 | | -// </div> |
98 | | -// {rows.map((r) => ( |
99 | | -// <GroupRow row={r} key={r.telegramId} invalidate={invalidate} /> |
100 | | -// ))} |
101 | | -// </div> |
102 | | -// </div> |
103 | | -// ) |
104 | | -// } |
105 | | -// |
106 | | -// function GroupRow({ row: r, invalidate }: { row: Groups[number]; invalidate: () => void }) { |
107 | | -// const trpc = useTRPC() |
108 | | -// const { mutateAsync: hideMutate } = useMutation(trpc.tg.groups.setHide.mutationOptions()) |
109 | | -// |
110 | | -// async function toggleHide() { |
111 | | -// const ok = await hideMutate({ telegramId: r.telegramId, hide: !r.hide }).catch(() => false) |
112 | | -// if (!ok) toast.error("The field cannot be modified") |
113 | | -// |
114 | | -// toast.success("Hide option toggled!") |
115 | | -// invalidate() |
116 | | -// } |
117 | | -// |
118 | | -// return ( |
119 | | -// <div className="grid gap-4 items-center grid-cols-5 border-b py-2 w-full"> |
120 | | -// <p>{r.telegramId}</p> |
121 | | -// <p>{r.title}</p> |
122 | | -// <p className={r.tag ? "" : "text-muted-foreground italic"}>{r.tag ? `@${r.tag}` : `<unset>`}</p> |
123 | | -// <div className="flex items-center justify-start gap-2"> |
124 | | -// {r.link && ( |
125 | | -// <a |
126 | | -// href={r.link} |
127 | | -// target="_blank" |
128 | | -// rel="noopener noreferrer" |
129 | | -// aria-label={`Link for group ${r.title}`} |
130 | | -// className="hover:underline text-xs" |
131 | | -// > |
132 | | -// {r.link} |
133 | | -// </a> |
134 | | -// )} |
135 | | -// <Button |
136 | | -// type="button" |
137 | | -// variant="outline" |
138 | | -// size="icon-sm" |
139 | | -// className={!r.link ? "hidden" : ""} |
140 | | -// onClick={async () => { |
141 | | -// try { |
142 | | -// if (!r.link) return |
143 | | -// await navigator.clipboard.writeText(r.link) |
144 | | -// toast.success("Link copied to clipboard!") |
145 | | -// } catch (err) { |
146 | | -// toast.error("Cannot copy link to clipboard") |
147 | | -// console.error(err) |
148 | | -// } |
149 | | -// }} |
150 | | -// > |
151 | | -// <Copy /> |
152 | | -// </Button> |
153 | | -// </div> |
154 | | -// <div className="flex items-center justify-start gap-2"> |
155 | | -// <p>{r.hide ? <Badge className="bg-yellow-800">HIDDEN</Badge> : <Badge variant="secondary">Visibile</Badge>}</p> |
156 | | -// <Button type="button" variant="outline" size="icon-sm" className={!r.link ? "hidden" : ""} onClick={toggleHide}> |
157 | | -// <Pen /> |
158 | | -// </Button> |
159 | | -// </div> |
160 | | -// </div> |
161 | | -// ) |
162 | | -// } |
| 1 | +"use server" |
| 2 | +import { ArrowLeft } from "lucide-react" |
| 3 | +import Link from "next/link" |
| 4 | +import { trpc } from "@/server/trpc" |
| 5 | +import { GroupRow } from "./group-row" |
| 6 | +import { SearchInput } from "./search-input" |
| 7 | + |
| 8 | +export default async function TgGroups({ searchParams }: { searchParams: Promise<{ q?: string }> }) { |
| 9 | + const { q } = await searchParams |
| 10 | + |
| 11 | + const all = await trpc.tg.groups.getAll.query() |
| 12 | + const rows = q ? (await trpc.tg.groups.search.query({ limit: 20, query: q, showHidden: true })).groups : all |
| 13 | + |
| 14 | + return ( |
| 15 | + <div className="container p-8"> |
| 16 | + <Link href="/dashboard/telegram" className="flex gap-1 items-center text-muted-foreground mb-2 hover:underline"> |
| 17 | + <ArrowLeft size={16} /> Back |
| 18 | + </Link> |
| 19 | + <SearchInput /> |
| 20 | + <div className="flex flex-col w-full items-start justify-start py-4"> |
| 21 | + <div className="grid gap-4 items-center grid-cols-5 w-full border-b py-2"> |
| 22 | + <p>telegram ID</p> |
| 23 | + <p>Title</p> |
| 24 | + <p>Tag</p> |
| 25 | + <p>Invite Link</p> |
| 26 | + <p>Hide</p> |
| 27 | + </div> |
| 28 | + {rows.map((r) => ( |
| 29 | + <GroupRow row={r} key={r.telegramId} /> |
| 30 | + ))} |
| 31 | + </div> |
| 32 | + </div> |
| 33 | + ) |
| 34 | +} |
0 commit comments