fix(buyer/billing/comms/a11y): Codex review pass round 2
Tuxedo buyer path (subagent 2): - src/app/tuxedo/page.tsx: remove duplicate CinematicShowcase render - src/components/storefront/CinematicShowcase.tsx: wire up useCart, Add to Cart button, brand-aware fulfillment - src/app/tuxedo/stops/TuxedoStopsList.tsx: improved empty state with calendar icon + CTAs - src/app/cart/CartClient.tsx: guard against empty cart checkout; 'Cart is Empty' state Billing reconciliation (subagent 3): - src/actions/billing/billing-overview.ts: NEW — single source of truth - src/app/admin/settings/billing/page.tsx: use getBillingOverview - src/app/admin/settings/billing/BillingClientPage.tsx: rewritten to consume BillingOverview (status pill, addons state, removable flags, derived invoice amounts, usage footer) - src/app/admin/page.tsx: use getBillingOverview (aligns dashboard with billing) - src/components/admin/DashboardClient.tsx: 'Active Products' now reads from getBillingOverview - supabase/migrations/203_plan_usage_active_products.sql: get_brand_plan_info counts products as active=true AND deleted_at IS NULL Harvest Reach dedup + audience preview (manual, subagent 4 didn't complete): - src/components/admin/CommunicationsPage.tsx: add initialTab prop - src/app/admin/communications/compose/page.tsx: now renders with initialTab='compose' (single compose experience, no duplicate edit panel) - src/components/admin/HarvestReach/CampaignComposerPage.tsx: always-visible audience preview panel (count + sample emails), loads via previewCampaignAudience action Layout/content consistency + a11y sweep (subagent 5): - src/components/layout/SiteHeader.tsx: Admin link only shows for authenticated admin users - src/components/Providers.tsx: suppress public SiteHeader/Footer for /admin, /cart, /checkout, /wholesale, /water (fixes duplicate headers) - src/app/contact/ContactClientPage.tsx: Phone/Email now use tel:/mailto: links; dynamic year - src/app/blog/page.tsx, changelog, privacy-policy, roadmap, security, terms-and-conditions, waitlist: dynamic year - src/app/admin/wholesale/WholesaleClient.tsx: proper htmlFor/id, type=email/tel, autoComplete - src/app/admin/settings/ai/AIClient.tsx: proper htmlFor/id, required + aria-required - src/app/admin/settings/integrations/IntegrationsClient.tsx: only mask secret fields; add required + aria-required + CredentialField.required type - src/app/admin/water-log/headgates/HeadgatesManager.tsx: htmlFor/id, aria-required - src/components/admin/CreateUserModal.tsx: htmlFor/id, required, aria-required, aria-describedby, autoComplete - src/app/admin/me/AdminMeClient.tsx, products/import, sales/import, water-log/settings, login, brands, tuxedo: a11y polish (ids/required/aria)
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const BRAND_NAMES: Record<string, string> = {
|
||||
tuxedo: "Tuxedo Corn",
|
||||
@@ -10,6 +11,26 @@ const BRAND_NAMES: Record<string, string> = {
|
||||
|
||||
export default function SiteHeader() {
|
||||
const pathname = usePathname();
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
|
||||
// Only show the Admin link to users who are actually authenticated as admins.
|
||||
// This prevents leaking the Admin entry point on public marketing pages
|
||||
// (e.g. /, /pricing, /contact, /security, /roadmap, /changelog, /blog, etc.).
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
(async () => {
|
||||
try {
|
||||
const mod = await import("@/actions/admin-user");
|
||||
const user = await mod.getCurrentAdminUser();
|
||||
if (!cancelled) setIsAdmin(!!user);
|
||||
} catch {
|
||||
if (!cancelled) setIsAdmin(false);
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [pathname]);
|
||||
|
||||
const showBrandName = pathname?.startsWith("/tuxedo") || pathname?.startsWith("/indian-river-direct");
|
||||
const brandKey = pathname?.split("/")[1];
|
||||
@@ -83,8 +104,8 @@ export default function SiteHeader() {
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Admin link */}
|
||||
{!isAdminRoute && (
|
||||
{/* Admin link — only rendered for users who are signed in as admins. */}
|
||||
{!isAdminRoute && isAdmin && (
|
||||
<Link
|
||||
href="/admin"
|
||||
className="text-xs sm:text-sm font-medium uppercase tracking-wider transition-colors hover:opacity-70"
|
||||
|
||||
Reference in New Issue
Block a user