@fayz-ai/plugin-marketing 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAO/F,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,WAAW,CAAA;AAClB,OAAO,KAAK,EACV,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,cAAc,CAAA;AAIrB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAOjE,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAA;AACvE,OAAO,EAAqB,KAAK,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,eAAe,CAAA;AACpG,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAclE,MAAM,WAAW,sBAAsB;IACrC,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IACvC,yEAAyE;IACzE,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,yEAAyE;IACzE,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAA;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,YAAY,CAAC,EAAE,qBAAqB,CAAA;IACpC,6EAA6E;IAC7E,cAAc,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,sBAAsB,CAAA;KAAE,CAAA;IAC1D,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,CAAA;IACxC,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,oEAAoE;IACpE,WAAW,CAAC,EAAE,sBAAsB,CAAA;IACpC;6DACyD;IACzD,QAAQ,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACxE;AA+CD,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,cAAc,CA0TtF;AAED,YAAY,EACV,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,kBAAkB,EAClB,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,eAAe,GAChB,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AACvE,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAA;AACjE,YAAY,EACV,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,aAAa,EACb,UAAU,EACV,UAAU,EACV,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,gCAAgC,EAAE,MAAM,oBAAoB,CAAA;AACrE,OAAO,EAAE,oCAAoC,EAAE,MAAM,wBAAwB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAQ/F,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,WAAW,CAAA;AAClB,OAAO,KAAK,EACV,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,cAAc,CAAA;AAIrB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAOjE,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAA;AACvE,OAAO,EAAqB,KAAK,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,eAAe,CAAA;AACpG,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAclE,MAAM,WAAW,sBAAsB;IACrC,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IACvC,yEAAyE;IACzE,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,yEAAyE;IACzE,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAA;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,YAAY,CAAC,EAAE,qBAAqB,CAAA;IACpC,6EAA6E;IAC7E,cAAc,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,sBAAsB,CAAA;KAAE,CAAA;IAC1D,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,CAAA;IACxC,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,oEAAoE;IACpE,WAAW,CAAC,EAAE,sBAAsB,CAAA;IACpC;6DACyD;IACzD,QAAQ,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACxE;AA+CD,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,cAAc,CAoUtF;AAED,YAAY,EACV,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,kBAAkB,EAClB,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,eAAe,GAChB,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AACvE,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAA;AACjE,YAAY,EACV,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,aAAa,EACb,UAAU,EACV,UAAU,EACV,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,gCAAgC,EAAE,MAAM,oBAAoB,CAAA;AACrE,OAAO,EAAE,oCAAoC,EAAE,MAAM,wBAAwB,CAAA"}
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import React9, { useState, useEffect, useMemo, useCallback } from 'react';
2
2
  import { connectionSettings, connectionStatus, settingsStatus, createConnectionStore, getActiveTenantId, registerTranslations, createSafeDataProvider, getSupabaseClientOptional, useTranslation, useDataChanged, resolveDataProvider } from '@fayz-ai/core';
