Skip to content
Merged

Dev #137

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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ dist
.next
!.env.example
data.ms/
data.ms/
*.mdb
5 changes: 3 additions & 2 deletions apps/core-api/src/middlewares/rateLimit.middleware.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { rateLimit } from 'express-rate-limit';
import { Request, Response, NextFunction } from 'express';
import { rateLimit, Options } from 'express-rate-limit';

export const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
Expand All @@ -9,7 +10,7 @@ export const authLimiter = rateLimit({
success: false,
message: "Too many authentication attempts. Please try again later.",
},
handler: (req, res, next, options) => {
handler: (req: Request, res: Response, next: NextFunction, options: Options) => {
res.status(429).json(options.message);
},
});
259 changes: 146 additions & 113 deletions apps/web/app/brand-dashboard/bookings/page.tsx

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions apps/web/app/brand-dashboard/calendar/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ export default function BrandCalendarPage() {
}

return (
<div className="px-4 sm:px-6 lg:px-8 py-8 h-full flex flex-col min-h-0 bg-[#f8fafc]">
<div className="flex flex-col lg:flex-row gap-8 flex-1 overflow-hidden">
<div className="px-4 sm:px-6 lg:px-8 py-4 sm:py-8 h-full flex flex-col min-h-0 bg-[#f8fafc]">
<div className="flex flex-col lg:flex-row gap-6 lg:gap-8 flex-1 overflow-y-auto lg:overflow-hidden pb-20 lg:pb-0">
{/* Left Column: Calendar Grid */}
<div className="flex-1 bg-white rounded-[2.5rem] border border-gray-100 shadow-sm p-10 flex flex-col items-center">
<div className="flex-1 bg-white rounded-[1.5rem] lg:rounded-[2.5rem] border border-gray-100 shadow-sm p-5 sm:p-8 lg:p-10 flex flex-col items-center lg:overflow-y-auto">
<div className="w-full max-w-2xl">
<div className="flex items-center justify-between mb-12">
<h1 className="text-2xl font-bold text-gray-900 tracking-tight">Select Date</h1>
<div className="flex items-center gap-6">
<div className="flex flex-col sm:flex-row items-center justify-between gap-4 mb-8 sm:mb-12">
<h1 className="text-xl sm:text-2xl font-bold text-gray-900 tracking-tight">Select Date</h1>
<div className="flex items-center gap-4 sm:gap-6">
<button
onClick={() => handleMonthChange(-1)}
className="p-2 hover:bg-gray-50 rounded-full transition-all text-gray-400"
Expand All @@ -146,16 +146,16 @@ export default function BrandCalendarPage() {
))}
</div>

<div className="grid grid-cols-7 gap-y-10 gap-x-4 mb-16 w-full">
<div className="grid grid-cols-7 gap-y-6 sm:gap-y-10 gap-x-2 sm:gap-x-4 mb-10 sm:mb-16 w-full">
{Array.from({ length: firstDayOfMonth(currentDate.getFullYear(), currentDate.getMonth()) }).map((_, i) => (
<div key={`empty-${i}`} className="h-14"></div>
<div key={`empty-${i}`} className="h-10 sm:h-14"></div>
))}

