Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions frontend/app/brand/createcampaign/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default function BrandCreateCampaign() {
return (
<main className="min-h-screen p-8">
<h1 className="text-2xl font-bold">Create Campaign</h1>
<p className="mt-4 text-slate-600">
Welcome to Create Campaign — coming soon!
</p>
</main>
);
}
2 changes: 2 additions & 0 deletions frontend/app/brand/home/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import AuthGuard from "@/components/auth/AuthGuard";
import SlidingMenu from "@/components/SlidingMenu";
import { getUserProfile, signOut } from "@/lib/auth-helpers";
import { Briefcase, Loader2, LogOut } from "lucide-react";
import { useRouter } from "next/navigation";
Expand Down Expand Up @@ -35,6 +36,7 @@ export default function BrandHomePage() {
return (
<AuthGuard requiredRole="Brand">
<div className="min-h-screen bg-linear-to-br from-blue-50 via-white to-purple-50">
<SlidingMenu role="brand" />
{/* Header */}
<header className="border-b border-gray-200 bg-white">
<div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-4 sm:px-6 lg:px-8">
Expand Down
10 changes: 10 additions & 0 deletions frontend/app/creator/createcampaign/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default function CreatorCreateCampaign() {
return (
<main className="min-h-screen p-8">
<h1 className="text-2xl font-bold">Create Campaign</h1>
<p className="mt-4 text-slate-600">
Welcome to Create Campaign — coming soon!
</p>
</main>
);
}
2 changes: 2 additions & 0 deletions frontend/app/creator/home/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import AuthGuard from "@/components/auth/AuthGuard";
import SlidingMenu from "@/components/SlidingMenu";
import { getUserProfile, signOut } from "@/lib/auth-helpers";
import { Loader2, LogOut, Sparkles } from "lucide-react";
import { useRouter } from "next/navigation";
Expand Down Expand Up @@ -35,6 +36,7 @@ export default function CreatorHomePage() {
return (
<AuthGuard requiredRole="Creator">
<div className="min-h-screen bg-linear-to-br from-purple-50 via-white to-blue-50">
<SlidingMenu role="creator" />
{/* Header */}
<header className="border-b border-gray-200 bg-white">
<div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-4 sm:px-6 lg:px-8">
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export default function SignupPage() {
name: data.name,
email: data.email,
password: data.password,
role: data.accountType,
role: data.accountType === "Creator" ? "creator" : "brand",
}),
});

Expand Down
141 changes: 141 additions & 0 deletions frontend/components/SlidingMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"use client";
import Link from "next/link";
import { useEffect, useRef, useState } from "react";

export type Role = "creator" | "brand";

type Props = {
role: Role;
};

export default function SlidingMenu({ role }: Props) {
const [open, setOpen] = useState(false);
const panelRef = useRef<HTMLDivElement | null>(null);

// Close on ESC
useEffect(() => {
function onKey(e: KeyboardEvent) {
if (e.key === "Escape") setOpen(false);
}
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, []);

// Click outside to close
useEffect(() => {
function onClick(e: MouseEvent) {
if (!open) return;
if (!panelRef.current) return;
if (!panelRef.current.contains(e.target as Node)) setOpen(false);
}
document.addEventListener("mousedown", onClick);
return () => document.removeEventListener("mousedown", onClick);
}, [open]);

// Strict role comparison for reliable routing
const normalizedRole = String(role).trim().toLowerCase();
const basePath = normalizedRole === "brand" ? "/brand" : "/creator";
const createCampaignPath = `${basePath}/createcampaign`;

return (
<>
{/* Hamburger Button */}
<button
aria-label={open ? "Close menu" : "Open menu"}
aria-expanded={open}
className="fixed top-4 left-4 z-50 inline-flex transform items-center justify-center rounded-md border bg-white/90 p-2 shadow-sm transition hover:scale-105 dark:bg-slate-900/90"
onClick={() => setOpen((s) => !s)}
>
{/* simple hamburger icon */}
<svg
className="h-6 w-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
d={open ? "M6 18L18 6M6 6l12 12" : "M4 6h16M4 12h16M4 18h16"}
/>
</svg>
</button>

{/* Backdrop */}
<div
aria-hidden={!open}
className={`fixed inset-0 z-40 bg-black/40 transition-opacity ${open ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"}`}
onClick={() => setOpen(false)}
/>

{/* Sliding panel */}
<aside
ref={panelRef}
role="dialog"
aria-modal="true"
aria-label="Navigation"
className={`fixed top-0 left-0 z-50 flex h-full w-80 transform flex-col bg-white shadow-xl transition-transform duration-300 ease-in-out sm:w-64 dark:bg-slate-900 ${open ? "translate-x-0" : "-translate-x-full"}`}
>
<div className="flex items-center justify-between border-b p-4 dark:border-slate-800">
<h3 className="text-lg font-semibold">Menu</h3>
<button
aria-label="Close menu"
onClick={() => setOpen(false)}
className="rounded p-1 hover:bg-slate-100"
>
<svg
className="h-5 w-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>

<nav className="p-4">
<ul className="space-y-2">
<li>
<Link
href={createCampaignPath}
className="flex items-center gap-3 rounded px-3 py-2 hover:bg-slate-100 dark:hover:bg-slate-800"
>
<svg
className="h-5 w-5"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
>
<path
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
d="M12 4v16m8-8H4"
/>
</svg>
<span>Create Campaign</span>
</Link>
</li>
{/* future actions listed here */}
</ul>
</nav>

<div className="mt-auto p-4 text-sm text-slate-500">
<p>
Logged in as{" "}
<strong className="text-slate-700 dark:text-slate-200">
{role}
</strong>
</p>
</div>
</aside>
</>
);
}