3
- import { createPluginContext, fayzConnectorOAuth, PluginSettingsPanel, useModuleNavigation, createViewRouter, ModuleActionBar, SettingsGroup, SelectRow, ToggleRow, PermissionGate, useLimitGuard, useOrganizationStore, CrudFormPage, invalidateLimit, CrudListView } from '@fayz-ai/admin';
4
- import { defineKpiWidget, defineCustomWidget, defineTableWidget, ModulePage, PageToolbar, DataTable, SubpageHeader, PageHeaderActions, Button, Skeleton, ConfirmDialog, ContentSplit, ContentSplitTrigger, Input, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, MarkdownEditor, DashboardCanvas, RangeControl, cn, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, SegmentedControl, Badge, SelectSeparator, Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetBody, SheetFooter, Checkbox, toast, KpiCard as KpiCard$1, Card, CardHeader, CardTitle, CardContent, TableWidget } from '@fayz-ai/ui';
3
+ import { createPluginContext, fayzConnectorOAuth, PluginSettingsPanel, useModuleNavigation, createViewRouter, ModuleActionBar, SettingsGroup, SelectRow, ToggleRow, askAI, PermissionGate, QuickActionsButton, useLimitGuard, useOrganizationStore, CrudFormPage, RightRailPage, invalidateLimit, CrudListView } from '@fayz-ai/admin';
4
+ import { defineKpiWidget, defineCustomWidget, defineTableWidget, ModulePage, PageToolbar, DataTable, SubpageHeader, PageHeaderActions, Button, Skeleton, ConfirmDialog, ContentSplit, ContentSplitTrigger, Input, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, MarkdownEditor, DashboardCanvas, RangeControl, cn, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, SheetBody, SegmentedControl, Badge, SheetFooter, SelectSeparator, Checkbox, toast, KpiCard as KpiCard$1, Card, CardHeader, CardTitle, CardContent, TableWidget } from '@fayz-ai/ui';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
- import { History, CheckCircle2, AlertCircle, ChevronRight, Users, Target, Percent, DollarSign, Trash2, Plus, ExternalLink, Sparkles, Pencil, Layers, MousePointerClick, NotebookPen, ArrowUpRight, ArrowDownRight, Settings2, Columns3, CalendarDays, List, ChevronLeft, Loader2, ImagePlus, X, Bike, Utensils, DoorOpen, MessageCircle, Instagram, Mail, Globe, Megaphone, Search, Link2, AtSign, Pin, Twitter, Linkedin, Facebook, Youtube, Music2, Repeat2, Heart, BarChart2, Share2, ThumbsUp, Send, MoreHorizontal, Bookmark, GripVertical, Image, Trophy } from 'lucide-react';
6
+ import { History, CheckCircle2, AlertCircle, ChevronRight, Users, Target, Percent, DollarSign, Trash2, ExternalLink, Sparkles, Pencil, Plus, Layers, MousePointerClick, NotebookPen, ArrowUpRight, ArrowDownRight, Settings2, Columns3, CalendarDays, List, ChevronLeft, Loader2, ImagePlus, X, Bike, Utensils, DoorOpen, MessageCircle, Instagram, Mail, Globe, Megaphone, Search, Link2, AtSign, Pin, Twitter, Linkedin, Facebook, Youtube, Music2, Repeat2, Heart, BarChart2, Share2, ThumbsUp, Send, MoreHorizontal, Bookmark, GripVertical, Image, Trophy } from 'lucide-react';
7
7
  import { createStore } from 'zustand/vanilla';
8
8
 
9
9
  // src/index.ts
@@ -350,12 +350,41 @@ function CampaignsView() {
350
350
  )
351
351
  }
352
352
  ], [t, conversion.labelPlural, currency, deleteCampaign]);
353
+ const createActions = React9.useMemo(() => [
354
+ {
355
+ id: "with-ai",
356
+ label: t("assistant.askAI"),
357
+ description: t("marketing.campaigns.aiHint"),
358
+ icon: "WandSparkles",
359
+ highlight: true,
360
+ action: () => askAI({
361
+ hint: t("marketing.campaigns.askPlaceholder"),
362
+ intro: {
363
+ role: "growth",
364
+ persona: t("marketing.campaigns.askPersona"),
365
+ pitch: t("marketing.campaigns.askPitch"),
366
+ description: t("marketing.campaigns.askDescription"),
367
+ suggestions: [0, 1, 2].map((i) => ({ label: t(`marketing.campaigns.askSuggestion.${i}`) }))
368
+ }
369
+ })
370
+ },
371
+ {
372
+ id: "by-hand",
373
+ label: t("marketing.campaigns.newByHand"),
374
+ description: t("marketing.campaigns.newByHandHint"),
375
+ icon: "SlidersHorizontal",
376
+ action: () => setComposerOpen(true)
377
+ }
378
+ ], [t]);
353
379
  return /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-6xl space-y-4", children: [
