commit 1153e8e78f99eac0a3e4d230827b005afddf3d8c Author: Alireza Hassani Date: Sun Oct 4 13:21:27 2026 +0330 Update carousels, card hover, and IranBay branding. Co-authored-by: Cursor diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e6e967e --- /dev/null +++ b/.env.example @@ -0,0 +1,15 @@ +NEXT_PUBLIC_WEBSITE_URL=http://localhost:3000 +# Meshkee CMS API — always remote (do not point at a local Meshkee) +NEXT_PUBLIC_MESHKEE_API_URL=https://api.meshkee.com/api/v1 +# IranBay marketplace API (local is fine) +NEXT_PUBLIC_MARKETPLACE_API_URL=http://localhost:3001/api/v1 + +# Dashboard hosts (same Next.js app; middleware switches by Host header) +NEXT_PUBLIC_ROOT_DOMAIN=localhost +# Local customer dashboard (shared login): http://customer.localhost:3002 +NEXT_PUBLIC_CUSTOMER_DASHBOARD_HOST=customer.localhost:3002 +# Local business dashboard: http://business.localhost:3002 +NEXT_PUBLIC_BUSINESS_DASHBOARD_HOST=business.localhost:3002 +# Local superadmin dashboard: http://localhost:3002 +NEXT_PUBLIC_ADMIN_DASHBOARD_HOST=localhost:3002 +NEXT_PUBLIC_MESHKEE_TENANT_DOMAIN=iranbay.com diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40543b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files +.env* +!.env.example + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..643577d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,9 @@ + + +# This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices. + +This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean. + + diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..3106044 --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +# Dashboard + +Admin, customer, and business dashboards for IranBay — one Next.js app; the `Host` header picks the experience. + +| Host | App | +|------|-----| +| `http://localhost:3002` (or `admin.`) | Superadmin | +| `http://customer.localhost:3002` (or `customer.`) | Customer account | +| `http://business.localhost:3002` (or `business.`) | Business owner | + +Public site stays on the main domain (`ariyaway.com` → `website/`). + +## Auth model + +- **One shared login** on the customer host (`/login`). +- After login, everyone lands in the **customer** dashboard. Superadmins and + business owners open admin/business from links there. +- If the user **owns a business**, customer UI shows a link to the business dashboard (session handoff across subdomains). +- Visiting `business.*/login` redirects to the customer login. +- Superadmin login stays on the admin host. + +```bash +# 1) Meshkee API (port 3010 — website already uses 3000) +cd "../MeshkeeApp Backend" +docker compose up -d +PORT=3010 npm run start:dev + +# 2) Dashboard +cd ../dashboard +cp .env.example .env.local +npm install +npm run dev +``` + +## Env + +| Variable | Local example | Prod example | +|----------|---------------|--------------| +| `NEXT_PUBLIC_ROOT_DOMAIN` | `localhost` | `ariyaway.com` | +| `NEXT_PUBLIC_CUSTOMER_DASHBOARD_HOST` | `customer.localhost:3002` | `customer.ariyaway.com` | +| `NEXT_PUBLIC_BUSINESS_DASHBOARD_HOST` | `business.localhost:3002` | `business.ariyaway.com` | +| `NEXT_PUBLIC_ADMIN_DASHBOARD_HOST` | `localhost:3002` | `admin.ariyaway.com` | +| `NEXT_PUBLIC_MESHKEE_API_URL` | Meshkee API base | same | +| `NEXT_PUBLIC_MARKETPLACE_API_URL` | `http://localhost:3001/api/v1` | marketplace API | + +Modern browsers resolve `*.localhost` without a hosts file. + +Prod: DNS `customer.*`, `business.*` (and optionally `admin.*`) → same dashboard deploy; TLS for those hosts. + +## Routes + +### Superadmin (`localhost:3002`) + +| Route | Purpose | +|-------|---------| +| `/login` | Super admin login | +| `/` | Admin home | +| `/businesses` | Marketplace listings | + +### Customer (`customer.localhost:3002`) + +| Route | Purpose | +|-------|---------| +| `/login` | Shared customer + business-owner login | +| `/` | Customer home | +| `/profile` | Account profile (read-only for now) | + +### Business (`business.localhost:3002`) + +Clean URLs (rewritten to `app/business/*`). Login redirects to customer host. + +| Route | Purpose | +|-------|---------| +| `/profile` | Meshkee business profile | +| `/products` | Product list | +| `/blog` | Blog list | +| `/portfolios` | Portfolio list | +| `/gallery` | Gallery list | diff --git a/app/auth/handoff/layout.tsx b/app/auth/handoff/layout.tsx new file mode 100644 index 0000000..14b9f29 --- /dev/null +++ b/app/auth/handoff/layout.tsx @@ -0,0 +1,64 @@ +import type { ReactNode } from "react"; + +/** + * Install session from the URL hash BEFORE React AuthProvider runs. + * Cross-subdomain localStorage is empty until this runs; without it, + * ProtectedRoute saw ?businessId= and bounced admins back to /businesses. + */ +const HANDOFF_BOOT = ` +(function () { + try { + var raw = location.hash ? location.hash.replace(/^#/, "") : ""; + if (!raw) return; + var p = new URLSearchParams(raw); + var access = p.get("access"); + var refresh = p.get("refresh"); + var businessId = p.get("businessId"); + var clearManaged = p.get("clearManaged") === "1"; + var next = p.get("next") || "/profile"; + if (!access || !refresh) return; + + localStorage.setItem("marketplace_access_token", access); + localStorage.setItem("marketplace_refresh_token", refresh); + + var root = "localhost"; + try { + // Best-effort shared cookie for *.localhost / prod root + document.cookie = + "marketplace_access_token=" + + encodeURIComponent(access) + + "; Path=/; Max-Age=1209600; SameSite=Lax; Domain=" + + root; + document.cookie = + "marketplace_refresh_token=" + + encodeURIComponent(refresh) + + "; Path=/; Max-Age=1209600; SameSite=Lax; Domain=" + + root; + } catch (e) {} + + if (businessId) { + localStorage.setItem("marketplace_managed_business_id", businessId); + sessionStorage.setItem("marketplace_managed_business_id", businessId); + } else if (clearManaged) { + localStorage.removeItem("marketplace_managed_business_id"); + sessionStorage.removeItem("marketplace_managed_business_id"); + } + + var target = next.charAt(0) === "/" ? next : "/" + next; + location.replace(target); + } catch (e) {} +})(); +`; + +export default function AuthHandoffLayout({ + children, +}: { + children: ReactNode; +}) { + return ( + <> +