# Dealer Dashboard

## Overview

The dealer dashboard at `/dashboard` is the central hub for AMSOIL dealers to manage their landing page sites. This documentation covers the non-editor features; for CMS and page editing features, see [DEALER_EDITORS.md](./DEALER_EDITORS.md).

## User Journey Overview

```mermaid
flowchart TD
    subgraph Dashboard["Dashboard Home"]
        HOME["/dashboard"]
    end

    subgraph Editors["Content Editors"]
        BASIC["Basic Editor"]
        SLIDER["Slider Editor<br/>(Enhanced+)"]
        PAGES["Pages Editor<br/>(Professional)"]
        MENU["Menu Editor<br/>(Enhanced+)"]
        LINKS["Quick Links<br/>(Growth+)"]
        MEDIA["Media Library<br/>(Starter+)"]
    end

    subgraph Management["Management Features"]
        LEADS["Lead Management<br/>(Growth+)"]
        STATS["Site Analytics<br/>(Enhanced+)"]
        SETTINGS["Settings"]
        DOMAINS["Domain Config<br/>(Growth+)"]
        SUBSCRIPTION["Subscription"]
    end

    subgraph Preview["Site Preview"]
        PREVIEW["/dashboard/preview"]
    end

    HOME --> BASIC
    HOME --> SLIDER
    HOME --> PAGES
    HOME --> MENU
    HOME --> LINKS
    HOME --> MEDIA
    HOME --> LEADS
    HOME --> STATS
    HOME --> SETTINGS
    HOME --> SUBSCRIPTION
    HOME --> PREVIEW

    SETTINGS --> DOMAINS

    %% Tier gating indicated by labels
    classDef tierGated fill:#fff3cd,stroke:#ffc107
    class SLIDER,PAGES,MENU,STATS tierGated
    classDef growthGated fill:#d4edda,stroke:#28a745
    class LEADS,LINKS,MEDIA,DOMAINS growthGated
```

## Architecture

### Layout Structure

The dashboard uses a shared layout (`app/dashboard/layout.tsx`) that provides:

- **Header** - "AMSOIL Dealer Lead Pages" branding with welcome message
- **Profile Dropdown** - User account menu (top-right)
- **Admin Button** - Visible only to admin/superadmin users (hidden during impersonation)
- **Floating Publish Button** - Appears on `/dashboard` for unpublished sites
- **Impersonation Banner** - Shows when admin is impersonating a dealer

### Authentication Flow

1. All dashboard routes require authentication via NextAuth
2. Unauthenticated users are redirected to `/api/auth/signin`
3. Users without a dealer account see the `NoDealerSetup` component
4. Admins can access the dashboard without a dealer account

### API Pattern

Dashboard pages typically:

1. Fetch data from `/api/dealer/*` or `/api/dealers/*` endpoints
2. Check tier restrictions before displaying features
3. Show `TierGate` component when feature access is denied

## Tier-Based Feature Access

| Feature                    | Starter | Growth | Enhanced | Professional |
| -------------------------- | ------- | ------ | -------- | ------------ |
| Dashboard Home             | Yes     | Yes    | Yes      | Yes          |
| Basic Editor               | Yes     | Yes    | Yes      | Yes          |
| Preview Site               | Yes     | Yes    | Yes      | Yes          |
| Subscription Management    | Yes     | Yes    | Yes      | Yes          |
| Lead Management            | No      | Yes    | Yes      | Yes          |
| Custom Domains             | No      | Yes    | Yes      | Yes          |
| Site Analytics             | No      | No     | Yes      | Yes          |
| Performance Metrics Widget | No      | No     | Yes      | Yes          |

## Dashboard Pages

### Dashboard Home (`/dashboard`)

**File:** `app/dashboard/page.tsx`

The main dashboard landing page displays:

#### Quick Access Grid

Navigation buttons to all editing and management features:

- **Basic Editor** - Edit dealer business information
- **Slider Editor** - Configure hero slider (Enhanced+)
- **Pages Editor** - Create and manage CMS pages (Professional)
- **Menu Editor** - Configure site navigation (Enhanced+)
- **Quick Links** - Manage footer quick links (Growth+)
- **Leads** - View and manage form submissions (Growth+)
- **Media Library** - Manage uploaded images (Starter+)