{days.map((date) => (
<div key={date.day} className="h-14 flex flex-col items-center justify-center relative">
<div key={date.day} className="h-10 sm:h-14 flex flex-col items-center justify-center relative">
<button
onClick={() => setSelectedDate(date.day)}
className={`w-14 h-14 rounded-full flex items-center justify-center text-[15px] font-bold transition-all relative z-10 ${selectedDate === date.day
className={`w-10 h-10 sm:w-14 sm:h-14 rounded-full flex items-center justify-center text-[13px] sm:text-[15px] font-bold transition-all relative z-10 ${selectedDate === date.day
? "bg-emerald-500 text-white shadow-xl shadow-emerald-200 scale-110"
: "text-gray-900 hover:bg-gray-50"
}`}
Expand All @@ -181,10 +181,10 @@ export default function BrandCalendarPage() {
</div>

{/* Right Column: Day Schedule */}
<div className="lg:w-[450px] flex flex-col">
<div className="mb-6 pl-2">
<span className="text-[11px] font-black text-emerald-500 uppercase tracking-[0.2em]">Expected Delivery</span>
<h2 className="text-3xl font-black text-gray-900 mt-2">{monthNames[currentDate.getMonth()]} {selectedDate}, {currentDate.getFullYear()}</h2>
<div className="lg:w-[450px] flex flex-col shrink-0 lg:overflow-y-hidden">
<div className="mb-4 sm:mb-6 pl-2 text-center lg:text-left mt-4 lg:mt-0">
<span className="text-[10px] sm:text-[11px] font-black text-emerald-500 uppercase tracking-[0.2em]">Expected Delivery</span>
<h2 className="text-2xl sm:text-3xl font-black text-gray-900 mt-1 sm:mt-2">{monthNames[currentDate.getMonth()]} {selectedDate}, {currentDate.getFullYear()}</h2>
</div>

<div className="space-y-4 overflow-y-auto pr-2 pb-8 flex-1">
Expand Down
59 changes: 36 additions & 23 deletions apps/web/app/brand-dashboard/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,83 +38,96 @@ export default function BrandDashboardLayout({
{ name: "Overview", href: "/brand-dashboard", icon: LayoutDashboard },
{ name: "Requests", href: "/brand-dashboard/requests", icon: Users, badge: counts.pendingRequestsCount > 0 ? counts.pendingRequestsCount.toString() : undefined },
{ name: "Bookings", href: "/brand-dashboard/bookings", icon: Briefcase },
{ name: "Messages", href: "/brand-dashboard/messages", icon: MessageSquare, badge: counts.unreadMessagesCount > 0 ? counts.unreadMessagesCount.toString() : undefined, badgeColor: "bg-rose-100 text-rose-600" },
{ name: "Messages", href: "/brand-dashboard/messages", icon: MessageSquare, badge: counts.unreadMessagesCount > 0 ? counts.unreadMessagesCount.toString() : undefined, badgeColor: "bg-rose-500 text-white shadow-lg shadow-rose-200" },
{ name: "Calendar", href: "/brand-dashboard/calendar", icon: Calendar },
{ name: "Transactions", href: "/brand-dashboard/transactions", icon: ArrowLeftRight },
];

return (
<RoleGuard allowedRoles={["BRAND"]}>
<div className="flex h-screen bg-[#F1F5F9] overflow-hidden">
<div className="flex h-[100dvh] bg-[#F8FAFC] overflow-hidden font-sans">

{/* Mobile Sidebar Overlay */}
{isSidebarOpen && (
<div
className="fixed inset-0 bg-black/20 z-40 lg:hidden"
className="fixed inset-0 bg-slate-900/40 backdrop-blur-sm z-40 lg:hidden transition-all duration-300"
onClick={() => setIsSidebarOpen(false)}
/>
)}

{/* Sidebar */}
<aside className={`fixed lg:static inset-y-0 left-0 w-64 bg-white border-r border-gray-100 flex flex-col py-6 shrink-0 transition-transform duration-300 z-50 lg:translate-x-0 ${isSidebarOpen ? "translate-x-0" : "-translate-x-full"}`}>
<div className="flex items-center justify-between px-6 mb-10">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg overflow-hidden shrink-0 flex items-center justify-center bg-gray-50 border border-gray-200">
<Image src="/favicon.ico" alt="Noillin" width={20} height={20} className="object-contain" />
<aside className={`fixed lg:static inset-y-0 left-0 w-72 bg-white border-r border-slate-100 flex flex-col py-6 shrink-0 transition-transform duration-300 ease-in-out z-50 shadow-2xl lg:shadow-none lg:translate-x-0 ${isSidebarOpen ? "translate-x-0" : "-translate-x-full"}`}>
<div className="flex items-center justify-between px-8 mb-10">
<div className="flex items-center gap-3 group cursor-pointer">
<div className="w-9 h-9 rounded-xl overflow-hidden shrink-0 flex items-center justify-center bg-emerald-50 border border-emerald-100 group-hover:shadow-md group-hover:shadow-emerald-100 transition-all">
<Image src="/favicon.ico" alt="Noillin" width={22} height={22} className="object-contain" />
</div>
<span className="font-bold text-gray-900 text-lg tracking-tight">Noillin</span>
<span className="font-black text-slate-900 text-xl tracking-tight">Noillin</span>
</div>
<button className="lg:hidden text-gray-500" onClick={() => setIsSidebarOpen(false)}>
<X className="w-6 h-6" />
<button className="lg:hidden p-2 rounded-lg text-slate-400 hover:bg-slate-50 hover:text-slate-600 transition-colors" onClick={() => setIsSidebarOpen(false)}>
<X className="w-5 h-5" />
</button>
</div>

<nav className="flex flex-col gap-1 flex-1 px-4">
<div className="px-8 mb-4">
<p className="text-[10px] font-black text-slate-400 uppercase tracking-widest">Main Menu</p>
</div>

<nav className="flex flex-col gap-1.5 flex-1 px-4">
{navItems.map((item) => {
const isActive = pathname === item.href;
const Icon = item.icon;
return (
<Link
key={item.name}
href={item.href}
className={`flex items-center justify-between px-3 py-2.5 rounded-xl transition-colors ${isActive ? "bg-emerald-50 text-emerald-600 font-medium" : "text-gray-500 hover:bg-gray-50 hover:text-gray-900"}`}
onClick={() => setIsSidebarOpen(false)}
className={`relative flex items-center justify-between px-4 py-3.5 rounded-2xl transition-all duration-200 group overflow-hidden ${isActive ? "bg-emerald-500 text-white shadow-xl shadow-emerald-500/20" : "text-slate-500 hover:bg-slate-50 hover:text-slate-900"}`}
>
<div className="flex items-center gap-3">
<Icon className="w-5 h-5" />
<span className="text-sm">{item.name}</span>
{isActive && (
<div className="absolute inset-0 bg-gradient-to-r from-emerald-400/0 via-white/10 to-emerald-400/0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-1000" />
)}
<div className="flex items-center gap-3.5 relative z-10">
<Icon className={`w-5 h-5 ${isActive ? "text-white" : "text-slate-400 group-hover:text-emerald-500"} transition-colors`} />
<span className={`text-[14px] ${isActive ? "font-bold" : "font-semibold"}`}>{item.name}</span>
</div>
{item.badge && (
<span className={`${item.badgeColor || "bg-emerald-100 text-emerald-600"} text-xs font-bold px-2 py-0.5 rounded-full`}>
<span className={`relative z-10 ${item.badgeColor || (isActive ? "bg-white/20 text-white" : "bg-emerald-100 text-emerald-600")} text-[10px] font-black px-2.5 py-0.5 rounded-full`}>
{item.badge}
</span>
)}
</Link>
);
})}
</nav>

</aside>

{/* Main Header & Content Area */}
<main className="flex-1 flex flex-col min-w-0 h-screen overflow-hidden">
<main className="flex-1 flex flex-col min-w-0 h-[100dvh] overflow-hidden bg-slate-50/50">
{/* Dashboard Header */}
<DashboardHeader
isFixed={false}
showSidebarToggle={true}
hideLogo={true}
onSidebarToggle={() => setIsSidebarOpen(true)}
>
<div className="flex items-center gap-6">
<div className="flex items-center gap-4 sm:gap-6">
<Link
href="/gig-list"
className="hidden md:flex items-center justify-center bg-emerald-500 hover:bg-emerald-600 text-white px-5 py-2 rounded-xl font-bold text-sm transition-colors shadow-sm"
className="hidden md:flex items-center justify-center bg-emerald-500 hover:bg-emerald-600 text-white px-5 py-2 rounded-xl font-bold text-xs transition-all shadow-lg shadow-emerald-500/20 hover:-translate-y-0.5"
>
Explore gigs
Explore Gigs
</Link>
</div>
</DashboardHeader>

<div className="flex-1 w-full overflow-y-auto pb-10">
{children}
<div className="flex-1 w-full relative">
<div className="absolute inset-0 overflow-y-auto">
<div className="min-h-full pb-6">
{children}
</div>
</div>
</div>
</main>

Expand Down
Loading
Loading