Organize Brand tab by brand selection for platform admins

- Added BrandSelector component showing all brands as cards
- Platform admins see brand selector at top of Brand tab
- Non-platform admins see only their brand's settings
- Brand selection via ?brand= query param updates the page
- Cards show which brand is currently selected
This commit is contained in:
2026-06-02 04:17:50 +00:00
parent 7783604141
commit f72cfad5f3
2 changed files with 90 additions and 5 deletions
+17 -4
View File
@@ -9,18 +9,31 @@ export const metadata = {
description: "Manage your brand settings, workers, tasks, and user permissions",
};
export default async function AdminSettingsPage() {
export default async function AdminSettingsPage({
searchParams,
}: {
searchParams: Promise<{ brand?: string }>;
}) {
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
const brandId = adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
const params = await searchParams;
const isPlatformAdmin = adminUser.role === "platform_admin";
// Platform admin can select a brand via query param, otherwise use their assigned brand
let brandId = adminUser.brand_id ?? "";
if (isPlatformAdmin && params.brand) {
brandId = params.brand;
} else if (!brandId) {
brandId = "64294306-5f42-463d-a5e8-2ad6c81a96de";
}
const [{ users, error }, { brands }] = await Promise.all([
getAdminUsers(adminUser.role === "platform_admin" ? undefined : (adminUser.brand_id ?? undefined)),
getAdminUsers(isPlatformAdmin ? undefined : (adminUser.brand_id ?? undefined)),
getBrands(),
]);
// Fetch payment settings for the brand tab
// Fetch payment settings for the current brand
const paymentResult = await getPaymentSettings(brandId);
const paymentSettings = paymentResult.success ? paymentResult.settings : null;
+73 -1
View File
@@ -58,6 +58,53 @@ const Icons = {
type Brand = { id: string; name: string };
// Brand Selector Component
function BrandSelector({
brands,
selectedBrandId,
onSelect,
}: {
brands: Brand[];
selectedBrandId: string;
onSelect: (id: string) => void;
}) {
return (
<div className="space-y-3">
<p className="text-sm text-[var(--admin-text-muted)]">Select which brand&apos;s settings to manage:</p>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
{brands.map((brand) => (
<button
key={brand.id}
onClick={() => onSelect(brand.id)}
className={`flex items-center gap-3 rounded-xl border p-4 text-left transition-all ${
selectedBrandId === brand.id
? "border-[var(--admin-accent)] bg-[var(--admin-accent-light)] ring-2 ring-[var(--admin-accent)]"
: "border-[var(--admin-border)] hover:border-[var(--admin-accent)] hover:bg-stone-50"
}`}
>
<div className={`flex h-10 w-10 items-center justify-center rounded-lg text-white font-bold ${
selectedBrandId === brand.id ? "bg-[var(--admin-accent)]" : "bg-stone-400"
}`}>
{brand.name.charAt(0).toUpperCase()}
</div>
<div className="flex-1 min-w-0">
<p className="font-semibold text-[var(--admin-text-primary)] truncate">{brand.name}</p>
{selectedBrandId === brand.id && (
<p className="text-xs text-[var(--admin-accent)]">Currently viewing</p>
)}
</div>
{selectedBrandId === brand.id && (
<svg className="w-5 h-5 text-[var(--admin-accent)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
)}
</button>
))}
</div>
</div>
);
}
type Props = {
brandId: string;
users: import("@/actions/admin/users").AdminUserRow[];
@@ -151,7 +198,32 @@ export default function SettingsClient({
{activeTab === "brand" && (
<div className="space-y-6">
{/* Brand Settings */}
{currentUser.role === "platform_admin" && brands.length > 0 && (
<div className="rounded-2xl border border-[var(--admin-border)] bg-white overflow-hidden">
<div className="p-4 sm:p-6 border-b border-[var(--admin-border)]">
<div className="flex items-center gap-3">
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-emerald-500">
{Icons.brand("w-4 h-4 text-white")}
</div>
<div>
<h2 className="text-sm sm:text-lg font-bold text-[var(--admin-text-primary)]">Select Brand</h2>
<p className="text-[10px] sm:text-xs text-[var(--admin-text-muted)]">Choose a brand to view and edit its settings</p>
</div>
</div>
</div>
<div className="p-4 sm:p-6">
<BrandSelector
brands={brands}
selectedBrandId={brandId}
onSelect={(id) => {
window.location.href = `/admin/settings?brand=${id}#brand`;
}}
/>
</div>
</div>
)}
{/* Selected Brand Settings */}
<div className="rounded-2xl border border-[var(--admin-border)] bg-white overflow-hidden">
<div className="p-4 sm:p-6 border-b border-[var(--admin-border)]">
<div className="flex items-center gap-3">