Commit Graph
8 Commits
Author SHA1 Message Date
AFFAANhandClaude Opus 5 6962334cbd Merge Phase 1 campaign management
Campaigns page with ad-account billing panel, six-step creation wizard,
and Meta ad preview across six placements.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 23:36:05 +05:30
AFFAANhandClaude Opus 5 66cfa38076 fix(campaigns): preview and review steps showed empty values
Form.useWatch([], form) tracks getFieldsValue(), which returns {} on a step
with no mounted Form.Item. The Preview and Review steps have none, so on
entering Preview the creative memo recomputed to empty and previewed a blank
ad pointing at example.com, and the Review step rendered "-" for every field.
The submitted payload was always correct — submit() reads the preserved store
via getFieldsValue(true) — so this was a display and preview defect, not data
loss. Pass preserve: true so the watch tracks the whole store.

Also document VITE_META_AD_ACCOUNT_ID. Unset, it silently disables the
billing panel, the missing-payment-method warning, ad preview, and the
account-minimum budget check, with no diagnostic anywhere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 19:45:59 +05:30
AFFAANhandClaude Opus 5 39119163c1 fix(campaigns): wizard sent an empty payload; harden preview URL extraction
Critical: only the active wizard step is mounted, so on the Review step no
Form.Items are registered and form.validateFields() resolved to {}. Every
field was dropped and every submit failed validation server-side. Read the
preserved store with getFieldsValue(true) instead, and validate each step's
fields when leaving it so the required rules actually run.

Security: extractSrc matched src=" anywhere in the body with no scheme or
host check, so a data-src attribute or an earlier <img> could hijack the
match, and javascript:/data:/protocol-relative URLs passed through. Combined
with sandbox="allow-same-origin" a javascript: URL would have inherited the
app origin. It now anchors on the iframe tag and accepts only https URLs on
facebook.com/fbcdn.net, failing closed otherwise. Verified against 14 inputs
including both hijack shapes.

Also: memoise the creative object so PreviewStep does not refetch on every
parent render, type the form values, guard the preview effect against stale
responses, reset the wizard on close, and show an explicit message when no
placement renders.

Moving extractSrc to its own module removes the react-refresh lint
suppression rather than hiding it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 18:48:20 +05:30
AFFAANh 07e4c8997e feat(campaigns): add campaign wizard with Meta ad preview 2026-08-02 02:57:41 +05:30
AFFAANh 3d238bcfec feat(campaigns): add campaigns list page with billing panel 2026-08-02 02:41:16 +05:30
AFFAANhandClaude Opus 5 72dcba1e6e fix(campaigns): make budget and guardrails optional in CampaignPayload
PUT /campaigns/{id} is a partial update on the backend, applying only the
fields present in the body. Requiring budget and guardrails in the client
type forced callers to resend both just to change a name. `name` stays
required because the backend request model requires it on POST and PUT.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 02:22:08 +05:30
AFFAANh 8145fcb52d feat(campaigns): add frontend campaign API module and types
Adds the typed API client for campaign management (Task 7): campaign.ts
types, campaignApi module wired to the backend's /campaigns endpoints,
and registration in the aggregated api index. This is the API layer
only; the list page and wizard land in Tasks 8/9.
2026-08-01 14:09:08 +05:30
AFFAANhandClaude Opus 5 b42b7406dc Initial commit: MaskanX frontend
Independent React, TypeScript and Vite web application for MaskanX.

Includes the chat console, agent and persona configuration, MCP client
management, model and provider settings, cron jobs, sessions, and
diagnostics.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 10:28:39 +05:30