Merge remote-tracking branch 'origin/main' into dev/credits

This commit is contained in:
javayhu 2025-07-05 15:52:40 +08:00
commit 98421afab8
9 changed files with 77 additions and 48 deletions

View File

@ -1,11 +1,21 @@
import { DashboardHeader } from '@/components/dashboard/dashboard-header';
import { getSession } from '@/lib/server';
import { getTranslations } from 'next-intl/server';
import { notFound } from 'next/navigation';
interface UsersLayoutProps {
children: React.ReactNode;
}
export default async function UsersLayout({ children }: UsersLayoutProps) {
// if is demo website, allow user to access admin and user pages, but data is fake
const isDemo = process.env.NEXT_PUBLIC_DEMO_WEBSITE === 'true';
// Check if user is admin
const session = await getSession();
if (!session || (session.user.role !== 'admin' && !isDemo)) {
notFound();
}
const t = await getTranslations('Dashboard.admin');
const breadcrumbs = [

View File

@ -23,18 +23,22 @@ export default async function BillingLayout({ children }: BillingLayoutProps) {
<>
<DashboardHeader breadcrumbs={breadcrumbs} />
<div className="px-4 lg:px-6 py-16">
<div className="max-w-6xl mx-auto space-y-10">
<div>
<h1 className="text-3xl font-bold tracking-tight">
{t('billing.title')}
</h1>
<p className="text-muted-foreground mt-2">
{t('billing.description')}
</p>
</div>
<div className="flex flex-1 flex-col">
<div className="@container/main flex flex-1 flex-col gap-2">
<div className="flex flex-col gap-4 py-4 md:gap-6 md:py-6">
<div className="px-4 lg:px-6 space-y-10">
<div>
<h1 className="text-3xl font-bold tracking-tight">
{t('billing.title')}
</h1>
<p className="text-muted-foreground mt-2">
{t('billing.description')}
</p>
</div>
{children}
{children}
</div>
</div>
</div>
</div>
</>

View File

@ -25,18 +25,22 @@ export default async function NotificationsLayout({
<>
<DashboardHeader breadcrumbs={breadcrumbs} />
<div className="px-4 lg:px-6 py-16">
<div className="max-w-6xl mx-auto space-y-10">
<div>
<h1 className="text-3xl font-bold tracking-tight">
{t('notification.title')}
</h1>
<p className="text-muted-foreground mt-2">
{t('notification.description')}
</p>
</div>
<div className="flex flex-1 flex-col">
<div className="@container/main flex flex-1 flex-col gap-2">
<div className="flex flex-col gap-4 py-4 md:gap-6 md:py-6">
<div className="px-4 lg:px-6 space-y-10">
<div>
<h1 className="text-3xl font-bold tracking-tight">
{t('notification.title')}
</h1>
<p className="text-muted-foreground mt-2">
{t('notification.description')}
</p>
</div>
{children}
{children}
</div>
</div>
</div>
</div>
</>

View File

@ -2,7 +2,7 @@ import { NewsletterFormCard } from '@/components/settings/notification/newslette
export default function NotificationPage() {
return (
<div className="grid gap-8 md:grid-cols-2">
<div className="grid gap-8 @lg/main:grid-cols-2">
<NewsletterFormCard />
</div>
);

View File

@ -23,18 +23,22 @@ export default async function ProfileLayout({ children }: ProfileLayoutProps) {
<>
<DashboardHeader breadcrumbs={breadcrumbs} />
<div className="px-4 lg:px-6 py-16">
<div className="max-w-6xl mx-auto space-y-10">
<div>
<h1 className="text-3xl font-bold tracking-tight">
{t('profile.title')}
</h1>
<p className="text-muted-foreground mt-2">
{t('profile.description')}
</p>
</div>
<div className="flex flex-1 flex-col">
<div className="@container/main flex flex-1 flex-col gap-2">
<div className="flex flex-col gap-4 py-4 md:gap-6 md:py-6">
<div className="px-4 lg:px-6 space-y-10">
<div>
<h1 className="text-3xl font-bold tracking-tight">
{t('profile.title')}
</h1>
<p className="text-muted-foreground mt-2">
{t('profile.description')}
</p>
</div>
{children}
{children}
</div>
</div>
</div>
</div>
</>

View File

@ -3,7 +3,7 @@ import { UpdateNameCard } from '@/components/settings/profile/update-name-card';
export default function ProfilePage() {
return (
<div className="grid gap-8 md:grid-cols-2">
<div className="flex flex-col gap-8">
<UpdateAvatarCard />
<UpdateNameCard />
</div>

View File

@ -25,18 +25,22 @@ export default async function SecurityLayout({
<>
<DashboardHeader breadcrumbs={breadcrumbs} />
<div className="px-4 lg:px-6 py-16">
<div className="max-w-6xl mx-auto space-y-10">
<div>
<h1 className="text-3xl font-bold tracking-tight">
{t('security.title')}
</h1>
<p className="text-muted-foreground mt-2">
{t('security.description')}
</p>
</div>
<div className="flex flex-1 flex-col">
<div className="@container/main flex flex-1 flex-col gap-2">
<div className="flex flex-col gap-4 py-4 md:gap-6 md:py-6">
<div className="px-4 lg:px-6 space-y-10">
<div>
<h1 className="text-3xl font-bold tracking-tight">
{t('security.title')}
</h1>
<p className="text-muted-foreground mt-2">
{t('security.description')}
</p>
</div>
{children}
{children}
</div>
</div>
</div>
</div>
</>

View File

@ -3,7 +3,7 @@ import { PasswordCardWrapper } from '@/components/settings/security/password-car
export default function SecurityPage() {
return (
<div className="grid gap-8 grid-cols-1">
<div className="flex flex-col gap-8">
<PasswordCardWrapper />
<DeleteAccountCard />
</div>

View File

@ -29,6 +29,9 @@ export function DashboardHeader({
breadcrumbs,
actions,
}: DashboardHeaderProps) {
// if is demo website, allow user to access admin and user pages, but data is fake
const isDemo = process.env.NEXT_PUBLIC_DEMO_WEBSITE === 'true';
return (
<header className="flex h-(--header-height) shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height)">
<div className="flex w-full items-center gap-1 px-4 lg:gap-2 lg:px-6">
@ -69,7 +72,7 @@ export function DashboardHeader({
<div className="ml-auto flex items-center gap-3 px-4">
{actions}
<ThemeSelector />
{isDemo && <ThemeSelector />}
<ModeSwitcher />
<LocaleSwitcher />
</div>