#### Performance Metrics Widget

**Component:** `components/dashboard/PerformanceMetrics.tsx`

- Shows traffic and inquiry metrics for the last 30 days
- Links to full analytics page (`/dashboard/stats`)
- Displays upgrade prompt for Starter/Growth tiers
- Fetches data from `/api/stats/dashboard?period=30d`

#### Setup/Publish Prompts

- **Setup Complete Alert** - Shows when `?setup=complete` query param is present
- **Ready to Publish Alert** - Shows for unpublished sites (status !== 'active')
- **Published Success Alert** - Shows after publishing (auto-dismisses after 5 seconds)

#### Contact Form

Embedded ClickUp form for dealer support requests.

**API Endpoints Called:**

- `GET /api/dealer` - Fetch dealer info and publish status

---

### Lead Management (`/dashboard/leads`)

**File:** `app/dashboard/leads/page.tsx`

**Tier Requirement:** Growth or above

Displays contact form submissions from the dealer's site.

#### Features

- **Paginated Lead Table** - 20 leads per page with navigation
- **Lead Details** - Date, name, email (mailto link), phone (tel link), message
- **Settings Modal** - Configure lead form behavior
- **Empty State** - Helpful message when no leads exist

#### Lead Form Settings Modal

**Component:** `components/LeadFormSettingsModal.tsx`

Settings include:

- **Enable/Disable Form** - Toggle contact form visibility on site
- **Email Notifications** - Receive email when leads are submitted
- **Custom Notification Email** - Override default contact email
- **Auto-Response** - Send automatic confirmation to leads
- **Auto-Response Content** - Rich text editor for response message

**API Endpoints Called:**

- `GET /api/dealer/leads?page={n}&pageSize=20` - Fetch paginated leads
- `GET /api/dealer/settings` - Fetch lead form settings
- `PUT /api/dealer/settings` - Save lead form settings

**Tier Gate:** Shows upgrade prompt with feature list when accessed by Starter tier.

---

### Settings (`/dashboard/settings`)

**File:** `app/dashboard/settings/page.tsx`

General settings page with expandable accordion sections.

#### Domain Settings Accordion

Expandable section containing:

- Current subdomain display (read-only)
- Custom domain configuration (Growth+)

**Component:** `components/settings/DomainSettingsContent.tsx`

See Domain Configuration section below for details.

**API Endpoints Called:**

- `GET /api/dealer` - Fetch dealer tier info

---

### Domain Configuration (`/dashboard/settings/domains`)

**File:** `app/dashboard/settings/domains/page.tsx`

**Tier Requirement:** Growth or above (or grandfathered custom domain access)

Standalone domain settings page using the same `DomainSettingsContent` component.

#### Features

##### Subdomain Display

- Shows current subdomain URL with copy button
- Subdomain is read-only after dealer creation

##### Custom Domain Configuration (A-record based)

Three-step setup process:

1. **Enter Domain** - Input your custom domain (e.g., example.com)
2. **Configure DNS** - Add A records (apex + `www`) pointing to our server IP at your registrar
3. **Verify & Activate** - Check DNS and activate; the origin then provisions a Let's Encrypt certificate via certbot

##### DNS Records Required

Custom domains are served from our origin behind Apache, with TLS issued by certbot/Let's Encrypt. Both the apex and `www` must point to the server IP (shown on the dealer's domains page; currently `69.169.111.27`):

| Type | Name | Value                       |
| ---- | ---- | --------------------------- |
| A    | @    | `69.169.111.27` (server IP) |
| A    | www  | `69.169.111.27` (server IP) |

##### Domain Status States

- **pending** - DNS setup incomplete
- **verified** - DNS confirmed, ready to activate
- **active** - Domain is live and serving traffic

##### Migration Banner

Shows for a small number of grandfathered domains set up via older methods (e.g. managed DNS / nameserver delegation), linking to the domain migration wizard.