354
- /* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx(PermissionGate, { feature: "marketing", action: "create", children: /* @__PURE__ */ jsxs(Button, { onClick: () => setComposerOpen(true), children: [
355
- /* @__PURE__ */ jsx(Plus, { className: "mr-1.5 h-4 w-4" }),
356
- " ",
357
- t("marketing.campaigns.new")
358
- ] }) }) }),
380
+ /* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx(PermissionGate, { feature: "marketing", action: "create", children: /* @__PURE__ */ jsx(
381
+ QuickActionsButton,
382
+ {
383
+ label: t("marketing.campaigns.new"),
384
+ variant: "default",
385
+ actions: createActions
386
+ }
387
+ ) }) }),
359
388
  /* @__PURE__ */ jsx(PageToolbar, { range: /* @__PURE__ */ jsx(RangeTabs, {}) }),
360
389
  /* @__PURE__ */ jsx(DataTable, { columns, data: campaigns, emptyMessage: t("marketing.campaigns.empty") }),
361
390
  /* @__PURE__ */ jsx(CampaignComposer, { open: composerOpen, onClose: () => setComposerOpen(false) })
@@ -464,113 +493,128 @@ function LandingPageComposer({
464
493
  setSaving(false);
465
494
  }
466
495
  }
467
- return /* @__PURE__ */ jsx(Modal, { open, onOpenChange: (o) => {
468
- if (!o) onClose();
469
- }, children: /* @__PURE__ */ jsxs(ModalContent, { size: "md", children: [
470
- /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(ModalTitle, { children: page ? t("marketing.landing.edit") : t("marketing.landing.new") }) }),
471
- /* @__PURE__ */ jsxs(ModalBody, { className: "space-y-4", children: [
472
- /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
473
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.site") }),
474
- /* @__PURE__ */ jsxs(Select, { value: siteId, onValueChange: setSiteId, children: [
475
- /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("marketing.landing.sitePlaceholder") }) }),
476
- /* @__PURE__ */ jsx(SelectContent, { children: sites.map((s) => /* @__PURE__ */ jsx(SelectItem, { value: s.id, children: s.url ? `${s.name} \xB7 ${s.url.replace(/^https?:\/\//, "")}` : s.name }, s.id)) })
477
- ] })
478
- ] }),
479
- /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
480
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.name") }),
481
- /* @__PURE__ */ jsx(Input, { value: name, onChange: (e) => setName(e.target.value), placeholder: t("marketing.landing.namePlaceholder") })
482
- ] }),
483
- /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
484
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.route") }),
485
- /* @__PURE__ */ jsx(Input, { value: route, onChange: (e) => setRoute(e.target.value), placeholder: "/lp-capilar" }),
486
- site?.url && previewPath ? /* @__PURE__ */ jsxs("span", { className: "block text-xs text-muted-foreground", children: [
487
- site.url.replace(/\/+$/, ""),
488
- previewPath
489
- ] }) : null
490
- ] }),
491
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
492
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.status") }),
493
- /* @__PURE__ */ jsx(
494
- SegmentedControl,
495
- {
496
- value: status,
497
- onChange: (v) => setStatus(v),
498
- options: [
499
- { value: "live", label: t("marketing.landing.statusLive") },
500
- { value: "planned", label: t("marketing.landing.statusPlanned") }
501
- ]
502
- }
503
- )
504
- ] }),
505
- status === "planned" ? /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
506
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
507
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.prompt") }),
508
- site?.editorUrl ? /* @__PURE__ */ jsxs(
509
- "button",
510
- {
511
- type: "button",
512
- onClick: () => window.open(site.editorUrl, "_blank", "noopener,noreferrer"),
513
- className: "inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline",
514
- children: [
515
- /* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5" }),
516
- " ",
517
- t("marketing.landing.buildWithFayz")
518
- ]
519
- }
520
- ) : null
521
- ] }),
522
- /* @__PURE__ */ jsx(
523
- "textarea",
524
- {
525
- value: prompt,
526
- onChange: (e) => setPrompt(e.target.value),
527
- rows: 3,
528
- placeholder: t("marketing.landing.promptPlaceholder"),
529
- className: "w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring"
530
- }
531
- )
532
- ] }) : null,
533
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
534
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.leadTag") }),
535
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5 rounded-md border border-border bg-background px-2 py-2 focus-within:ring-2 focus-within:ring-ring", children: [
536
- options.map((opt) => {
537
- const active = tags.includes(opt.slug);
538
- return /* @__PURE__ */ jsx(
539
- Badge,
540
- {
541
- variant: active ? "default" : "outline",
542
- className: "cursor-pointer text-xs",
543
- onClick: () => toggleTag(opt.slug),
544
- children: opt.label
545
- },
546
- opt.slug
547
- );
548
- }),
549
- /* @__PURE__ */ jsx(
550
- "input",
551
- {
552
- value: newTag,
553
- onChange: (e) => setNewTag(e.target.value),
554
- onKeyDown: (e) => {
555
- if (e.key === "Enter") {
556
- e.preventDefault();
557
- addTag();
496
+ return (
497
+ // Beside the list, not over it: the routes already taken are what you check
498
+ // a new one against, and the dialog covered them.
499
+ /* @__PURE__ */ jsxs(
500
+ RightRailPage,
501
+ {
502
+ title: page ? page.name || t("marketing.landing.edit") : t("marketing.landing.new"),
503
+ open,
504
+ onClose,
505
+ width: "max-w-md",
506
+ children: [
507
+ /* @__PURE__ */ jsxs(SheetBody, { className: "space-y-4", children: [
508
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
509
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.site") }),
510
+ /* @__PURE__ */ jsxs(Select, { value: siteId, onValueChange: setSiteId, children: [
511
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("marketing.landing.sitePlaceholder") }) }),
512
+ /* @__PURE__ */ jsx(SelectContent, { children: sites.map((s) => /* @__PURE__ */ jsx(SelectItem, { value: s.id, children: s.url ? `${s.name} \xB7 ${s.url.replace(/^https?:\/\//, "")}` : s.name }, s.id)) })
513
+ ] })
514
+ ] }),
515
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
516
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.name") }),
517
+ /* @__PURE__ */ jsx(Input, { value: name, onChange: (e) => setName(e.target.value), placeholder: t("marketing.landing.namePlaceholder") })
518
+ ] }),
519
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
520
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.route") }),
521
+ /* @__PURE__ */ jsx(Input, { value: route, onChange: (e) => setRoute(e.target.value), placeholder: "/lp-capilar" }),
522
+ site?.url && previewPath ? /* @__PURE__ */ jsxs("span", { className: "block text-xs text-muted-foreground", children: [
523
+ site.url.replace(/\/+$/, ""),
524
+ previewPath
525
+ ] }) : null
526
+ ] }),
527
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
528
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.status") }),
529
+ /* @__PURE__ */ jsx(
530
+ SegmentedControl,
531
+ {
532
+ value: status,
533
+ onChange: (v) => setStatus(v),
534
+ options: [
535
+ { value: "live", label: t("marketing.landing.statusLive") },
536
+ { value: "planned", label: t("marketing.landing.statusPlanned") }
537
+ ]
538
+ }
539
+ )
540
+ ] }),
541
+ status === "planned" ? /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
542
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
543
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.prompt") }),
544
+ site?.editorUrl ? /* @__PURE__ */ jsxs(
545
+ "button",
546
+ {
547
+ type: "button",
548
+ onClick: () => window.open(site.editorUrl, "_blank", "noopener,noreferrer"),
549
+ className: "inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline",
550
+ children: [
551
+ /* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5" }),
552
+ " ",
553
+ t("marketing.landing.buildWithFayz")
554
+ ]
555
+ }
556
+ ) : null
557
+ ] }),
558
+ /* @__PURE__ */ jsx(
559
+ "textarea",
560
+ {
561
+ value: prompt,
562
+ onChange: (e) => setPrompt(e.target.value),
563
+ rows: 3,
564
+ placeholder: t("marketing.landing.promptPlaceholder"),
565
+ className: "w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring"
558
566
  }
559
- },
560
- onBlur: addTag,
561
- placeholder: t("marketing.landing.leadTagPlaceholder"),
562
- className: "min-w-[8rem] flex-1 border-0 bg-transparent px-1 text-xs text-foreground outline-none placeholder:text-muted-foreground"
567
+ )
568
+ ] }) : null,
569
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
570
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t("marketing.landing.leadTag") }),
571
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5 rounded-md border border-border bg-background px-2 py-2 focus-within:ring-2 focus-within:ring-ring", children: [
572
+ options.map((opt) => {
573
+ const active = tags.includes(opt.slug);
574
+ return /* @__PURE__ */ jsx(
575
+ Badge,
576
+ {
577
+ variant: active ? "default" : "outline",
578
+ className: "cursor-pointer text-xs",
579
+ onClick: () => toggleTag(opt.slug),
580
+ children: opt.label
581
+ },
582
+ opt.slug
583
+ );
584
+ }),
585
+ /* @__PURE__ */ jsx(
586
+ "input",
587
+ {
588
+ value: newTag,
589
+ onChange: (e) => setNewTag(e.target.value),
590
+ onKeyDown: (e) => {
591
+ if (e.key === "Enter") {
592
+ e.preventDefault();
593
+ addTag();
594
+ }
595
+ },
596
+ onBlur: addTag,
597
+ placeholder: t("marketing.landing.leadTagPlaceholder"),
598
+ className: "min-w-[8rem] flex-1 border-0 bg-transparent px-1 text-xs text-foreground outline-none placeholder:text-muted-foreground"
599
+ }
600
+ )
601
+ ] }),
602
+ /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: t("marketing.landing.leadTagHint") })
603
+ ] })
604
+ ] }),
605
+ /* @__PURE__ */ jsx(SheetFooter, { children: /* @__PURE__ */ jsx(
606
+ Button,
607
+ {
608
+ className: "flex-1",
609
+ onClick: handleSave,
610
+ disabled: saving || !siteId || !name.trim() || !route.trim(),
611
+ children: page ? t("marketing.landing.save") : t("marketing.landing.create")
563
612
  }
564
- )
565
- ] }),
566
- /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: t("marketing.landing.leadTagHint") })
567
- ] })
568
- ] }),
569
- /* @__PURE__ */ jsxs(ModalFooter, { children: [
570
- /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onClose, children: t("marketing.composer.cancel") }),
571
- /* @__PURE__ */ jsx(Button, { onClick: handleSave, disabled: saving || !siteId || !name.trim() || !route.trim(), children: page ? t("marketing.landing.save") : t("marketing.landing.create") })
572
- ] })
573
- ] }) });
613
+ ) })
614
+ ]
615
+ }
616
+ )
617
+ );
574
618
  }
