@fayz-ai/plugin-marketing 0.9.0 → 0.9.1
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.
- package/README.md +3 -3
- package/dist/{MarketingContext.d.ts → context.d.ts} +5 -3
- package/dist/context.d.ts.map +1 -0
- package/dist/data/mock.d.ts +1 -1
- package/dist/data/mock.d.ts.map +1 -1
- package/dist/{registries.d.ts → data/registries.d.ts} +1 -1
- package/dist/data/registries.d.ts.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -22
- package/dist/index.js.map +1 -1
- package/dist/lib/format.d.ts.map +1 -0
- package/dist/{presets.d.ts → lib/presets.d.ts} +1 -1
- package/dist/lib/presets.d.ts.map +1 -0
- package/dist/{MarketingPage.d.ts → views/MarketingPage.d.ts} +5 -5
- package/dist/views/MarketingPage.d.ts.map +1 -0
- package/dist/views/blog/BlogAdminView.d.ts.map +1 -1
- package/dist/views/content/ContentPlannerContext.d.ts +1 -1
- package/dist/views/content/ContentPlannerContext.d.ts.map +1 -1
- package/dist/views/dashboardWidgets.d.ts +1 -1
- package/dist/views/dashboardWidgets.d.ts.map +1 -1
- package/package.json +6 -9
- package/dist/MarketingContext.d.ts.map +0 -1
- package/dist/MarketingPage.d.ts.map +0 -1
- package/dist/format.d.ts.map +0 -1
- package/dist/presets.d.ts.map +0 -1
- package/dist/registries.d.ts.map +0 -1
- package/src/MarketingContext.tsx +0 -42
- package/src/MarketingPage.tsx +0 -139
- package/src/components/MarketingBits.tsx +0 -131
- package/src/components/icons.tsx +0 -36
- package/src/data/blogEntities.tsx +0 -91
- package/src/data/capability.test.ts +0 -92
- package/src/data/contentMedia.ts +0 -25
- package/src/data/contentMock.ts +0 -253
- package/src/data/contentSupabase.ts +0 -263
- package/src/data/contentTypes.ts +0 -138
- package/src/data/mock.ts +0 -308
- package/src/data/supabase.ts +0 -613
- package/src/data/tables.ts +0 -33
- package/src/data/types.ts +0 -97
- package/src/format.ts +0 -40
- package/src/index.ts +0 -457
- package/src/integrations/ranklayer/RANKLAYER.md +0 -40
- package/src/integrations/ranklayer/connectorDef.tsx +0 -102
- package/src/integrations/ranklayer/data/supabase.ts +0 -106
- package/src/integrations/ranklayer/types.ts +0 -16
- package/src/locales/en.ts +0 -192
- package/src/locales/index.ts +0 -7
- package/src/locales/pt-BR.ts +0 -192
- package/src/migrations/000_plg_rename.sql +0 -15
- package/src/migrations/001_content_planner.sql +0 -94
- package/src/migrations/002_multi_platform.sql +0 -25
- package/src/migrations/003_recording_ops.sql +0 -25
- package/src/migrations/004_ranklayer.sql +0 -50
- package/src/migrations/005_analytics_base.sql +0 -60
- package/src/migrations/006_analytics_views.sql +0 -68
- package/src/migrations/007_agent_rpcs.sql +0 -119
- package/src/migrations/008_landing_pages.sql +0 -112
- package/src/migrations/index.ts +0 -601
- package/src/presets.ts +0 -119
- package/src/registries.ts +0 -62
- package/src/schema/index.ts +0 -106
- package/src/store.ts +0 -102
- package/src/types.ts +0 -153
- package/src/views/CampaignComposer.tsx +0 -89
- package/src/views/CampaignsView.tsx +0 -59
- package/src/views/ChannelDetailView.tsx +0 -59
- package/src/views/ChannelsView.tsx +0 -46
- package/src/views/FunnelView.tsx +0 -56
- package/src/views/LandingPageComposer.tsx +0 -201
- package/src/views/LandingPagesView.tsx +0 -172
- package/src/views/OverviewView.tsx +0 -24
- package/src/views/SettingsView.tsx +0 -72
- package/src/views/blog/BlogAdminView.tsx +0 -99
- package/src/views/blog/BlogEntityForm.tsx +0 -101
- package/src/views/blog/useEntityCrud.ts +0 -50
- package/src/views/content/ContentPlannerContext.tsx +0 -13
- package/src/views/content/ContentView.tsx +0 -908
- package/src/views/content/PlanBriefView.tsx +0 -268
- package/src/views/content/PostPage.tsx +0 -370
- package/src/views/content/PostSocialPreview.tsx +0 -212
- package/src/views/content/RecordingChecklist.tsx +0 -145
- package/src/views/content/contentBits.tsx +0 -114
- package/src/views/content/contentStore.ts +0 -160
- package/src/views/content/templates.ts +0 -172
- package/src/views/dashboardWidgets.tsx +0 -173
- /package/dist/{format.d.ts → lib/format.d.ts} +0 -0
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
// RankLayer as a unified ConnectorDefinition, surfaced in Marketing → settings
|
|
2
|
-
// → Integrações (rendered by the shared ConnectorsHub). SCAFFOLD: the hub gives
|
|
3
|
-
// us the API-key form + Test/Save; the ExtraPanel below explains that automated
|
|
4
|
-
// SEO content sync is being prepared. The real sync lands via an external PR —
|
|
5
|
-
// see ./RANKLAYER.md.
|
|
6
|
-
import React, { useEffect, useState } from 'react'
|
|
7
|
-
import { Sparkles, History, CheckCircle2, AlertCircle } from 'lucide-react'
|
|
8
|
-
import type { ConnectorDefinition } from '@fayz-ai/core'
|
|
9
|
-
import { createRankLayerProvider } from './data/supabase'
|
|
10
|
-
import type { RankLayerIntegration, RankLayerSyncLogEntry } from './types'
|
|
11
|
-
|
|
12
|
-
const provider = createRankLayerProvider()
|
|
13
|
-
|
|
14
|
-
function RankLayerExtraPanel() {
|
|
15
|
-
const [integration, setIntegration] = useState<RankLayerIntegration | null>(null)
|
|
16
|
-
const [log, setLog] = useState<RankLayerSyncLogEntry[]>([])
|
|
17
|
-
const [loaded, setLoaded] = useState(false)
|
|
18
|
-
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
let cancelled = false
|
|
21
|
-
;(async () => {
|
|
22
|
-
try {
|
|
23
|
-
const found = await provider.getIntegration()
|
|
24
|
-
if (cancelled) return
|
|
25
|
-
setIntegration(found)
|
|
26
|
-
if (found) setLog(await provider.getSyncLog(found.id))
|
|
27
|
-
} catch {
|
|
28
|
-
/* not connected / no client — nothing to show */
|
|
29
|
-
} finally {
|
|
30
|
-
if (!cancelled) setLoaded(true)
|
|
31
|
-
}
|
|
32
|
-
})()
|
|
33
|
-
return () => { cancelled = true }
|
|
34
|
-
}, [])
|
|
35
|
-
|
|
36
|
-
if (!loaded || !integration) return null // nothing until the connection is saved
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<div className="space-y-4 border-t pt-4">
|
|
40
|
-
<div className="flex items-start gap-3 rounded-md border border-dashed p-3">
|
|
41
|
-
<Sparkles className="mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" />
|
|
42
|
-
<div className="space-y-1">
|
|
43
|
-
<h4 className="text-sm font-semibold">Sincronização de conteúdo — em breve</h4>
|
|
44
|
-
<p className="text-xs text-muted-foreground">
|
|
45
|
-
A publicação automática de páginas e artigos de SEO com a RankLayer está em preparação.
|
|
46
|
-
{integration.siteDomain ? ` Domínio configurado: ${integration.siteDomain}.` : ''} Assim que a
|
|
47
|
-
integração estiver ativa, o histórico de sincronizações aparece aqui.
|
|
48
|
-
</p>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
{log.length > 0 && (
|
|
53
|
-
<div className="space-y-2">
|
|
54
|
-
<div className="flex items-center gap-2">
|
|
55
|
-
<History className="h-4 w-4 text-muted-foreground" />
|
|
56
|
-
<h4 className="text-sm font-semibold">Histórico</h4>
|
|
57
|
-
</div>
|
|
58
|
-
<div className="divide-y rounded-md border text-sm">
|
|
59
|
-
{log.map((r) => (
|
|
60
|
-
<div key={r.id} className="flex items-center gap-3 px-3 py-2">
|
|
61
|
-
<span className="text-xs text-muted-foreground">{new Date(r.createdAt).toLocaleString('pt-BR')}</span>
|
|
62
|
-
<span className="ml-auto text-xs">{r.written}/{r.fetched} publicadas</span>
|
|
63
|
-
{r.status === 'success'
|
|
64
|
-
? <CheckCircle2 className="h-3.5 w-3.5 text-success" />
|
|
65
|
-
: <AlertCircle className="h-3.5 w-3.5 text-warning" />}
|
|
66
|
-
</div>
|
|
67
|
-
))}
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
)}
|
|
71
|
-
</div>
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Inlined as a data URI so the mark can never fail to load from an app's domain.
|
|
76
|
-
const RANKLAYER_MARK = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj48cmVjdCB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHJ4PSI3IiBmaWxsPSIjMUYyNDMxIi8+PHBvbHlnb24gcG9pbnRzPSIxNiw1LjYgMjYuNCwxMS42IDE2LDE3LjYgNS42LDExLjYiIGZpbGw9IiNGRkZGRkYiIHN0cm9rZT0iI0ZGRkZGRiIgc3Ryb2tlLXdpZHRoPSIxLjI1IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PGcgb3BhY2l0eT0iMC41NSI+PHBvbHlnb24gcG9pbnRzPSI1LjYsMTYuNCAxNiwyMi40IDI2LjQsMTYuNCAyNi40LDE4LjIgMTYsMjQuMiA1LjYsMTguMiIgZmlsbD0iI0ZGRkZGRiIgc3Ryb2tlPSIjRkZGRkZGIiBzdHJva2Utd2lkdGg9IjEuMjUiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L2c+PGcgb3BhY2l0eT0iMC4yOCI+PHBvbHlnb24gcG9pbnRzPSI1LjYsMjEuMiAxNiwyNy4yIDI2LjQsMjEuMiAyNi40LDIzIDE2LDI5IDUuNiwyMyIgZmlsbD0iI0ZGRkZGRiIgc3Ryb2tlPSIjRkZGRkZGIiBzdHJva2Utd2lkdGg9IjEuMjUiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L2c+PC9zdmc+'
|
|
77
|
-
|
|
78
|
-
export const ranklayerConnectorDef: ConnectorDefinition = {
|
|
79
|
-
id: 'ranklayer',
|
|
80
|
-
hostPluginId: 'marketing',
|
|
81
|
-
name: 'RankLayer',
|
|
82
|
-
description: 'Publicação de conteúdo e páginas de SEO por serviço/bairro para ser encontrado no Google e em assistentes de IA.',
|
|
83
|
-
icon: 'Search',
|
|
84
|
-
logoUrl: RANKLAYER_MARK,
|
|
85
|
-
authKind: 'api-key',
|
|
86
|
-
fields: [
|
|
87
|
-
{ key: 'apiKey', label: 'API Key', type: 'password', placeholder: '••••••••' },
|
|
88
|
-
{ key: 'siteDomain', label: 'Domínio do site', type: 'text', placeholder: 'exemplo.com.br' },
|
|
89
|
-
],
|
|
90
|
-
async getStatus() {
|
|
91
|
-
try {
|
|
92
|
-
const found = await provider.getIntegration()
|
|
93
|
-
return { connected: !!found?.apiKey, detail: found?.siteDomain }
|
|
94
|
-
} catch {
|
|
95
|
-
return { connected: false }
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
testConnection: (values) => provider.testConnection({ apiKey: values.apiKey }),
|
|
99
|
-
saveConnection: async (values) => { await provider.saveIntegration({ apiKey: values.apiKey, siteDomain: values.siteDomain }) },
|
|
100
|
-
disconnect: () => provider.disconnect(),
|
|
101
|
-
ExtraPanel: RankLayerExtraPanel,
|
|
102
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'
|
|
2
|
-
import type { TestConnectionResult } from '@fayz-ai/core'
|
|
3
|
-
import type { RankLayerIntegration, RankLayerSyncLogEntry } from '../types'
|
|
4
|
-
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
// RankLayer connector — control-plane client (SCAFFOLD).
|
|
7
|
-
//
|
|
8
|
-
// Reads/writes the connection row (plg_marketing_ranklayer_integrations) and
|
|
9
|
-
// reads the sync log. `testConnection` and `sync` are stubbed: RankLayer has no
|
|
10
|
-
// public API wired yet, so the real work (an edge function calling RankLayer)
|
|
11
|
-
// lands via an external PR — see ../RANKLAYER.md. Everything here is safe to
|
|
12
|
-
// ship: it only persists the tenant's API key + domain and surfaces status.
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
const INTEGRATIONS = 'plg_marketing_ranklayer_integrations'
|
|
16
|
-
const SYNC_LOG = 'plg_marketing_ranklayer_sync_log'
|
|
17
|
-
|
|
18
|
-
function getClient() {
|
|
19
|
-
const supabase = getSupabaseClientOptional() as { from: (t: string) => any } | null
|
|
20
|
-
if (!supabase) throw new Error('[ranklayer] Supabase not initialized')
|
|
21
|
-
return supabase
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function requireTenantId(): string {
|
|
25
|
-
const tenantId = getActiveTenantId()
|
|
26
|
-
if (!tenantId) throw new Error('[ranklayer] No active tenant')
|
|
27
|
-
return tenantId
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function toIntegration(row: Record<string, any>): RankLayerIntegration {
|
|
31
|
-
return {
|
|
32
|
-
id: row.id,
|
|
33
|
-
apiKey: row.api_key ?? undefined,
|
|
34
|
-
siteDomain: row.site_domain ?? undefined,
|
|
35
|
-
active: row.active ?? true,
|
|
36
|
-
lastSyncAt: row.last_sync_at ?? undefined,
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function createRankLayerProvider() {
|
|
41
|
-
return {
|
|
42
|
-
async getIntegration(): Promise<RankLayerIntegration | null> {
|
|
43
|
-
const tenantId = getActiveTenantId()
|
|
44
|
-
if (!tenantId) return null
|
|
45
|
-
const { data } = await getClient()
|
|
46
|
-
.from(INTEGRATIONS)
|
|
47
|
-
.select('*')
|
|
48
|
-
.eq('tenant_id', tenantId)
|
|
49
|
-
.maybeSingle()
|
|
50
|
-
return data ? toIntegration(data) : null
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
async saveIntegration(values: { apiKey: string; siteDomain?: string }): Promise<RankLayerIntegration> {
|
|
54
|
-
const tenantId = requireTenantId()
|
|
55
|
-
const payload = {
|
|
56
|
-
tenant_id: tenantId,
|
|
57
|
-
api_key: values.apiKey,
|
|
58
|
-
site_domain: values.siteDomain ?? null,
|
|
59
|
-
active: true,
|
|
60
|
-
updated_at: new Date().toISOString(),
|
|
61
|
-
}
|
|
62
|
-
// Upsert on the unique tenant_id.
|
|
63
|
-
const { data, error } = await getClient()
|
|
64
|
-
.from(INTEGRATIONS)
|
|
65
|
-
.upsert(payload, { onConflict: 'tenant_id' })
|
|
66
|
-
.select('*')
|
|
67
|
-
.single()
|
|
68
|
-
if (error) throw error
|
|
69
|
-
return toIntegration(data)
|
|
70
|
-
},
|
|
71
|
-
|
|
72
|
-
async disconnect(): Promise<void> {
|
|
73
|
-
const tenantId = getActiveTenantId()
|
|
74
|
-
if (!tenantId) return
|
|
75
|
-
await getClient().from(INTEGRATIONS).delete().eq('tenant_id', tenantId)
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
// SCAFFOLD: no RankLayer API yet — accept any non-empty key so the connect
|
|
79
|
-
// flow can be exercised. Replace with a real credential check in the PR.
|
|
80
|
-
async testConnection(values: { apiKey: string }): Promise<TestConnectionResult> {
|
|
81
|
-
if (!values.apiKey || values.apiKey.trim().length < 8) {
|
|
82
|
-
return { ok: false, message: 'Informe uma API Key válida da RankLayer.' }
|
|
83
|
-
}
|
|
84
|
-
return { ok: true, message: 'Chave aceita (validação real pendente — integração em preparação).' }
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
async getSyncLog(integrationId: string): Promise<RankLayerSyncLogEntry[]> {
|
|
88
|
-
const { data } = await getClient()
|
|
89
|
-
.from(SYNC_LOG)
|
|
90
|
-
.select('*')
|
|
91
|
-
.eq('integration_id', integrationId)
|
|
92
|
-
.order('created_at', { ascending: false })
|
|
93
|
-
.limit(20)
|
|
94
|
-
return (data ?? []).map((r: Record<string, any>) => ({
|
|
95
|
-
id: r.id,
|
|
96
|
-
createdAt: r.created_at,
|
|
97
|
-
status: r.status,
|
|
98
|
-
message: r.message ?? undefined,
|
|
99
|
-
fetched: r.fetched ?? 0,
|
|
100
|
-
written: r.written ?? 0,
|
|
101
|
-
}))
|
|
102
|
-
},
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export type RankLayerProvider = ReturnType<typeof createRankLayerProvider>
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export interface RankLayerIntegration {
|
|
2
|
-
id: string
|
|
3
|
-
apiKey?: string
|
|
4
|
-
siteDomain?: string
|
|
5
|
-
active: boolean
|
|
6
|
-
lastSyncAt?: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface RankLayerSyncLogEntry {
|
|
10
|
-
id: string
|
|
11
|
-
createdAt: string
|
|
12
|
-
status: 'success' | 'partial' | 'error'
|
|
13
|
-
message?: string
|
|
14
|
-
fetched: number
|
|
15
|
-
written: number
|
|
16
|
-
}
|
package/src/locales/en.ts
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
export const en: Record<string, string> = {
|
|
2
|
-
// metrics
|
|
3
|
-
'marketing.metric.conversionRate': 'Conversion rate',
|
|
4
|
-
'marketing.metric.cpa': 'Cost per acquisition',
|
|
5
|
-
'marketing.metric.topChannel': 'Top channel',
|
|
6
|
-
'marketing.metric.spend': 'spend',
|
|
7
|
-
'marketing.metric.reach': 'Reach',
|
|
8
|
-
'marketing.metric.cvr': 'CVR',
|
|
9
|
-
'marketing.metric.totalVisits': 'Total visits',
|
|
10
|
-
'marketing.metric.pages': 'Pages',
|
|
11
|
-
'marketing.metric.leads': 'Leads',
|
|
12
|
-
'marketing.metric.avgConversion': 'Avg. conversion',
|
|
13
|
-
// columns
|
|
14
|
-
'marketing.col.campaign': 'Campaign',
|
|
15
|
-
'marketing.col.channel': 'Channel',
|
|
16
|
-
'marketing.col.reach': 'Reach',
|
|
17
|
-
'marketing.col.leads': 'Leads',
|
|
18
|
-
'marketing.col.cvr': 'CVR',
|
|
19
|
-
'marketing.col.spend': 'Spend',
|
|
20
|
-
'marketing.col.cpa': 'CPA',
|
|
21
|
-
'marketing.col.status': 'Status',
|
|
22
|
-
'marketing.col.visits': 'Visits',
|
|
23
|
-
'marketing.col.conversions': 'Conversions',
|
|
24
|
-
'marketing.col.type': 'Type',
|
|
25
|
-
'marketing.col.page': 'Page',
|
|
26
|
-
'marketing.col.route': 'Route',
|
|
27
|
-
'marketing.col.leadTag': 'Tag',
|
|
28
|
-
// overview
|
|
29
|
-
'marketing.overview.byChannelSuffix': 'by channel',
|
|
30
|
-
'marketing.overview.recent': 'Recent campaigns',
|
|
31
|
-
// channels
|
|
32
|
-
'marketing.channels.subtitle': 'Acquisition performance by channel',
|
|
33
|
-
'marketing.channels.campaignsOn': 'Campaigns on this channel',
|
|
34
|
-
'marketing.channels.noCampaigns': 'No campaigns yet on this channel.',
|
|
35
|
-
// campaigns
|
|
36
|
-
'marketing.campaigns.subtitle': 'All acquisition campaigns and their conversion performance',
|
|
37
|
-
'marketing.campaigns.new': 'New campaign',
|
|
38
|
-
'marketing.campaigns.empty': 'No campaigns yet — create your first one.',
|
|
39
|
-
'marketing.campaigns.delete': 'Delete campaign',
|
|
40
|
-
// composer
|
|
41
|
-
'marketing.composer.title': 'New campaign',
|
|
42
|
-
'marketing.composer.name': 'Campaign name',
|
|
43
|
-
'marketing.composer.namePlaceholder': 'e.g. Spring Promo — Paid Social',
|
|
44
|
-
'marketing.composer.channel': 'Channel',
|
|
45
|
-
'marketing.composer.channelPlaceholder': 'Select a channel',
|
|
46
|
-
'marketing.composer.status': 'Status',
|
|
47
|
-
'marketing.composer.budget': 'Budget / spend',
|
|
48
|
-
'marketing.composer.cancel': 'Cancel',
|
|
49
|
-
'marketing.composer.create': 'Create campaign',
|
|
50
|
-
'marketing.status.draft': 'draft',
|
|
51
|
-
'marketing.status.active': 'active',
|
|
52
|
-
'marketing.status.paused': 'paused',
|
|
53
|
-
'marketing.status.ended': 'ended',
|
|
54
|
-
// funnel
|
|
55
|
-
'marketing.funnel.subtitlePrefix': 'Attribution funnel — reach to',
|
|
56
|
-
'marketing.funnel.overall': 'Overall conversion rate',
|
|
57
|
-
'marketing.funnel.ofPrev': 'of prev',
|
|
58
|
-
// landing pages
|
|
59
|
-
'marketing.landing.new': 'New page',
|
|
60
|
-
'marketing.landing.edit': 'Edit page',
|
|
61
|
-
'marketing.landing.delete': 'Delete page',
|
|
62
|
-
'marketing.landing.save': 'Save',
|
|
63
|
-
'marketing.landing.empty': 'No pages yet.',
|
|
64
|
-
'marketing.landing.site': 'Site',
|
|
65
|
-
'marketing.landing.sitePlaceholder': 'Pick a site',
|
|
66
|
-
'marketing.landing.name': 'Name',
|
|
67
|
-
'marketing.landing.namePlaceholder': 'Hair consult LP',
|
|
68
|
-
'marketing.landing.route': 'Route',
|
|
69
|
-
'marketing.landing.create': 'Create page',
|
|
70
|
-
'marketing.landing.status': 'Does this page exist on the site yet?',
|
|
71
|
-
'marketing.landing.statusLive': 'Already live',
|
|
72
|
-
'marketing.landing.statusPlanned': 'Not yet',
|
|
73
|
-
'marketing.landing.prompt': 'Page prompt',
|
|
74
|
-
'marketing.landing.promptPlaceholder': 'Describe the page: offer, audience, sections, call to action…',
|
|
75
|
-
'marketing.landing.buildWithFayz': 'Build page with Fayz',
|
|
76
|
-
'marketing.landing.leadTag': 'Lead tags',
|
|
77
|
-
'marketing.landing.leadTagPlaceholder': 'new tag…',
|
|
78
|
-
'marketing.landing.leadTagHint': 'Leads from this page enter the CRM with these tags.',
|
|
79
|
-
'marketing.landing.visitsPending': 'Visits come from the platform hosting the site; that source is not connected yet.',
|
|
80
|
-
// settings
|
|
81
|
-
'marketing.settings.conversionModel': 'Conversion model',
|
|
82
|
-
'marketing.settings.conversionModelDesc': "What counts as a conversion in this workspace and where it's attributed from.",
|
|
83
|
-
'marketing.settings.conversion': 'Conversion',
|
|
84
|
-
'marketing.settings.valueMetric': 'Value metric',
|
|
85
|
-
'marketing.settings.attributedFrom': 'Attributed from',
|
|
86
|
-
'marketing.settings.channels': 'Acquisition channels',
|
|
87
|
-
'marketing.settings.channelsDesc': 'Sources tracked for this workspace.',
|
|
88
|
-
'marketing.settings.trackValue': 'Track monetary value',
|
|
89
|
-
'marketing.settings.trackValueDesc': 'Attribute revenue to channels and campaigns.',
|
|
90
|
-
'marketing.settings.attribution': 'Attribution',
|
|
91
|
-
'marketing.settings.attributionDesc': 'How conversions are matched to channels.',
|
|
92
|
-
'marketing.settings.autoSync': 'Auto-sync conversions',
|
|
93
|
-
'marketing.settings.autoSyncDesc': 'Pull conversions automatically from the source.',
|
|
94
|
-
'marketing.settings.assisted': 'Count assisted conversions',
|
|
95
|
-
'marketing.settings.assistedDesc': 'Credit channels that contributed to a conversion.',
|
|
96
|
-
'marketing.settings.channelTrackDesc': 'Track this acquisition source.',
|
|
97
|
-
// content planner
|
|
98
|
-
'marketing.content.title': 'Content',
|
|
99
|
-
'marketing.content.week': 'Week',
|
|
100
|
-
'marketing.content.month': 'Month',
|
|
101
|
-
'marketing.content.newPost': 'New post',
|
|
102
|
-
'marketing.content.untitled': 'Untitled',
|
|
103
|
-
'marketing.content.account': 'Account',
|
|
104
|
-
'marketing.content.addAccount': 'Add account',
|
|
105
|
-
'marketing.content.previewNow': 'Just now',
|
|
106
|
-
'marketing.content.previewLike': 'Like',
|
|
107
|
-
'marketing.content.previewComment': 'Comment',
|
|
108
|
-
'marketing.content.previewShare': 'Share',
|
|
109
|
-
'marketing.content.showLess': 'show less',
|
|
110
|
-
'marketing.content.checklistTitle': 'Recording checklist',
|
|
111
|
-
'marketing.content.checklistDescription': 'Shooting-day operations',
|
|
112
|
-
'marketing.content.checklistOpen': 'Checklist',
|
|
113
|
-
'marketing.content.checklistEmpty': 'No items yet — generate them from the script or add your own below.',
|
|
114
|
-
'marketing.content.checklistAddPlaceholder': 'New item…',
|
|
115
|
-
'marketing.content.checklistAdd': 'Add item',
|
|
116
|
-
'marketing.content.checklistGenerate': 'Generate from script',
|
|
117
|
-
'marketing.content.scriptLabel': 'Script',
|
|
118
|
-
'marketing.content.captionLabel': 'Caption',
|
|
119
|
-
'marketing.content.captionPlaceholder': 'Write the post caption…',
|
|
120
|
-
'marketing.content.mediaLabel': 'Media asset',
|
|
121
|
-
'marketing.content.mediaUpload': 'Upload media',
|
|
122
|
-
'marketing.content.mediaHint': 'Image or video for this post',
|
|
123
|
-
'marketing.content.mediaReplace': 'Replace',
|
|
124
|
-
'marketing.content.mediaRemove': 'Remove',
|
|
125
|
-
'marketing.content.mediaUnavailable': 'Media upload requires a connected Supabase project.',
|
|
126
|
-
'marketing.content.editAccountTitle': 'Account settings',
|
|
127
|
-
'marketing.content.accountSettings': 'Account settings',
|
|
128
|
-
'marketing.content.deleteAccount': 'Delete account',
|
|
129
|
-
'marketing.content.deleteAccountConfirm': 'The account and all of its content plans and posts will be permanently deleted.',
|
|
130
|
-
'marketing.content.noAccountsAvailable': 'No accounts available',
|
|
131
|
-
'marketing.content.addAccountTitle': 'New account',
|
|
132
|
-
'marketing.content.nameLabel': 'Name',
|
|
133
|
-
'marketing.content.handleLabel': 'Handle',
|
|
134
|
-
'marketing.content.handlePlaceholder': '@handle (optional)',
|
|
135
|
-
'marketing.content.viewBoard': 'Weekly',
|
|
136
|
-
'marketing.content.viewCalendar': 'Monthly',
|
|
137
|
-
'marketing.content.viewList': 'List',
|
|
138
|
-
'marketing.content.unscheduled': 'Unscheduled',
|
|
139
|
-
'marketing.content.noPosts': 'No posts yet — add your first one from any week.',
|
|
140
|
-
'marketing.content.listTitle': 'Title',
|
|
141
|
-
'marketing.content.listWeek': 'Week',
|
|
142
|
-
'marketing.content.listDate': 'Date',
|
|
143
|
-
'marketing.content.listFormat': 'Format',
|
|
144
|
-
'marketing.content.listStatus': 'Status',
|
|
145
|
-
'marketing.content.noAccountsHint': 'Create the account (e.g. your Instagram profile) to start planning content.',
|
|
146
|
-
'marketing.content.accountNamePlaceholder': 'e.g. @myclinic',
|
|
147
|
-
'marketing.content.createAccount': 'Create account',
|
|
148
|
-
'marketing.content.defaultPlanName': 'Content plan — 8 weeks',
|
|
149
|
-
'marketing.content.brief': 'Brief',
|
|
150
|
-
'marketing.content.planName': 'Plan name',
|
|
151
|
-
'marketing.content.objective': 'Objective',
|
|
152
|
-
'marketing.content.objectivePlaceholder': 'e.g. generate evaluation bookings',
|
|
153
|
-
'marketing.content.tone': 'Tone of voice',
|
|
154
|
-
'marketing.content.tonePlaceholder': 'e.g. approachable authority, plain language',
|
|
155
|
-
'marketing.content.pillars': 'Content pillars',
|
|
156
|
-
'marketing.content.pillarPlaceholder': 'Add pillar…',
|
|
157
|
-
'marketing.content.formatsLabel': 'Formats',
|
|
158
|
-
'marketing.content.weeklyFrequency': 'Posts per week',
|
|
159
|
-
'marketing.content.weeksCount': 'Weeks',
|
|
160
|
-
'marketing.content.briefBody': 'Brief (markdown)',
|
|
161
|
-
'marketing.content.briefPlaceholder': 'Describe the strategy, references and what the content should achieve…',
|
|
162
|
-
'marketing.content.formatLabel': 'Format',
|
|
163
|
-
'marketing.content.statusLabel': 'Status',
|
|
164
|
-
'marketing.content.scheduledDate': 'Planned date',
|
|
165
|
-
'marketing.content.hook': 'Hook',
|
|
166
|
-
'marketing.content.hookPlaceholder': 'The first line that grabs attention…',
|
|
167
|
-
'marketing.content.cta': 'CTA',
|
|
168
|
-
'marketing.content.ctaPlaceholder': 'e.g. Book your evaluation',
|
|
169
|
-
'marketing.content.titlePlaceholder': 'Post title…',
|
|
170
|
-
'marketing.content.bodyPlaceholder': 'Post script / plan in markdown…',
|
|
171
|
-
'marketing.content.insertTemplate': 'Insert script template',
|
|
172
|
-
'marketing.content.save': 'Save',
|
|
173
|
-
'marketing.content.cancel': 'Cancel',
|
|
174
|
-
'marketing.content.edit': 'Edit',
|
|
175
|
-
'marketing.content.preview': 'Preview',
|
|
176
|
-
'marketing.content.deletePost': 'Delete post',
|
|
177
|
-
'marketing.content.deletePostConfirm': 'This post and its script will be permanently removed.',
|
|
178
|
-
'marketing.content.format.reel': 'Reel',
|
|
179
|
-
'marketing.content.format.static': 'Static',
|
|
180
|
-
'marketing.content.format.carousel': 'Carousel',
|
|
181
|
-
'marketing.content.format.story': 'Story',
|
|
182
|
-
'marketing.content.format.video': 'Video',
|
|
183
|
-
'marketing.content.format.live': 'Live',
|
|
184
|
-
'marketing.content.format.article': 'Article',
|
|
185
|
-
'marketing.content.platformsLabel': 'Platforms',
|
|
186
|
-
'marketing.content.status.idea': 'idea',
|
|
187
|
-
'marketing.content.status.script': 'script',
|
|
188
|
-
'marketing.content.status.recording': 'recording',
|
|
189
|
-
'marketing.content.status.editing': 'editing',
|
|
190
|
-
'marketing.content.status.scheduled': 'scheduled',
|
|
191
|
-
'marketing.content.status.published': 'published',
|
|
192
|
-
}
|
package/src/locales/index.ts
DELETED
package/src/locales/pt-BR.ts
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
export const ptBR: Record<string, string> = {
|
|
2
|
-
// metrics
|
|
3
|
-
'marketing.metric.conversionRate': 'Taxa de conversão',
|
|
4
|
-
'marketing.metric.cpa': 'Custo por aquisição',
|
|
5
|
-
'marketing.metric.topChannel': 'Principal canal',
|
|
6
|
-
'marketing.metric.spend': 'investido',
|
|
7
|
-
'marketing.metric.reach': 'Alcance',
|
|
8
|
-
'marketing.metric.cvr': 'CVR',
|
|
9
|
-
'marketing.metric.totalVisits': 'Total de visitas',
|
|
10
|
-
'marketing.metric.pages': 'Páginas',
|
|
11
|
-
'marketing.metric.leads': 'Leads',
|
|
12
|
-
'marketing.metric.avgConversion': 'Conversão média',
|
|
13
|
-
// columns
|
|
14
|
-
'marketing.col.campaign': 'Campanha',
|
|
15
|
-
'marketing.col.channel': 'Canal',
|
|
16
|
-
'marketing.col.reach': 'Alcance',
|
|
17
|
-
'marketing.col.leads': 'Leads',
|
|
18
|
-
'marketing.col.cvr': 'CVR',
|
|
19
|
-
'marketing.col.spend': 'Investimento',
|
|
20
|
-
'marketing.col.cpa': 'CPA',
|
|
21
|
-
'marketing.col.status': 'Status',
|
|
22
|
-
'marketing.col.visits': 'Visitas',
|
|
23
|
-
'marketing.col.conversions': 'Conversões',
|
|
24
|
-
'marketing.col.type': 'Tipo',
|
|
25
|
-
'marketing.col.page': 'Página',
|
|
26
|
-
'marketing.col.route': 'Rota',
|
|
27
|
-
'marketing.col.leadTag': 'Tag',
|
|
28
|
-
// overview
|
|
29
|
-
'marketing.overview.byChannelSuffix': 'por canal',
|
|
30
|
-
'marketing.overview.recent': 'Campanhas recentes',
|
|
31
|
-
// channels
|
|
32
|
-
'marketing.channels.subtitle': 'Desempenho de aquisição por canal',
|
|
33
|
-
'marketing.channels.campaignsOn': 'Campanhas neste canal',
|
|
34
|
-
'marketing.channels.noCampaigns': 'Nenhuma campanha ainda neste canal.',
|
|
35
|
-
// campaigns
|
|
36
|
-
'marketing.campaigns.subtitle': 'Todas as campanhas de aquisição e seu desempenho de conversão',
|
|
37
|
-
'marketing.campaigns.new': 'Nova campanha',
|
|
38
|
-
'marketing.campaigns.empty': 'Nenhuma campanha ainda — crie a primeira.',
|
|
39
|
-
'marketing.campaigns.delete': 'Excluir campanha',
|
|
40
|
-
// composer
|
|
41
|
-
'marketing.composer.title': 'Nova campanha',
|
|
42
|
-
'marketing.composer.name': 'Nome da campanha',
|
|
43
|
-
'marketing.composer.namePlaceholder': 'ex.: Promo de Verão — Mídia Paga',
|
|
44
|
-
'marketing.composer.channel': 'Canal',
|
|
45
|
-
'marketing.composer.channelPlaceholder': 'Selecione um canal',
|
|
46
|
-
'marketing.composer.status': 'Status',
|
|
47
|
-
'marketing.composer.budget': 'Orçamento / investimento',
|
|
48
|
-
'marketing.composer.cancel': 'Cancelar',
|
|
49
|
-
'marketing.composer.create': 'Criar campanha',
|
|
50
|
-
'marketing.status.draft': 'rascunho',
|
|
51
|
-
'marketing.status.active': 'ativa',
|
|
52
|
-
'marketing.status.paused': 'pausada',
|
|
53
|
-
'marketing.status.ended': 'encerrada',
|
|
54
|
-
// funnel
|
|
55
|
-
'marketing.funnel.subtitlePrefix': 'Funil de atribuição — alcance até',
|
|
56
|
-
'marketing.funnel.overall': 'Taxa de conversão geral',
|
|
57
|
-
'marketing.funnel.ofPrev': 'do anterior',
|
|
58
|
-
// landing pages
|
|
59
|
-
'marketing.landing.new': 'Nova página',
|
|
60
|
-
'marketing.landing.edit': 'Editar página',
|
|
61
|
-
'marketing.landing.delete': 'Excluir página',
|
|
62
|
-
'marketing.landing.save': 'Salvar',
|
|
63
|
-
'marketing.landing.empty': 'Nenhuma página cadastrada ainda.',
|
|
64
|
-
'marketing.landing.site': 'Site',
|
|
65
|
-
'marketing.landing.sitePlaceholder': 'Selecione o site',
|
|
66
|
-
'marketing.landing.name': 'Nome',
|
|
67
|
-
'marketing.landing.namePlaceholder': 'LP Capilar',
|
|
68
|
-
'marketing.landing.route': 'Rota',
|
|
69
|
-
'marketing.landing.create': 'Criar página',
|
|
70
|
-
'marketing.landing.status': 'Esta página já existe no site?',
|
|
71
|
-
'marketing.landing.statusLive': 'Já existe',
|
|
72
|
-
'marketing.landing.statusPlanned': 'Ainda não existe',
|
|
73
|
-
'marketing.landing.prompt': 'Prompt da página',
|
|
74
|
-
'marketing.landing.promptPlaceholder': 'Descreva a página: oferta, público, seções, chamada para ação…',
|
|
75
|
-
'marketing.landing.buildWithFayz': 'Criar página com Fayz',
|
|
76
|
-
'marketing.landing.leadTag': 'Tags dos leads',
|
|
77
|
-
'marketing.landing.leadTagPlaceholder': 'nova tag…',
|
|
78
|
-
'marketing.landing.leadTagHint': 'Os leads desta página entram no CRM com estas tags.',
|
|
79
|
-
'marketing.landing.visitsPending': 'As visitas vêm da plataforma que hospeda o site; essa origem ainda não está conectada.',
|
|
80
|
-
// settings
|
|
81
|
-
'marketing.settings.conversionModel': 'Modelo de conversão',
|
|
82
|
-
'marketing.settings.conversionModelDesc': 'O que conta como conversão neste workspace e de onde é atribuída.',
|
|
83
|
-
'marketing.settings.conversion': 'Conversão',
|
|
84
|
-
'marketing.settings.valueMetric': 'Métrica de valor',
|
|
85
|
-
'marketing.settings.attributedFrom': 'Atribuída de',
|
|
86
|
-
'marketing.settings.channels': 'Canais de aquisição',
|
|
87
|
-
'marketing.settings.channelsDesc': 'Fontes monitoradas neste workspace.',
|
|
88
|
-
'marketing.settings.trackValue': 'Acompanhar valor monetário',
|
|
89
|
-
'marketing.settings.trackValueDesc': 'Atribuir receita a canais e campanhas.',
|
|
90
|
-
'marketing.settings.attribution': 'Atribuição',
|
|
91
|
-
'marketing.settings.attributionDesc': 'Como as conversões são associadas aos canais.',
|
|
92
|
-
'marketing.settings.autoSync': 'Sincronizar conversões automaticamente',
|
|
93
|
-
'marketing.settings.autoSyncDesc': 'Importar conversões automaticamente da fonte.',
|
|
94
|
-
'marketing.settings.assisted': 'Contar conversões assistidas',
|
|
95
|
-
'marketing.settings.assistedDesc': 'Creditar canais que contribuíram para uma conversão.',
|
|
96
|
-
'marketing.settings.channelTrackDesc': 'Monitorar esta fonte de aquisição.',
|
|
97
|
-
// content planner
|
|
98
|
-
'marketing.content.title': 'Conteúdo',
|
|
99
|
-
'marketing.content.week': 'Semana',
|
|
100
|
-
'marketing.content.month': 'Mês',
|
|
101
|
-
'marketing.content.newPost': 'Novo post',
|
|
102
|
-
'marketing.content.untitled': 'Sem título',
|
|
103
|
-
'marketing.content.account': 'Conta',
|
|
104
|
-
'marketing.content.addAccount': 'Adicionar conta',
|
|
105
|
-
'marketing.content.previewNow': 'Agora',
|
|
106
|
-
'marketing.content.previewLike': 'Curtir',
|
|
107
|
-
'marketing.content.previewComment': 'Comentar',
|
|
108
|
-
'marketing.content.previewShare': 'Compartilhar',
|
|
109
|
-
'marketing.content.showLess': 'mostrar menos',
|
|
110
|
-
'marketing.content.checklistTitle': 'Checklist de gravação',
|
|
111
|
-
'marketing.content.checklistDescription': 'Operação do dia de gravação',
|
|
112
|
-
'marketing.content.checklistOpen': 'Checklist',
|
|
113
|
-
'marketing.content.checklistEmpty': 'Nenhum item ainda — gere a partir do roteiro ou adicione o seu abaixo.',
|
|
114
|
-
'marketing.content.checklistAddPlaceholder': 'Novo item…',
|
|
115
|
-
'marketing.content.checklistAdd': 'Adicionar item',
|
|
116
|
-
'marketing.content.checklistGenerate': 'Gerar do roteiro',
|
|
117
|
-
'marketing.content.scriptLabel': 'Roteiro',
|
|
118
|
-
'marketing.content.captionLabel': 'Legenda',
|
|
119
|
-
'marketing.content.captionPlaceholder': 'Escreva a legenda do post…',
|
|
120
|
-
'marketing.content.mediaLabel': 'Arte / mídia',
|
|
121
|
-
'marketing.content.mediaUpload': 'Enviar mídia',
|
|
122
|
-
'marketing.content.mediaHint': 'Imagem ou vídeo deste post',
|
|
123
|
-
'marketing.content.mediaReplace': 'Substituir',
|
|
124
|
-
'marketing.content.mediaRemove': 'Remover',
|
|
125
|
-
'marketing.content.mediaUnavailable': 'O upload de mídia requer um projeto Supabase conectado.',
|
|
126
|
-
'marketing.content.editAccountTitle': 'Configurações da conta',
|
|
127
|
-
'marketing.content.accountSettings': 'Configurações da conta',
|
|
128
|
-
'marketing.content.deleteAccount': 'Excluir conta',
|
|
129
|
-
'marketing.content.deleteAccountConfirm': 'A conta e todos os planos e posts de conteúdo dela serão excluídos permanentemente.',
|
|
130
|
-
'marketing.content.noAccountsAvailable': 'Nenhuma conta disponível',
|
|
131
|
-
'marketing.content.addAccountTitle': 'Nova conta',
|
|
132
|
-
'marketing.content.nameLabel': 'Nome',
|
|
133
|
-
'marketing.content.handleLabel': 'Usuário',
|
|
134
|
-
'marketing.content.handlePlaceholder': '@usuario (opcional)',
|
|
135
|
-
'marketing.content.viewBoard': 'Semanal',
|
|
136
|
-
'marketing.content.viewCalendar': 'Mensal',
|
|
137
|
-
'marketing.content.viewList': 'Lista',
|
|
138
|
-
'marketing.content.unscheduled': 'Sem data',
|
|
139
|
-
'marketing.content.noPosts': 'Nenhum post ainda — adicione o primeiro em qualquer semana.',
|
|
140
|
-
'marketing.content.listTitle': 'Título',
|
|
141
|
-
'marketing.content.listWeek': 'Semana',
|
|
142
|
-
'marketing.content.listDate': 'Data',
|
|
143
|
-
'marketing.content.listFormat': 'Formato',
|
|
144
|
-
'marketing.content.listStatus': 'Status',
|
|
145
|
-
'marketing.content.noAccountsHint': 'Crie a conta (ex.: o perfil do Instagram) para começar a planejar o conteúdo.',
|
|
146
|
-
'marketing.content.accountNamePlaceholder': 'ex.: @minhaclinica',
|
|
147
|
-
'marketing.content.createAccount': 'Criar conta',
|
|
148
|
-
'marketing.content.defaultPlanName': 'Plano de conteúdo — 8 semanas',
|
|
149
|
-
'marketing.content.brief': 'Briefing',
|
|
150
|
-
'marketing.content.planName': 'Nome do plano',
|
|
151
|
-
'marketing.content.objective': 'Objetivo',
|
|
152
|
-
'marketing.content.objectivePlaceholder': 'ex.: gerar agendamentos de avaliação',
|
|
153
|
-
'marketing.content.tone': 'Tom de voz',
|
|
154
|
-
'marketing.content.tonePlaceholder': 'ex.: autoridade acessível, linguagem simples',
|
|
155
|
-
'marketing.content.pillars': 'Pilares de conteúdo',
|
|
156
|
-
'marketing.content.pillarPlaceholder': 'Adicionar pilar…',
|
|
157
|
-
'marketing.content.formatsLabel': 'Formatos',
|
|
158
|
-
'marketing.content.weeklyFrequency': 'Posts por semana',
|
|
159
|
-
'marketing.content.weeksCount': 'Semanas',
|
|
160
|
-
'marketing.content.briefBody': 'Briefing (markdown)',
|
|
161
|
-
'marketing.content.briefPlaceholder': 'Descreva a estratégia, referências e o que se quer com o conteúdo…',
|
|
162
|
-
'marketing.content.formatLabel': 'Formato',
|
|
163
|
-
'marketing.content.statusLabel': 'Status',
|
|
164
|
-
'marketing.content.scheduledDate': 'Data prevista',
|
|
165
|
-
'marketing.content.hook': 'Gancho',
|
|
166
|
-
'marketing.content.hookPlaceholder': 'A primeira frase que segura a atenção…',
|
|
167
|
-
'marketing.content.cta': 'CTA',
|
|
168
|
-
'marketing.content.ctaPlaceholder': 'ex.: Agende sua avaliação',
|
|
169
|
-
'marketing.content.titlePlaceholder': 'Título do post…',
|
|
170
|
-
'marketing.content.bodyPlaceholder': 'Roteiro / plano do post em markdown…',
|
|
171
|
-
'marketing.content.insertTemplate': 'Inserir modelo de roteiro',
|
|
172
|
-
'marketing.content.save': 'Salvar',
|
|
173
|
-
'marketing.content.cancel': 'Cancelar',
|
|
174
|
-
'marketing.content.edit': 'Editar',
|
|
175
|
-
'marketing.content.preview': 'Visualizar',
|
|
176
|
-
'marketing.content.deletePost': 'Excluir post',
|
|
177
|
-
'marketing.content.deletePostConfirm': 'Este post e seu roteiro serão removidos permanentemente.',
|
|
178
|
-
'marketing.content.format.reel': 'Reel',
|
|
179
|
-
'marketing.content.format.static': 'Estático',
|
|
180
|
-
'marketing.content.format.carousel': 'Carrossel',
|
|
181
|
-
'marketing.content.format.story': 'Story',
|
|
182
|
-
'marketing.content.format.video': 'Vídeo',
|
|
183
|
-
'marketing.content.format.live': 'Live',
|
|
184
|
-
'marketing.content.format.article': 'Artigo',
|
|
185
|
-
'marketing.content.platformsLabel': 'Plataformas',
|
|
186
|
-
'marketing.content.status.idea': 'ideia',
|
|
187
|
-
'marketing.content.status.script': 'roteiro',
|
|
188
|
-
'marketing.content.status.recording': 'gravação',
|
|
189
|
-
'marketing.content.status.editing': 'edição',
|
|
190
|
-
'marketing.content.status.scheduled': 'agendado',
|
|
191
|
-
'marketing.content.status.published': 'publicado',
|
|
192
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
-- 000_plg_rename.sql — rename legacy marketing tables to plg_marketing_* for pools
|
|
2
|
-
-- provisioned before the industry-pool rename. Guarded: fires only when legacy
|
|
3
|
-
-- name exists and target does not, so fresh pools skip every branch.
|
|
4
|
-
DO $$
|
|
5
|
-
BEGIN
|
|
6
|
-
IF to_regclass('public.mkt_social_accounts') IS NOT NULL AND to_regclass('public.plg_marketing_social_accounts') IS NULL THEN
|
|
7
|
-
ALTER TABLE public.mkt_social_accounts RENAME TO plg_marketing_social_accounts;
|
|
8
|
-
END IF;
|
|
9
|
-
IF to_regclass('public.mkt_content_plans') IS NOT NULL AND to_regclass('public.plg_marketing_content_plans') IS NULL THEN
|
|
10
|
-
ALTER TABLE public.mkt_content_plans RENAME TO plg_marketing_content_plans;
|
|
11
|
-
END IF;
|
|
12
|
-
IF to_regclass('public.mkt_content_posts') IS NOT NULL AND to_regclass('public.plg_marketing_content_posts') IS NULL THEN
|
|
13
|
-
ALTER TABLE public.mkt_content_posts RENAME TO plg_marketing_content_posts;
|
|
14
|
-
END IF;
|
|
15
|
-
END $$;
|