> **Deprecated:** The migration wizard and its `/api/dealer/custom-domain/migrate` endpoint target an abandoned Cloudflare-for-SaaS CNAME path that was never put into production use. The current and only supported custom-domain flow is **A-record + certbot** (above). This tooling is vestigial and pending cleanup.

**API Endpoints Called:**

- `GET /api/dealer/custom-domain` - Fetch current domain config
- `POST /api/dealer/custom-domain` - Configure new domain
- `POST /api/dealer/custom-domain/verify` - Check DNS configuration
- `POST /api/dealer/custom-domain/activate` - Activate verified domain
- `DELETE /api/dealer/custom-domain` - Remove custom domain

##### Support Triage: Custom Domain Issues

When a dealer reports their custom domain isn't working, the answer is almost always one of the cases below.

**Where to send the dealer:** `/dashboard/settings/domains`. That page shows the server IP to point their A records at (apex `@` + `www`) and the "Check My DNS" button. Direct the dealer to the page rather than reading values out of the database.

**`customDomainStatus` decoder:**

| Value      | What it means                                               | What to tell the dealer                                                                           |
| ---------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `none`     | No custom domain configured yet                             | Enter the custom domain in `/dashboard/settings/domains` to begin                                 |
| `pending`  | Domain entered; DNS records not yet visible to our resolver | Wait for DNS propagation (usually <1h, up to 24h), then click "Check My DNS"                      |
| `verified` | DNS resolved correctly; awaiting activation                 | Click the green activation button on the same page                                                |
| `active`   | Live and serving traffic                                    | Working as expected                                                                               |
| `failed`   | DNS check failed (records wrong or absent)                  | Re-verify the records at the registrar match what the dashboard shows; click "Check My DNS" again |

**"No record found" error:** This is the in-app DNS-check failure when the records the dealer added at their registrar haven't propagated to our resolver, OR when they were added with the wrong type/name/value. Most common causes: (a) propagation delay - wait, then re-check; (b) wrong value at the registrar - compare exactly with what the dashboard shows; (c) registrar UI added the apex domain to the value (e.g., `<value>.greenwaydist.com` instead of `<value>`).

**A records are the standard flow:** Custom domains point apex (`@`) + `www` A records at the server IP `69.169.111.27`; the origin then provisions a Let's Encrypt cert via certbot. If a dealer asks "what value do I put in GoDaddy?", the answer is `69.169.111.27` for both the apex (`@`) and `www` A records.

**Legacy managed-DNS dealers:** A small number of older dealers were set up via nameserver delegation (managed DNS). These are grandfathered; all new custom domains use the A-record + certbot flow above.

---

### Domain Migration (`/dashboard/settings/domains/migrate`)

**File:** `app/dashboard/settings/domains/migrate/page.tsx`

**Component:** `components/settings/DomainMigrationWizard.tsx`

> **Deprecated - do not direct dealers here.** This wizard was built to move legacy domains onto a Cloudflare-for-SaaS CNAME system that was never adopted in production. The supported custom-domain flow is A-record + certbot (see above); this page and its `migrate` endpoint are vestigial and pending removal.

Step-by-step wizard that was intended to migrate legacy custom domains to a Cloudflare-for-SaaS CNAME setup (abandoned).

#### Wizard Steps

1. **Intro** - Explanation of what's changing and benefits
2. **Instructions** - Step-by-step DNS update guide
3. **Verify** - Check if CNAME is configured
4. **Migrating** - Processing state
5. **Complete** - Success confirmation

#### Migration Types

- **Managed DNS** - Previous nameserver delegation
- **Self-Managed** - Previous A record pointing

**API Endpoints Called:**

- `GET /api/dealer/custom-domain/migrate` - Check migration status
- `POST /api/dealer/custom-domain/migrate` - Perform migration

---

### Subscription Management (`/dashboard/subscription`)

**File:** `app/dashboard/subscription/page.tsx`

Central hub for managing billing and subscription tier.

#### Current Subscription Card

Displays:

- Current plan name (Starter/Growth/Enhanced/Professional)
- Account status (Active/Pending/Payment Issue/Suspended/Cancelled)
- Billing interval (Monthly/Annual) when applicable
- Status-specific alerts for payment issues

#### Plan Comparison Table

**Component:** `components/subscription/PlanComparison.tsx`

- Full feature comparison across all tiers
- Current plan highlighted with badge
- Upgrade buttons for higher tiers
- Downgrade buttons for lower tiers (with confirmation)
- Modal confirmation for tier changes with proration info

#### Billing Interval Toggle (Sidegrade)

**Component:** `components/subscription/SidegradeToggle.tsx`

- Available for tiers with both monthly and annual options
- Toggle between billing intervals without changing tier

#### Billing Management

Actions that redirect to Stripe Customer Portal:

- Update payment method
- View invoice history
- Update billing address

#### Status Alerts

Contextual alerts based on URL query parameters:

- `?upgraded=true` - Upgrade success message
- `?downgraded=true` - Downgrade complete message
- `?sidegraded=true` - Billing interval changed
- `?upgrade_cancelled=true` - Upgrade was cancelled
- `?partialSuccess=true` - May need page refresh
- `?reactivated=1` - Reactivation checkout completed; shows a confirmation banner and suppresses the Reactivate CTA while the webhook finishes flipping the dealer back to `active` (prevents double-subscribing)

**Self-serve reactivation:** Cancelled dealers see a billing-interval picker and a **Reactivate** CTA that starts a new Stripe Checkout session on their prior tier. On return (`?reactivated=1`) the dealer is restored to `active` once `customer.subscription.created` fires. See [Admin Status Management](./ADMIN_STATUS_MANAGEMENT.md) for the `cancelled → active` transition.

**API Endpoints Called:**

- `GET /api/dealers/current` - Fetch dealer and subscription info
- `POST /api/checkout/upgrade` - Initiate upgrade
- `POST /api/subscription/downgrade` - Process downgrade
- `POST /api/subscription/sidegrade` - Change billing interval
- `POST /api/subscription/reactivate` - Start a Checkout session to reactivate a cancelled dealer on their prior tier
- `GET /api/subscription/portal` - Redirect to Stripe portal

---

### Site Analytics (`/dashboard/stats`)

**File:** `app/dashboard/stats/page.tsx`

**Tier Requirement:** Enhanced or above

Detailed analytics for dealer site performance.

#### Period Selection

**Component:** `components/dashboard/PeriodSelector.tsx`

Options:

- Last 7 days
- Last 30 days
- Last 90 days
- Year to date
- Custom date range

#### Overview Metrics

- **Traffic** - Total pageviews with period comparison
- **Inquiries** - Form submissions with period comparison

#### Link Clicks by Category

Four clickable category cards:

- **AMSOIL Links** - Clicks to AMSOIL shop/products
- **Internal Links** - Site navigation clicks
- **Social Links** - Social media link clicks
- **External Links** - Other outbound clicks

Each card shows:

- Current period count
- Percent change from previous period
- Expandable top links breakdown (top 10)

#### Top Links Panel

When a category is selected, displays ranked list of most-clicked links with click counts.

**API Endpoints Called:**

- `GET /api/stats/dashboard?period={period}&includeTopLinks=true` - Fetch all metrics

**Tier Gate:** Shows upgrade prompt with feature list when accessed by Starter/Growth tier.

---

### Site Preview (`/dashboard/preview`)

**File:** `app/dashboard/preview/page.tsx`

Server-rendered preview of the dealer's public site.

#### Features

- Full site preview using `DealerTemplate` component
- Preview banner for unpublished sites with:
  - "PREVIEW MODE" badge
  - Publish button
  - Back to Dashboard link
- Lead form enabled based on tier and settings
- Fetches navigation and quick links from database
- The displayed site name mirrors exactly what visitors see: with no
  business name set, the contact name is used only when "Show contact
  name" is enabled; otherwise the generic "AMSOIL Independent Dealer"
  appears (the public privacy gate in `lib/dealer-display-name.ts`)

#### Data Fetching

Server-side fetch of:

