Updated the header of these pages to match the rest of the pages.
This commit is contained in:
4 files changed
+216
-209
No files matched your search
@@ -3,6 +3,7 @@ import Link from "next/link";
|
||||
import { Plus, Search, ShieldCheck, ShieldPlus } from "lucide-react";
|
||||
import { redirect } from "next/navigation";
|
||||
import { auth } from "@/auth";
|
||||
import { TopNav } from "@/components/navigation/top-nav";
|
||||
import { prisma } from "@/lib/db/prisma";
|
||||
import { hasPermission } from "@/lib/auth/permissions";
|
||||
import { Permission } from "@/generated/prisma/enums";
|
||||
@@ -30,80 +31,82 @@ export default async function OwnerTeamPage({
|
||||
const { q = "" } = await searchParams;
|
||||
const staff = await listStaffForBusiness(prisma, { businessId: context.businessId, q, includeInactive: true });
|
||||
|
||||
const headerAction = (
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
href="/owner/team/add-administrator"
|
||||
className="border-line text-ink flex h-10 w-10 items-center justify-center rounded-full border"
|
||||
aria-label="Invite administrator"
|
||||
title="Invite Administrator"
|
||||
>
|
||||
<ShieldPlus className="h-4 w-4" aria-hidden="true" />
|
||||
</Link>
|
||||
<Link
|
||||
href="/owner/team/add"
|
||||
className="bg-ink flex h-10 w-10 items-center justify-center rounded-full text-white"
|
||||
aria-label="Add staff member"
|
||||
>
|
||||
<Plus className="h-4 w-4" aria-hidden="true" />
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="px-6 pt-12 pb-12 lg:max-w-4xl">
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<h1 className="text-2xl font-bold tracking-tight">Team</h1>
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
href="/owner/team/add-administrator"
|
||||
className="border-line text-ink flex h-10 w-10 items-center justify-center rounded-full border"
|
||||
aria-label="Invite administrator"
|
||||
title="Invite Administrator"
|
||||
>
|
||||
<ShieldPlus className="h-4 w-4" aria-hidden="true" />
|
||||
</Link>
|
||||
<Link
|
||||
href="/owner/team/add"
|
||||
className="bg-ink flex h-10 w-10 items-center justify-center rounded-full text-white"
|
||||
aria-label="Add staff member"
|
||||
>
|
||||
<Plus className="h-4 w-4" aria-hidden="true" />
|
||||
</Link>
|
||||
<div className="pb-12">
|
||||
<TopNav title="Team" onBack sticky className="bg-stone" action={headerAction} />
|
||||
<main className="px-6 py-6 lg:max-w-4xl">
|
||||
<form action="/owner/team" method="GET" className="relative mb-4">
|
||||
<Search className="text-muted absolute top-1/2 left-4 h-4 w-4 -translate-y-1/2" aria-hidden="true" />
|
||||
<label htmlFor="team-search" className="sr-only">
|
||||
Search staff by name or email
|
||||
</label>
|
||||
<input
|
||||
id="team-search"
|
||||
type="search"
|
||||
name="q"
|
||||
defaultValue={q}
|
||||
placeholder="Search by name or email"
|
||||
className="border-line focus:ring-ink w-full rounded-xl border bg-white py-3 pr-4 pl-11 text-sm outline-none focus:ring-2"
|
||||
/>
|
||||
</form>
|
||||
|
||||
<div className="grid gap-3 lg:grid-cols-2">
|
||||
{staff.length === 0 ? (
|
||||
<p className="text-muted col-span-full rounded-md border border-line bg-white p-5 text-center text-sm">
|
||||
No staff match “{q}”.
|
||||
</p>
|
||||
) : (
|
||||
staff.map((s) => (
|
||||
<Link
|
||||
key={s.id}
|
||||
href={`/owner/team/${s.id}`}
|
||||
className={cn(
|
||||
"rounded-md border-line flex items-center gap-4 border bg-white p-5",
|
||||
s.status === "INACTIVE" && "opacity-60",
|
||||
)}
|
||||
>
|
||||
<div className="bg-stone text-muted flex h-12 w-12 shrink-0 items-center justify-center rounded-full text-sm font-bold">
|
||||
{(s.user.name ?? "?").charAt(0)}
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="truncate text-sm font-bold">{s.user.name}</p>
|
||||
<p className="text-muted truncate text-xs">{s.user.email}</p>
|
||||
<p className="text-accent mt-0.5 flex items-center gap-1 text-[10px] font-bold tracking-widest uppercase">
|
||||
{s.role.name === "Administrator" && (
|
||||
<ShieldCheck className="h-3 w-3 shrink-0" aria-hidden="true" />
|
||||
)}
|
||||
{s.role.name}
|
||||
{s.status === "INACTIVE" && <span className="text-muted"> · Inactive</span>}
|
||||
{s.status === "ACTIVE" && s.invitation && !s.invitation.acceptedAt && (
|
||||
<span className="text-warning-foreground"> · Invite Pending</span>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form action="/owner/team" method="GET" className="relative mb-4">
|
||||
<Search className="text-muted absolute top-1/2 left-4 h-4 w-4 -translate-y-1/2" aria-hidden="true" />
|
||||
<label htmlFor="team-search" className="sr-only">
|
||||
Search staff by name or email
|
||||
</label>
|
||||
<input
|
||||
id="team-search"
|
||||
type="search"
|
||||
name="q"
|
||||
defaultValue={q}
|
||||
placeholder="Search by name or email"
|
||||
className="border-line focus:ring-ink w-full rounded-xl border bg-white py-3 pr-4 pl-11 text-sm outline-none focus:ring-2"
|
||||
/>
|
||||
</form>
|
||||
|
||||
<div className="grid gap-3 lg:grid-cols-2">
|
||||
{staff.length === 0 ? (
|
||||
<p className="text-muted col-span-full rounded-md border border-line bg-white p-5 text-center text-sm">
|
||||
No staff match “{q}”.
|
||||
</p>
|
||||
) : (
|
||||
staff.map((s) => (
|
||||
<Link
|
||||
key={s.id}
|
||||
href={`/owner/team/${s.id}`}
|
||||
className={cn(
|
||||
"rounded-md border-line flex items-center gap-4 border bg-white p-5",
|
||||
s.status === "INACTIVE" && "opacity-60",
|
||||
)}
|
||||
>
|
||||
<div className="bg-stone text-muted flex h-12 w-12 shrink-0 items-center justify-center rounded-full text-sm font-bold">
|
||||
{(s.user.name ?? "?").charAt(0)}
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="truncate text-sm font-bold">{s.user.name}</p>
|
||||
<p className="text-muted truncate text-xs">{s.user.email}</p>
|
||||
<p className="text-accent mt-0.5 flex items-center gap-1 text-[10px] font-bold tracking-widest uppercase">
|
||||
{s.role.name === "Administrator" && (
|
||||
<ShieldCheck className="h-3 w-3 shrink-0" aria-hidden="true" />
|
||||
)}
|
||||
{s.role.name}
|
||||
{s.status === "INACTIVE" && <span className="text-muted"> · Inactive</span>}
|
||||
{s.status === "ACTIVE" && s.invitation && !s.invitation.acceptedAt && (
|
||||
<span className="text-warning-foreground"> · Invite Pending</span>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user