Staff / Owner
Merged staff and owner settings
This commit is contained in:
23 files changed
+693
-236
No files matched your search
@@ -2,11 +2,19 @@ import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import {
|
||||
AlertTriangle,
|
||||
BarChart3,
|
||||
Building2,
|
||||
Calendar,
|
||||
CalendarClock,
|
||||
CalendarX2,
|
||||
CheckCheck,
|
||||
ClipboardList,
|
||||
Crown,
|
||||
Gift,
|
||||
Images,
|
||||
ScissorsSquare,
|
||||
Stamp,
|
||||
Star,
|
||||
TrendingUp,
|
||||
UserX,
|
||||
Users,
|
||||
@@ -37,6 +45,55 @@ function StatTile({ icon: Icon, label, value, hint }: { icon: typeof Calendar; l
|
||||
);
|
||||
}
|
||||
|
||||
const MANAGE_SECTIONS = [
|
||||
{
|
||||
title: "Business",
|
||||
links: [
|
||||
{ href: "/owner/settings/business", label: "Business Details", icon: Building2 },
|
||||
{ href: "/owner/settings/hours", label: "Opening Hours", icon: CalendarClock },
|
||||
{ href: "/owner/settings/gallery", label: "Gallery", icon: Images },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Booking",
|
||||
links: [
|
||||
{ href: "/owner/services", label: "Services", icon: ScissorsSquare },
|
||||
{ href: "/owner/settings/booking-rules", label: "Booking Rules", icon: ClipboardList },
|
||||
{ href: "/owner/settings/loyalty", label: "Loyalty Programme", icon: Crown },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Customers",
|
||||
links: [{ href: "/owner/settings/reviews", label: "Reviews", icon: Star }],
|
||||
},
|
||||
{
|
||||
title: "Team",
|
||||
links: [{ href: "/owner/team", label: "Team Management", icon: Users }],
|
||||
},
|
||||
{
|
||||
title: "Reports",
|
||||
links: [{ href: "/owner/reports", label: "Reports", icon: BarChart3 }],
|
||||
},
|
||||
] as const;
|
||||
|
||||
function ManageSection({ title, links }: (typeof MANAGE_SECTIONS)[number]) {
|
||||
return (
|
||||
<div>
|
||||
<p className="text-muted mb-2 px-1 text-[10px] font-bold tracking-widest uppercase">{title}</p>
|
||||
<ul className="divide-line rounded-md border-line divide-y border bg-white">
|
||||
{links.map(({ href, label, icon: Icon }) => (
|
||||
<li key={href}>
|
||||
<Link href={href} className="hover:bg-stone flex items-center gap-3 px-5 py-4 text-sm font-bold">
|
||||
<Icon className="text-muted h-5 w-5" aria-hidden="true" />
|
||||
{label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default async function OwnerDashboardPage() {
|
||||
const session = await auth();
|
||||
if (!session?.user) redirect("/sign-in?callbackUrl=/owner");
|
||||
@@ -57,8 +114,8 @@ export default async function OwnerDashboardPage() {
|
||||
return (
|
||||
<div className="space-y-6 px-6 pt-12 pb-12">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold tracking-tight">Dashboard</h1>
|
||||
<p className="text-muted text-sm">{context.businessName} — today</p>
|
||||
<h1 className="text-2xl font-bold tracking-tight">Manage</h1>
|
||||
<p className="text-muted text-sm">{context.businessName} — today's overview</p>
|
||||
</div>
|
||||
|
||||
{summary.warnings.length > 0 && (
|
||||
@@ -168,25 +225,10 @@ export default async function OwnerDashboardPage() {
|
||||
)}
|
||||
</Card>
|
||||
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<Link
|
||||
href="/owner/reports"
|
||||
className="rounded-md border-line flex-1 border bg-white px-5 py-4 text-center text-sm font-bold"
|
||||
>
|
||||
View Reports
|
||||
</Link>
|
||||
<Link
|
||||
href="/owner/team"
|
||||
className="rounded-md border-line flex-1 border bg-white px-5 py-4 text-center text-sm font-bold"
|
||||
>
|
||||
Manage Team
|
||||
</Link>
|
||||
<Link
|
||||
href="/owner/settings/booking-rules"
|
||||
className="rounded-md bg-ink flex-1 px-5 py-4 text-center text-sm font-bold text-white"
|
||||
>
|
||||
Update Booking Rules
|
||||
</Link>
|
||||
<div className="space-y-5">
|
||||
{MANAGE_SECTIONS.map((section) => (
|
||||
<ManageSection key={section.title} {...section} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,66 +1,16 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { Bell, Building2, CalendarClock, ClipboardList, Crown, Images, ScissorsSquare, Star } from "lucide-react";
|
||||
import { redirect } from "next/navigation";
|
||||
import { auth } from "@/auth";
|
||||
import { ProfileCard } from "@/components/ui/profile-card";
|
||||
import { SignOutButton } from "@/features/auth/components/sign-out-button";
|
||||
import { hasPermission } from "@/lib/auth/permissions";
|
||||
import { Permission } from "@/generated/prisma/enums";
|
||||
import { getBranding } from "@/lib/business/branding";
|
||||
import { InstallAppButton } from "@/features/pwa/components/install-app-button";
|
||||
|
||||
export const metadata: Metadata = { title: "Owner Settings" };
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
const SETTINGS_LINKS = [
|
||||
{ href: "/owner/settings/business", label: "Business Details", icon: Building2 },
|
||||
{ href: "/owner/settings/gallery", label: "Gallery", icon: Images },
|
||||
{ href: "/owner/settings/hours", label: "Opening Hours", icon: CalendarClock },
|
||||
{ href: "/owner/settings/booking-rules", label: "Booking Rules", icon: ClipboardList },
|
||||
{ href: "/owner/settings/loyalty", label: "Loyalty Programme", icon: Crown },
|
||||
{ href: "/owner/settings/reviews", label: "Reviews", icon: Star },
|
||||
{ href: "/staff/settings/notifications", label: "Notifications", icon: Bell },
|
||||
] as const;
|
||||
|
||||
export default async function OwnerSettingsPage() {
|
||||
const session = await auth();
|
||||
if (!session?.user) redirect("/sign-in");
|
||||
|
||||
const canManage = await hasPermission(session.user.id, Permission.MANAGE_STAFF);
|
||||
if (!canManage) redirect("/staff");
|
||||
const branding = await getBranding();
|
||||
|
||||
return (
|
||||
<div className="space-y-6 px-6 pt-12 pb-12">
|
||||
<h1 className="text-2xl font-bold tracking-tight">Owner Settings</h1>
|
||||
<ProfileCard name={session.user.name ?? "Owner"} meta={session.user.email} avatarUrl={session.user.image ?? undefined} />
|
||||
|
||||
<Link
|
||||
href="/staff/settings"
|
||||
className="rounded-md border-line flex items-center gap-3 border bg-white p-5 text-sm font-bold hover:bg-stone"
|
||||
>
|
||||
<ScissorsSquare className="text-accent h-5 w-5" aria-hidden="true" />
|
||||
Switch to Barber Tools
|
||||
</Link>
|
||||
|
||||
<ul className="divide-line rounded-md border-line divide-y border bg-white">
|
||||
{SETTINGS_LINKS.map(({ href, label, icon: Icon }) => (
|
||||
<li key={href}>
|
||||
<Link href={href} className="hover:bg-stone flex items-center gap-3 px-5 py-4 text-sm font-bold">
|
||||
<Icon className="text-muted h-5 w-5" aria-hidden="true" />
|
||||
{label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<div className="rounded-md border-line border bg-white p-5">
|
||||
<p className="mb-3 text-sm font-bold">Get the app</p>
|
||||
<InstallAppButton businessName={branding.name} />
|
||||
</div>
|
||||
|
||||
<SignOutButton />
|
||||
</div>
|
||||
);
|
||||
/**
|
||||
* Kept as a redirect rather than deleted so any existing bookmark to
|
||||
* `/owner/settings` still works (see the Phase 11 merged-nav brief: "avoid
|
||||
* unnecessary route changes... add redirects only where old nav entry
|
||||
* routes become obsolete"). The page it used to render — a mix of personal
|
||||
* settings (Notifications) and business settings (Business Details,
|
||||
* Gallery, Hours, Booking Rules, Loyalty, Reviews) plus a "Switch to
|
||||
* Barber Tools" link — is now split cleanly: personal settings live at the
|
||||
* one shared `/staff/settings` hub, and business settings are reachable
|
||||
* from the "Manage" nav item's grouped links (see (owner)/owner/page.tsx).
|
||||
*/
|
||||
export default function OwnerSettingsRedirectPage() {
|
||||
redirect("/staff/settings");
|
||||
}
|
||||
Reference in new issue
Block a user