# Ad Campaign Previewer Plan

## Goal
Add a live ad campaign previewer to the campaign submission form so advertisers can see the sponsored card before submitting and paying. Work should happen in a separate git worktree, with the current `.env` copied into that worktree.

## Worktree Setup
Use the `using-git-worktrees` skill workflow during implementation.

1. Detect whether the current checkout is already an isolated linked worktree.
2. If not already isolated, create a worktree with the native worktree mechanism if available; otherwise use git fallback.
3. Prefer the repo-local ignored `.worktrees/` directory if available or safe; otherwise use the skill's fallback directory selection.
4. Use branch name `feat/ad-campaign-preview`.
5. Copy local environment variables into the worktree:
   - `cp .env <worktree-path>/.env`
6. Install dependencies in the worktree:
   - `bun install`
7. If an `amp` root-directory workflow needs a shortcut, create it as a local shell alias or local symlink outside committed source files. Do not add repo files for that unless the user gives a concrete target.

## Implementation

### 1. Reuse The Real Ad Card Shape
Modify `src/components/ads/ad-card.tsx` so the production card can also render as a preview-only card:
- Add optional preview props for disabled navigation and image placeholder rendering.
- Keep the default production behavior unchanged for real feed ads.
- Preserve the same visual structure for preview and production cards.

Modify `src/components/ads/advertise-form.tsx` to import and render `AdCard` for the live preview.

Do not use `src/components/ads/feed-ad-slot.tsx`; that component records impressions/clicks and preview rendering must stay analytics-free.

### 2. Add Lightweight Preview State
Keep the existing submit flow based on `FormData` intact. Add minimal controlled state only for preview fields:
- `title`
- `description`
- `destinationUrl`
- `imagePreviewUrl`

Wire `onChange` handlers to the existing title, destination URL, description, and file input. Do not refactor unrelated fields into controlled inputs.

Use fallback preview values until the user enters real copy, for example localized placeholders for title, description, and URL.

### 3. Manage Image Object URLs Safely
When the selected image changes:
- Revoke the previous preview URL if one exists.
- Create a new object URL with `URL.createObjectURL(file)`.
- Store it for the preview image.
- Revoke it on component unmount.

The existing `imageFile` state should remain the source for upload/submission validation.

### 4. Add Preview UI To The Form
Add a new localized `Ad preview` section inside `AdvertiseForm`, after the creative upload area and before package selection.

Recommended behavior:
- Always show the preview card in the form.
- Use the exact production card shape.
- Use a generic gray placeholder in the image area before an image is uploaded.
- Disable navigation from the preview card so users do not accidentally leave the form.
- Keep the preview responsive as a single card rather than adding desktop/mobile toggles.
- Show only the fields the current production ad card shows: image, title, description, destination behavior, and sponsored labels. Do not add company name or domain display.

Use existing Petdex styles:
- `rounded-3xl`
- `border-border-base`
- `bg-surface/76` or `bg-background`
- mono uppercase labels
- semantic Tailwind tokens from `src/app/globals.css`

Ensure the preview fits the existing `AdvertiseForm` width in `src/app/[locale]/advertise/page.tsx`, which currently places the form in a `440px` right column on large screens.

### 5. Add Translation Keys
Update all locale message files:
- `src/i18n/messages/en.json`
- `src/i18n/messages/es.json`
- `src/i18n/messages/zh.json`

Add keys under `advertise.form`, likely:
- `previewTitle`
- `previewHelp`
- `previewEmptyTitle`
- `previewEmptyBody`
- `previewFallbackTitle`
- `previewFallbackDescription`

### 6. Add A Lightweight Regression Test
Add a Bun source-contract test near existing component tests, likely:
- `src/components/ads/advertise-form.test.ts`

Assert that:
- `AdvertiseForm` renders/contains the localized preview section path.
- The preview uses `AdCard` rather than `FeedAdSlot`.
- Preview navigation is disabled via the new `AdCard` preview prop.

Keep existing `advertise.card` keys unchanged unless the preview exposes missing card copy.

## Verification
Run these from the new worktree:
1. `bun run check`
2. `bun run i18n:check`
3. `bun test src/components/ads/advertise-form.test.ts`
4. `bun run build`

Manual verification:
1. Start the app with `bun run dev` using the copied `.env`, or `bun run dev:mock` if real services are not needed for visual verification.
2. Visit `/en/advertise`.
3. Confirm the preview updates when typing title, description, and destination URL.
4. Confirm uploading PNG/JPG/WebP creative immediately updates the preview image.
5. Confirm replacing the image updates the preview without browser console errors.
6. Confirm the form still requires an image, submits the campaign, uploads the creative, and continues to Stripe checkout.
7. Check mobile width to ensure the preview remains readable and does not overflow.

## Notes
- `AdCard` imports `next/image`; object URLs should work for local preview rendering, but verify this in the browser. If Next image handling rejects blob URLs, add a small preview-only presentational component that mirrors `AdCard` markup using a plain `<img>` only for preview.
- Do not add tracking hooks, impression beacons, or click analytics to the preview.
- Do not commit `.env`; it is ignored by `.gitignore`.
