|
1 | 1 | "use client" |
2 | 2 | import { useQuery, useQueryClient } from "@tanstack/react-query" |
3 | | -import { ArrowLeft, ExternalLinkIcon, Search, Star, X } from "lucide-react" |
| 3 | +import { ArrowLeft, Search, X } from "lucide-react" |
4 | 4 | import Link from "next/link" |
5 | 5 | import { useState } from "react" |
6 | 6 | import { toast } from "sonner" |
7 | | -import { Code } from "@/components/code" |
8 | | -import { Badge } from "@/components/ui/badge" |
9 | 7 | import { Button } from "@/components/ui/button" |
10 | | -import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" |
11 | 8 | import { Input } from "@/components/ui/input" |
12 | 9 | import { Label } from "@/components/ui/label" |
13 | | -import { useSession } from "@/lib/auth" |
14 | 10 | import { useTRPC } from "@/lib/trpc/client" |
15 | 11 | import type { ApiOutput } from "@/lib/trpc/types" |
16 | | -import { fmtUser, stripChatId } from "@/lib/utils/telegram" |
17 | | -import { AddRole } from "./add-role" |
18 | | -import { DeleteGroupAdmin } from "./delete-group-admin" |
| 12 | +import { AuditLogCard } from "./card-audit-log" |
| 13 | +import { GroupAdminCard } from "./card-group-admin" |
| 14 | +import { MessageCard } from "./card-message" |
| 15 | +import { UserInfoCard } from "./card-user-info" |
19 | 16 | import { NewGroupAdmin } from "./new-group-admin" |
20 | | -import { RemoveRole } from "./remove-role" |
21 | 17 |
|
22 | 18 | type User = ApiOutput["tg"]["users"]["getByUsername"]["user"] |
23 | 19 |
|
@@ -137,149 +133,3 @@ export default function TgUsers() { |
137 | 133 | </div> |
138 | 134 | ) |
139 | 135 | } |
140 | | - |
141 | | -type UserRoles = ApiOutput["tg"]["permissions"]["getRoles"]["roles"] |
142 | | -function UserInfoCard({ user, roles }: { user: NonNullable<User>; roles: UserRoles }) { |
143 | | - const sesh = useSession() |
144 | | - const seshUserId = sesh.data?.user.telegramId |
145 | | - const isSelf = seshUserId && seshUserId === user.id |
146 | | - |
147 | | - return ( |
148 | | - <Card className="w-fit min-w-120"> |
149 | | - <CardHeader> |
150 | | - <CardTitle> |
151 | | - User ID: {user.id}{" "} |
152 | | - {isSelf && ( |
153 | | - <Badge> |
154 | | - <Star /> You |
155 | | - </Badge> |
156 | | - )} |
157 | | - </CardTitle> |
158 | | - </CardHeader> |
159 | | - <CardContent className="space-y-2"> |
160 | | - <p> |
161 | | - <span className="text-muted-foreground">Name: </span> |
162 | | - {user.firstName} {user.lastName ?? ""} |
163 | | - </p> |
164 | | - <p> |
165 | | - <span className="text-muted-foreground">Username: </span> |
166 | | - {user.username} |
167 | | - </p> |
168 | | - <div className="flex items-center gap-2"> |
169 | | - <span className="text-muted-foreground">Roles: </span> |
170 | | - {roles ? roles.map((r) => <Badge key={r}>{r}</Badge>) : "N/A"} |
171 | | - </div> |
172 | | - </CardContent> |
173 | | - <CardFooter className="gap-2"> |
174 | | - <AddRole alreadyRoles={roles ?? []} user={user} /> |
175 | | - <RemoveRole alreadyRoles={roles ?? []} user={user} /> |
176 | | - </CardFooter> |
177 | | - </Card> |
178 | | - ) |
179 | | -} |
180 | | - |
181 | | -type GroupAdminSingle = NonNullable<ApiOutput["tg"]["permissions"]["getRoles"]["groupAdmin"][number]> |
182 | | -function GroupAdminCard({ user, groupAdminInfo: m }: { user: NonNullable<User>; groupAdminInfo: GroupAdminSingle }) { |
183 | | - return ( |
184 | | - <Card> |
185 | | - <CardHeader> |
186 | | - <CardTitle>{m.group.title}</CardTitle> |
187 | | - </CardHeader> |
188 | | - <CardContent className="space-y-2"> |
189 | | - <p> |
190 | | - <span className="text-muted-foreground">Chat ID: </span> |
191 | | - <Code copyOnClick>{m.group.id}</Code> / <Code copyOnClick>{stripChatId(m.group.id)}</Code> |
192 | | - </p> |
193 | | - <p> |
194 | | - <span className="text-muted-foreground">Added By: </span> |
195 | | - {m.addedBy.firstName} {m.addedBy.username ? `@${m.addedBy.username}` : ""} |
196 | | - </p> |
197 | | - </CardContent> |
198 | | - <CardFooter className="justify-end gap-2"> |
199 | | - <DeleteGroupAdmin userId={user.id} chatId={m.group.id} /> |
200 | | - </CardFooter> |
201 | | - </Card> |
202 | | - ) |
203 | | -} |
204 | | - |
205 | | -type Message = NonNullable<ApiOutput["tg"]["messages"]["getLastByUser"]["messages"]>[number] |
206 | | -function MessageCard({ message: m }: { message: Message }) { |
207 | | - return ( |
208 | | - <Card> |
209 | | - <CardContent className="space-y-1"> |
210 | | - <p> |
211 | | - <span className="text-muted-foreground">Chat: </span> |
212 | | - {m.group && <span>{m.group.title}</span>} [{m.chatId}] |
213 | | - </p> |
214 | | - <p> |
215 | | - <span className="text-muted-foreground">Message ID: </span> |
216 | | - {m.messageId} |
217 | | - </p> |
218 | | - <p> |
219 | | - <span className="text-muted-foreground">Timestamp: </span> |
220 | | - {m.timestamp.toLocaleString()} |
221 | | - </p> |
222 | | - <span className="text-muted-foreground">Content:</span> |
223 | | - <p className="pl-3">{m.message}</p> |
224 | | - </CardContent> |
225 | | - <CardFooter className="justify-end gap-2"> |
226 | | - {m.group?.inviteLink && ( |
227 | | - <a href={m.group.inviteLink} rel="noopener noreferral" target="_blank" aria-label="Join group"> |
228 | | - <Button variant="outline"> |
229 | | - <ExternalLinkIcon size={20} /> Join Chat |
230 | | - </Button> |
231 | | - </a> |
232 | | - )} |
233 | | - <a |
234 | | - href={`https://t.me/c/${stripChatId(m.chatId)}/${m.messageId}`} |
235 | | - rel="noopener noreferral" |
236 | | - target="_blank" |
237 | | - aria-label="Open message in chat" |
238 | | - > |
239 | | - <Button variant="outline"> |
240 | | - <ExternalLinkIcon size={20} /> Open |
241 | | - </Button> |
242 | | - </a> |
243 | | - </CardFooter> |
244 | | - </Card> |
245 | | - ) |
246 | | -} |
247 | | - |
248 | | -type Log = NonNullable<ApiOutput["tg"]["auditLog"]["getById"]>[number] |
249 | | -function AuditLogCard({ log: m }: { log: Log }) { |
250 | | - const trpc = useTRPC() |
251 | | - |
252 | | - const { data: admin } = useQuery(trpc.tg.users.get.queryOptions({ userId: m.adminId })) |
253 | | - |
254 | | - return ( |
255 | | - <Card> |
256 | | - <CardHeader> |
257 | | - <CardTitle>{m.type}</CardTitle> |
258 | | - </CardHeader> |
259 | | - <CardContent className="grid grid-cols-[auto_1fr] gap-x-2"> |
260 | | - <span className="text-muted-foreground">Chat: </span> |
261 | | - <p> |
262 | | - {m.groupTitle && <span>{m.groupTitle}</span>} [{m.groupId}] |
263 | | - </p> |
264 | | - <span className="text-muted-foreground">Admin ID: </span> |
265 | | - <p>{admin?.user && fmtUser(admin.user)}</p> |
266 | | - |
267 | | - {m.createdAt && ( |
268 | | - <> |
269 | | - <span className="text-muted-foreground">Created: </span> |
270 | | - <p>{m.createdAt.toLocaleString()}</p> |
271 | | - </> |
272 | | - )} |
273 | | - |
274 | | - {m.until && ( |
275 | | - <> |
276 | | - <span className="text-muted-foreground">Until: </span> |
277 | | - <p>{m.until.toLocaleString()}</p> |
278 | | - </> |
279 | | - )} |
280 | | - <span className="text-muted-foreground">Reason:</span> |
281 | | - {m.reason ? <p>{m.reason}</p> : <p className="text-muted-foreground">N/A</p>} |
282 | | - </CardContent> |
283 | | - </Card> |
284 | | - ) |
285 | | -} |
0 commit comments