575
619
  function LandingPagesView() {
576
620
  const t = useTranslation();
@@ -995,19 +1039,19 @@ function PlanBriefView({ onBack }) {
995
1039
  function PlanBriefSheet({ open, onClose }) {
996
1040
  const t = useTranslation();
997
1041
  const { plan, draft, patch, dirty, saving, save } = useBriefDraft();
998
- return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange: (v) => {
999
- if (!v) onClose();
1000
- }, children: /* @__PURE__ */ jsxs(SheetContent, { width: "max-w-2xl", children: [
1001
- /* @__PURE__ */ jsxs(SheetHeader, { children: [
1002
- /* @__PURE__ */ jsx(SheetTitle, { children: t("marketing.content.brief") }),
1003
- plan && /* @__PURE__ */ jsx(SheetDescription, { children: plan.name })
1004
- ] }),
1005
- /* @__PURE__ */ jsx(SheetBody, { children: draft ? /* @__PURE__ */ jsx(BriefFields, { draft, patch }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "\u2026" }) }),
1006
- /* @__PURE__ */ jsxs(SheetFooter, { children: [
1007
- /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onClose, disabled: saving, children: t("marketing.content.cancel") }),
1008
- /* @__PURE__ */ jsx(Button, { onClick: () => void save(), disabled: !dirty || saving, children: t("marketing.content.save") })
1009
- ] })
1010
- ] }) });
1042
+ return /* @__PURE__ */ jsxs(
1043
+ RightRailPage,
1044
+ {
1045
+ title: plan?.name ?? t("marketing.content.brief"),
1046
+ open,
1047
+ onClose,
1048
+ width: "max-w-2xl",
1049
+ children: [
1050
+ /* @__PURE__ */ jsx(SheetBody, { children: draft ? /* @__PURE__ */ jsx(BriefFields, { draft, patch }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "\u2026" }) }),
1051
+ /* @__PURE__ */ jsx(SheetFooter, { children: /* @__PURE__ */ jsx(Button, { className: "flex-1", onClick: () => void save(), disabled: !dirty || saving, children: t("marketing.content.save") }) })
1052
+ ]
1053
+ }
1054
+ );
1011
1055
  }