- Dealer record with all display fields
- Navigation items with children
- Quick links
- Lead form settings

**Component Used:**

- `components/DealerTemplate.tsx` - Full site template
- `components/PreviewPublishButton.tsx` - Publish action button

---

## Key Components

### TierGate

**Component:** `components/ui/TierGate.tsx`

Displays upgrade prompt when feature access is denied.

Props:

- `title` - Feature name
- `description` - What the feature does
- `features` - Array of feature benefits
- `requiredTier` - Minimum tier needed
- `backLink` - Optional return navigation

### PerformanceMetrics

**Component:** `components/dashboard/PerformanceMetrics.tsx`

Compact analytics widget for dashboard home.

- Fixed 30-day period
- Links to full stats page
- Shows upgrade prompt for lower tiers

### MetricCard

**Component:** `components/dashboard/MetricCard.tsx`

Individual metric display with:

- Label and value
- Sub-label description
- Percent change indicator (positive/negative)

### PeriodSelector

**Component:** `components/dashboard/PeriodSelector.tsx`

Dropdown for selecting analytics time period.

- Preset periods (7d, 30d, 90d, YTD)
- Custom date range picker

---

## API Reference

### Dealer Info

| Endpoint               | Method | Description                          |
| ---------------------- | ------ | ------------------------------------ |
| `/api/dealer`          | GET    | Get current dealer info              |
| `/api/dealers/current` | GET    | Get dealer with subscription details |
| `/api/dealer/settings` | GET    | Get dealer settings                  |
| `/api/dealer/settings` | PUT    | Update dealer settings               |

### Leads

| Endpoint            | Method | Description         |
| ------------------- | ------ | ------------------- |
| `/api/dealer/leads` | GET    | Get paginated leads |

### Custom Domain

| Endpoint                             | Method | Description            |
| ------------------------------------ | ------ | ---------------------- |
| `/api/dealer/custom-domain`          | GET    | Get domain config      |
| `/api/dealer/custom-domain`          | POST   | Configure new domain   |
| `/api/dealer/custom-domain`          | DELETE | Remove domain          |
| `/api/dealer/custom-domain/verify`   | POST   | Check DNS              |
| `/api/dealer/custom-domain/activate` | POST   | Activate domain        |
| `/api/dealer/custom-domain/migrate`  | GET    | Check migration status |
| `/api/dealer/custom-domain/migrate`  | POST   | Perform migration      |

### Subscription

| Endpoint                       | Method | Description                 |
| ------------------------------ | ------ | --------------------------- |
| `/api/checkout/upgrade`        | POST   | Upgrade tier                |
| `/api/subscription/downgrade`  | POST   | Downgrade tier              |
| `/api/subscription/sidegrade`  | POST   | Change billing interval     |
| `/api/subscription/reactivate` | POST   | Reactivate cancelled dealer |
| `/api/subscription/portal`     | GET    | Redirect to Stripe portal   |

### Analytics

| Endpoint               | Method | Description       |
| ---------------------- | ------ | ----------------- |
| `/api/stats/dashboard` | GET    | Dashboard metrics |

---

## Tier Access Functions

Located in `lib/cms/types.ts`:

| Function                                     | Description              |
| -------------------------------------------- | ------------------------ |
| `hasLeadFormAccess(tier)`                    | Growth+                  |
| `hasCustomDomainAccess(tier, grandfathered)` | Growth+ or grandfathered |
| `hasSliderEditorAccess(tier)`                | Enhanced+                |
| `hasNavEditorAccess(tier)`                   | Enhanced+                |
| `hasCMSAccess(tier)`                         | Professional only        |
| `hasMediaLibraryAccess(tier)`                | Starter+                 |

---

## Related Documentation

- [DEALER_EDITORS.md](./DEALER_EDITORS.md) - CMS and page editing features
- [STYLING_GUIDE.md](./STYLING_GUIDE.md) - Dashboard styling patterns
- [STATS_API.md](./STATS_API.md) - Analytics API details
- [EMAIL_SERVICE.md](./EMAIL_SERVICE.md) - Lead notification emails
