More cleanup

This commit is contained in:
cte 2025-05-12 01:13:42 -07:00
parent c1c7206525
commit 73983ccb4b
8 changed files with 177 additions and 156 deletions

View file

@ -1,4 +1,3 @@
import { useTranslations } from 'next-intl';
import { getLocale, getTranslations } from 'next-intl/server';
import { DashboardHeader } from '@/components/dashboard/DashboardHeader';
@ -9,35 +8,21 @@ export async function generateMetadata() {
return { title: t('meta_title'), description: t('meta_description') };
}
export default function DashboardLayout(props: { children: React.ReactNode }) {
const t = useTranslations('DashboardLayout');
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<>
<div className="shadow-md">
<div className="mx-auto flex max-w-screen-xl items-center justify-between px-3 py-4">
<DashboardHeader
menu={[
{
href: '/dashboard',
label: t('home'),
},
{
href: '/dashboard/organization-profile/organization-members',
label: t('members'),
},
{
href: '/dashboard/organization-profile',
label: t('settings'),
},
]}
/>
<DashboardHeader />
</div>
</div>
<div className="min-h-[calc(100vh-72px)] bg-muted">
<div className="mx-auto max-w-screen-xl px-3 pb-16 pt-6">
{props.children}
{children}
</div>
</div>
</>

View file

@ -12,17 +12,11 @@ export default function Page() {
title={t('title_bar')}
description={t('title_bar_description')}
/>
<OrganizationProfile
routing="path"
path="/dashboard/organization-profile"
afterLeaveOrganizationUrl="/onboarding/organization-selection"
appearance={{
elements: {
rootBox: 'w-full',
cardBox: 'w-full flex',
},
}}
afterLeaveOrganizationUrl="/onboarding/select-org"
appearance={{ elements: { rootBox: 'w-full', cardBox: 'w-full flex' } }}
/>
</>
);

View file

@ -1,29 +0,0 @@
import { OrganizationList } from '@clerk/nextjs';
import { getTranslations } from 'next-intl/server';
export async function generateMetadata(props: { params: { locale: string } }) {
const t = await getTranslations({
locale: props.params.locale,
namespace: 'Dashboard',
});
return {
title: t('meta_title'),
description: t('meta_description'),
};
}
const OrganizationSelectionPage = () => (
<div className="flex min-h-screen items-center justify-center">
<OrganizationList
afterSelectOrganizationUrl="/dashboard"
afterCreateOrganizationUrl="/dashboard"
hidePersonal
skipInvitationScreen
/>
</div>
);
export const dynamic = 'force-dynamic';
export default OrganizationSelectionPage;

View file

@ -0,0 +1,29 @@
import { redirect } from 'next/navigation';
import { CreateOrganization } from '@clerk/nextjs';
import { auth as clerkAuth } from '@clerk/nextjs/server';
import { getLocale, getTranslations } from 'next-intl/server';
export async function generateMetadata() {
const locale = await getLocale();
const t = await getTranslations({ locale, namespace: 'Dashboard' });
return { title: t('meta_title'), description: t('meta_description') };
}
export const dynamic = 'force-dynamic';
export default async function Page() {
const auth = await clerkAuth();
if (!auth.userId) {
redirect('/');
}
return (
<div className="flex min-h-screen items-center justify-center">
<CreateOrganization
// afterSelectOrganizationUrl="/dashboard"
afterCreateOrganizationUrl="/dashboard"
/>
</div>
);
}

View file

@ -0,0 +1,29 @@
import { redirect } from 'next/navigation';
import { OrganizationList } from '@clerk/nextjs';
import { auth as clerkAuth } from '@clerk/nextjs/server';
import { getLocale, getTranslations } from 'next-intl/server';
export async function generateMetadata() {
const locale = await getLocale();
const t = await getTranslations({ locale, namespace: 'Dashboard' });
return { title: t('meta_title'), description: t('meta_description') };
}
export const dynamic = 'force-dynamic';
export default async function Page() {
const auth = await clerkAuth();
if (!auth.userId) {
redirect('/');
}
return (
<div className="flex min-h-screen items-center justify-center">
<OrganizationList
afterSelectOrganizationUrl="/dashboard"
afterCreateOrganizationUrl="/dashboard"
/>
</div>
);
}

View file

@ -1,7 +1,13 @@
'use client';
import { OrganizationSwitcher, UserButton } from '@clerk/nextjs';
import { useMemo } from 'react';
import Link from 'next/link';
import {
OrganizationSwitcher,
UserButton,
useOrganization,
} from '@clerk/nextjs';
import { useTranslations } from 'next-intl';
import { ActiveLink } from '@/components/ActiveLink';
import { LocaleSwitcher } from '@/components/LocaleSwitcher';
@ -16,85 +22,94 @@ import {
} from '@/components/ui';
import { Logo } from '@/components/templates/Logo';
type DashboardHeaderProps = {
menu: {
href: string;
label: string;
}[];
};
export const DashboardHeader = () => {
const t = useTranslations('DashboardLayout');
const { organization } = useOrganization();
export const DashboardHeader = (props: DashboardHeaderProps) => (
<>
<div className="flex items-center">
<Link href="/dashboard" className="max-sm:hidden">
<Logo />
</Link>
<svg
className="size-8 stroke-muted-foreground max-sm:hidden"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" />
<path d="M17 5 7 19" />
</svg>
<OrganizationSwitcher
organizationProfileMode="navigation"
organizationProfileUrl="/dashboard/organization-profile"
afterCreateOrganizationUrl="/dashboard"
hidePersonal
skipInvitationScreen
appearance={{
elements: { organizationSwitcherTrigger: 'max-w-28 sm:max-w-52' },
}}
/>
<nav className="ml-3 max-lg:hidden">
<ul className="flex flex-row items-center gap-x-3 text-lg font-medium [&_a:hover]:opacity-100 [&_a]:opacity-75">
{props.menu.map((item) => (
<li key={item.href}>
<ActiveLink href={item.href}>{item.label}</ActiveLink>
</li>
))}
const menu = useMemo(() => {
const menu = [{ href: '/dashboard', label: t('home') }];
return organization
? [
...menu,
{
href: '/dashboard/organization-profile/organization-members',
label: t('members'),
},
{ href: '/dashboard/organization-profile', label: t('settings') },
]
: menu;
}, [organization, t]);
return (
<>
<div className="flex items-center">
<Link href="/dashboard" className="max-sm:hidden">
<Logo />
</Link>
<svg
className="size-8 stroke-muted-foreground max-sm:hidden"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" />
<path d="M17 5 7 19" />
</svg>
<OrganizationSwitcher
organizationProfileMode="navigation"
organizationProfileUrl="/dashboard/organization-profile"
afterCreateOrganizationUrl="/dashboard"
createOrganizationUrl="/onboarding/create-org"
/>
<nav className="ml-3 max-lg:hidden">
<ul className="flex flex-row items-center gap-x-3 text-lg font-medium [&_a:hover]:opacity-100 [&_a]:opacity-75">
{menu.map(({ href, label }) => (
<li key={href}>
<ActiveLink href={href}>{label}</ActiveLink>
</li>
))}
</ul>
</nav>
</div>
<div>
<ul className="flex items-center gap-x-1.5 [&_li[data-fade]:hover]:opacity-100 [&_li[data-fade]]:opacity-60">
<li data-fade>
<div className="lg:hidden">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<ToggleMenuButton />
</DropdownMenuTrigger>
<DropdownMenuContent>
{menu.map(({ href, label }) => (
<DropdownMenuItem key={href} asChild>
<Link href={href}>{label}</Link>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
</div>
</li>
<li data-fade>
<LocaleSwitcher />
</li>
<li data-fade>
<ThemeSwitcher />
</li>
<li>
<Separator orientation="vertical" className="h-4" />
</li>
<li>
<UserButton
userProfileMode="navigation"
userProfileUrl="/dashboard/user-profile"
appearance={{ elements: { rootBox: 'px-2 py-1.5' } }}
/>
</li>
</ul>
</nav>
</div>
<div>
<ul className="flex items-center gap-x-1.5 [&_li[data-fade]:hover]:opacity-100 [&_li[data-fade]]:opacity-60">
<li data-fade>
<div className="lg:hidden">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<ToggleMenuButton />
</DropdownMenuTrigger>
<DropdownMenuContent>
{props.menu.map((item) => (
<DropdownMenuItem key={item.href} asChild>
<Link href={item.href}>{item.label}</Link>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
</div>
</li>
<li data-fade>
<LocaleSwitcher />
</li>
<li data-fade>
<ThemeSwitcher />
</li>
<li>
<Separator orientation="vertical" className="h-4" />
</li>
<li>
<UserButton
userProfileMode="navigation"
userProfileUrl="/dashboard/user-profile"
appearance={{ elements: { rootBox: 'px-2 py-1.5' } }}
/>
</li>
</ul>
</div>
</>
);
</div>
</>
);
};

View file

@ -1,17 +1,21 @@
export const DashboardSection = (props: {
type DashboardSectionProps = {
title: string;
description: string;
children: React.ReactNode;
}) => (
};
export const DashboardSection = ({
title,
description,
children,
}: DashboardSectionProps) => (
<div className="rounded-md bg-card p-5">
<div className="max-w-3xl">
<div className="text-lg font-semibold">{props.title}</div>
<div className="text-lg font-semibold">{title}</div>
<div className="mb-4 text-sm font-medium text-muted-foreground">
{props.description}
{description}
</div>
{props.children}
{children}
</div>
</div>
);

View file

@ -11,18 +11,12 @@ if (Env.LOGTAIL_SOURCE_TOKEN) {
stream = pino.multistream([
await logtail({
sourceToken: Env.LOGTAIL_SOURCE_TOKEN,
options: {
sendLogsToBetterStack: true,
},
options: { sendLogsToBetterStack: true },
}),
{
stream: pretty(), // Prints logs to the console
},
{ stream: pretty() }, // Prints logs to the console
]);
} else {
stream = pretty({
colorize: true,
});
stream = pretty({ colorize: true });
}
export const logger = pino({ base: undefined }, stream);