1012
1056
  var DEFAULT_WEEKS = 8;
1013
1057
  var ADD_ACCOUNT_VALUE = "__add-account__";
@@ -2562,6 +2606,21 @@ function PostsList({ navigate, navTabs }) {
2562
2606
  navTabs,
2563
2607
  activeNavTab: "posts",
2564
2608
  onNew: () => navigate("blog-new"),
2609
+ aiCreate: {
2610
+ hint: "Descreva o post\u2026",
2611
+ description: "Descreva o assunto e eu escrevo o rascunho.",
2612
+ intro: {
2613
+ role: "growth",
2614
+ persona: "Redator do blog",
2615
+ pitch: "Diga sobre o que \xE9 o post.",
2616
+ description: "Escrevo t\xEDtulo, resumo e corpo em markdown, com slug e tempo de leitura. Nasce como rascunho \u2014 voc\xEA l\xEA, ajusta e publica quando quiser.",
2617
+ suggestions: [
2618
+ { label: "Um post sobre cuidados p\xF3s-procedimento" },
2619
+ { label: "Cinco d\xFAvidas frequentes dos clientes, respondidas" },
2620
+ { label: "Um post curto para divulgar a promo\xE7\xE3o do m\xEAs" }
2621
+ ]
2622
+ }
2623
+ },
2565
2624
  addLabel: "New post",
2566
2625
  onRowClick: (row) => navigate(`blog-post:${row.id}`)
2567
2626
  }
