Refactor Next.js configuration and remove Sentry integration
- Updated `serverExternalPackages` in the Next.js configuration to exclude `@sentry/node`, improving compatibility with React's RSC/client boundary. - Removed the `instrumentation.ts` file and refactored Sentry-related code to a no-op, ensuring it does not interfere with the Next.js build process. - Simplified the dashboard page by integrating `DashboardGuildGrid`, enhancing the user interface and reducing complexity in the component structure.
This commit is contained in:
86
apps/webui/src/components/dashboard/dashboard-guild-grid.tsx
Normal file
86
apps/webui/src/components/dashboard/dashboard-guild-grid.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
'use client';
|
||||
|
||||
import type { DashboardGuild } from '@nexumi/shared';
|
||||
import Link from 'next/link';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
|
||||
function guildIconUrl(guild: Pick<DashboardGuild, 'id' | 'icon'>): string | undefined {
|
||||
return guild.icon
|
||||
? `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.png?size=64`
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function initials(name: string): string {
|
||||
return (
|
||||
name
|
||||
.split(' ')
|
||||
.filter(Boolean)
|
||||
.slice(0, 2)
|
||||
.map((part) => part[0]?.toUpperCase())
|
||||
.join('') || '?'
|
||||
);
|
||||
}
|
||||
|
||||
export function DashboardGuildGrid({
|
||||
guilds,
|
||||
inviteUrls,
|
||||
labels
|
||||
}: {
|
||||
guilds: DashboardGuild[];
|
||||
inviteUrls: Record<string, string>;
|
||||
labels: {
|
||||
empty: string;
|
||||
botMissing: string;
|
||||
manage: string;
|
||||
invite: string;
|
||||
};
|
||||
}) {
|
||||
if (guilds.length === 0) {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="py-10 text-center text-sm text-muted-foreground">
|
||||
{labels.empty}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{guilds.map((guild) => (
|
||||
<Card key={guild.id}>
|
||||
<CardContent className="flex flex-col gap-4 p-5">
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar className="size-10">
|
||||
<AvatarImage src={guildIconUrl(guild)} alt={guild.name} />
|
||||
<AvatarFallback>{initials(guild.name)}</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="min-w-0">
|
||||
<p className="truncate font-medium">{guild.name}</p>
|
||||
{!guild.botPresent && (
|
||||
<Badge variant="outline" className="mt-1">
|
||||
{labels.botMissing}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{guild.botPresent ? (
|
||||
<Button asChild>
|
||||
<Link href={`/dashboard/${guild.id}`}>{labels.manage}</Link>
|
||||
</Button>
|
||||
) : (
|
||||
<Button asChild variant="outline">
|
||||
<a href={inviteUrls[guild.id]} target="_blank" rel="noreferrer">
|
||||
{labels.invite}
|
||||
</a>
|
||||
</Button>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { Slot } from '@radix-ui/react-slot';
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
import * as React from 'react';
|
||||
|
||||
Reference in New Issue
Block a user