@@ -5229,6 +5288,16 @@ var en = {
5229
5288
  "marketing.channels.noCampaigns": "No campaigns yet on this channel.",
5230
5289
  // campaigns
5231
5290
  "marketing.campaigns.subtitle": "All acquisition campaigns and their conversion performance",
5291
+ "marketing.campaigns.aiHint": "Describe the campaign and I set it up.",
5292
+ "marketing.campaigns.newByHand": "Create by hand",
5293
+ "marketing.campaigns.newByHandHint": "Fill in channel, budget and period.",
5294
+ "marketing.campaigns.askPlaceholder": "Describe the campaign\u2026",
5295
+ "marketing.campaigns.askPersona": "Campaign planner",
5296
+ "marketing.campaigns.askPitch": "Tell me the campaign you want to run.",
5297
+ "marketing.campaigns.askDescription": "Goal, channel, how much you mean to spend and for how long \u2014 tell me what you have and I fill the rest sensibly against your history. You confirm before it is created.",
5298
+ "marketing.campaigns.askSuggestion.0": "Instagram campaign for the month, $800",
5299
+ "marketing.campaigns.askSuggestion.1": "Win back clients who have not returned in 90 days",
5300
+ "marketing.campaigns.askSuggestion.2": "Weekend promo on Google",
5232
5301
  "marketing.campaigns.new": "New campaign",
5233
5302
  "marketing.campaigns.empty": "No campaigns yet \u2014 create your first one.",
5234
5303
  "marketing.campaigns.delete": "Delete campaign",
@@ -5423,6 +5492,16 @@ var ptBR = {
5423
5492
  "marketing.channels.noCampaigns": "Nenhuma campanha ainda neste canal.",
5424
5493
  // campaigns
5425
5494
  "marketing.campaigns.subtitle": "Todas as campanhas de aquisi\xE7\xE3o e seu desempenho de convers\xE3o",
5495
+ "marketing.campaigns.aiHint": "Descreva a campanha e eu monto.",
5496
+ "marketing.campaigns.newByHand": "Criar manualmente",
5497
+ "marketing.campaigns.newByHandHint": "Preencher canal, or\xE7amento e per\xEDodo.",
5498
+ "marketing.campaigns.askPlaceholder": "Descreva a campanha\u2026",
5499
+ "marketing.campaigns.askPersona": "Planejador de campanhas",
5500
+ "marketing.campaigns.askPitch": "Diga a campanha que voc\xEA quer rodar.",
5501
+ "marketing.campaigns.askDescription": "Objetivo, canal, quanto pretende gastar e por quanto tempo \u2014 diga o que tiver e eu completo o resto com o que faz sentido para o seu hist\xF3rico. Voc\xEA confirma antes de criar.",
5502
+ "marketing.campaigns.askSuggestion.0": "Campanha de Instagram para o m\xEAs, R$ 800",
5503
+ "marketing.campaigns.askSuggestion.1": "Reativar clientes que n\xE3o voltam h\xE1 90 dias",
5504
+ "marketing.campaigns.askSuggestion.2": "Promo\xE7\xE3o de fim de semana no Google",
5426
5505
  "marketing.campaigns.new": "Nova campanha",
5427
5506
  "marketing.campaigns.empty": "Nenhuma campanha ainda \u2014 crie a primeira.",
5428
5507
  "marketing.campaigns.delete": "Excluir campanha",
@@ -5651,7 +5730,6 @@ function createMarketingPlugin(options) {
5651
5730
  { config, provider: provider2, store: store3 },
5652
5731
  React9.createElement(PluginSettingsPanel, {
5653
5732
  title: config.labels.settings ?? config.labels.pageTitle,
5654
- subtitle: config.labels.pageSubtitle,
5655
5733
  generalSettings: React9.createElement(SettingsView),
5656
5734
  registries: marketingRegistries,
5657
5735
  // Enables the "Integrações" tab (renders manifest connectors for this host).
@@ -5662,6 +5740,7 @@ function createMarketingPlugin(options) {
5662
5740
  SettingsComponent.displayName = "MarketingSettings";
5663
5741
  return {
5664
5742
  id: "marketing",
5743
+ defaultAgentRole: "growth",
5665
5744
  name: options?.navLabel ?? config.labels.pageTitle,
5666
5745
  icon: "Megaphone",
5667
5746
  version: "1.0.0",
@@ -5734,6 +5813,16 @@ function createMarketingPlugin(options) {
5734
5813
  }
5735
5814
  }
5736
5815
  }] : [],
5816
+ // O post do blog é a única entidade daqui que o agente pode ESCREVER: é
5817
+ // um rascunho de texto, o formulário é o mesmo que a pessoa usaria, e a
5818
+ // permissão de create continua sendo cobrada pelas primitivas. Campanha e
5819
+ // post de conteúdo seguem só-leitura — campanha tem RPC própria e o
5820
+ // planner escreve por outro caminho.
5821
+ ...config.modules.blog ? [{
5822
+ key: "marketing:blogPosts",
5823
+ writable: true,
5824
+ entity: buildBlogPostEntity()
5825
+ }] : [],
5737
5826
  ...config.modules.contentPlanner ? [{
5738
5827
  key: "marketing:contentPosts",
5739
5828
  writable: false,