// Mock data for the Clicky dashboard const SPEND_TREND = [ { d: '30 Mar', v: 38 }, { d: '2 Apr', v: 41 }, { d: '6 Apr', v: 47 }, { d: '9 Apr', v: 46 }, { d: '13 Apr', v: 49 }, { d: '16 Apr', v: 52 }, { d: '20 Apr', v: 58 }, { d: '23 Apr', v: 61 }, { d: '27 Apr', v: 63 }, ]; const CONV_TREND = [ { d: '30 Mar', conv: 0.05, cpc: 8 }, { d: '2 Apr', conv: 0.18, cpc: 14 }, { d: '6 Apr', conv: 0.36, cpc: 22 }, { d: '9 Apr', conv: 0.32, cpc: 18 }, { d: '13 Apr', conv: 0.40, cpc: 6 }, { d: '16 Apr', conv: 0.28, cpc: 12 }, { d: '20 Apr', conv: 0.30, cpc: 16 }, { d: '23 Apr', conv: 0.31, cpc: 19 }, { d: '27 Apr', conv: 0.30, cpc: 17 }, ]; // Sparkline helpers function spark(seed, n=24, trend='up') { const out = []; let v = 50; for (let i = 0; i < n; i++) { const noise = (Math.sin(i * 1.7 + seed) * 0.5 + Math.cos(i * 0.9 + seed * 2) * 0.3) * 8; const drift = trend === 'up' ? i * 0.6 : trend === 'down' ? -i * 0.4 : 0; v = 50 + drift + noise; out.push({ i, v: Math.max(5, v) }); } return out; } const KPIS = [ { key: 'spend', label: 'Spend', value: '£1,550.98', delta: +12.4, dir: 'up', trend: spark(1, 24, 'up'), tone: 'positive' }, { key: 'conv', label: 'Conversions', value: '14', delta: +55.6, dir: 'up', trend: spark(2, 24, 'up'), tone: 'positive' }, { key: 'cpconv', label: 'Cost Per Conversion', value: '£110.78', delta: -27.7, dir: 'down', trend: spark(3, 24, 'down'), tone: 'positive' }, { key: 'cvr', label: 'Conversion Rate', value: '2.4%', delta: +41.2, dir: 'up', trend: spark(4, 24, 'up'), tone: 'positive' }, { key: 'clicks', label: 'Clicks', value: '587', delta: +12.5, dir: 'up', trend: spark(5, 24, 'up'), tone: 'positive' }, { key: 'imp', label: 'Impressions', value: '5,932', delta: +10.0, dir: 'up', trend: spark(6, 24, 'up'), tone: 'positive' }, { key: 'ctr', label: 'CTR', value: '9.9%', delta: +2.1, dir: 'up', trend: spark(7, 24, 'flat'), tone: 'positive' }, { key: 'cpc', label: 'Avg. CPC', value: '£2.64', delta: -11.1, dir: 'down', trend: spark(8, 24, 'down'), tone: 'positive' }, ]; const REPORTS = [ { id: 'r-1042', name: 'April cross-channel performance — Evergreen Escapes', channel: 'Cross-channel', period: 'Apr 2026', status: 'Ready', requestedBy: 'Hayley Roberts', requestedOn: 'Apr 28', uploadedBy: 'Joe Marshall', uploadedOn: '2 hr ago', format: 'PDF', size: '2.4 MB', notes: 'Standard month-end deck — board summary on slide 1.' }, { id: 'r-1041', name: 'Q1 Bookings Roll-up · paid + organic', channel: 'Bookings', period: 'Q1 2026', status: 'Ready', requestedBy: 'Hayley Roberts', requestedOn: 'Apr 5', uploadedBy: 'Matt Jones', uploadedOn: 'Yesterday', format: 'XLS', size: '186 KB', notes: 'Pivot by campaign + month included on tab 2.' }, { id: 'r-1040', name: 'Meta Ads creative readout', channel: 'Meta Ads', period: 'Apr 2026', status: 'Ready', requestedBy: 'Hayley Roberts', requestedOn: 'Apr 22', uploadedBy: 'Hayley Roberts',uploadedOn: 'Yesterday', format: 'PDF', size: '3.1 MB', notes: 'Top 12 ads by ROAS, with creative recommendations.' }, { id: 'r-1038', name: 'Branded vs Non-Branded Spend', channel: 'Google Ads', period: 'Mar 2026', status: 'Ready', requestedBy: 'Hayley Roberts', requestedOn: 'Mar 28', uploadedBy: 'Matt Jones', uploadedOn: '3 days ago', format: 'PDF', size: '980 KB', notes: 'Year-on-year overlay added per request.' }, { id: 'r-1037', name: 'SEO health & ranking distribution', channel: 'SEO', period: 'Mar 2026', status: 'Ready', requestedBy: 'Daniel Trevethan',requestedOn: 'Mar 26', uploadedBy: 'Nathan Smith', uploadedOn: '5 days ago', format: 'PDF', size: '1.4 MB', notes: 'GSC + Ahrefs blended view; backlinks tab on page 6.' }, { id: 'r-1036', name: 'Website maintenance · uptime + speed',channel: 'Maintenance', period: 'Mar 2026', status: 'Ready', requestedBy: 'Joe Marshall', requestedOn: 'Mar 30', uploadedBy: 'Nathan Smith', uploadedOn: '6 days ago', format: 'XLS', size: '142 KB', notes: 'All 3 Evergreen sites · core web vitals included.' }, { id: 'r-1035', name: 'Google Ads search terms audit', channel: 'Google Ads', period: 'Mar 2026', status: 'In progress', requestedBy: 'Hayley Roberts', requestedOn: 'Apr 30', uploadedBy: null, uploadedOn: null, format: null, size: null, notes: 'Matt pulling negatives recommendations alongside.' }, { id: 'r-1033', name: 'Booking funnel CRO audit', channel: 'CRO', period: 'Mar 2026', status: 'In progress', requestedBy: 'Hayley Roberts', requestedOn: 'Apr 24', uploadedBy: null, uploadedOn: null, format: null, size: null, notes: 'Hayley running 3 user sessions before write-up.' }, { id: 'r-1031', name: 'Geo performance breakdown', channel: 'Google Ads', period: 'Feb 2026', status: 'Ready', requestedBy: 'Hayley Roberts', requestedOn: 'Feb 26', uploadedBy: 'Nathan Smith', uploadedOn: '12 days ago', format: 'PDF', size: '1.8 MB', notes: '' }, { id: 'r-1029', name: 'GA4 attribution & conversion paths', channel: 'GA4', period: 'Feb 2026', status: 'Ready', requestedBy: 'Joe Marshall', requestedOn: 'Feb 24', uploadedBy: 'Nathan Smith', uploadedOn: '13 days ago', format: 'PDF', size: '1.1 MB', notes: 'Multi-touch view, model-comparison appendix.' }, { id: 'r-1028', name: 'Device & hour-of-day heatmap', channel: 'Google Ads', period: 'Feb 2026', status: 'Ready', requestedBy: 'Hayley Roberts', requestedOn: 'Feb 22', uploadedBy: 'Matt Jones', uploadedOn: '14 days ago', format: 'XLS', size: '92 KB', notes: '' }, ]; const TICKETS = [ { id: 'T-2104', subject: 'Add tracking for new landing page variant', priority: 'Normal', status: 'In progress', assignee: 'Joe Marshall', opened: 'Apr 28' }, { id: 'T-2098', subject: 'Conversion mismatch between GA4 and Google Ads', priority: 'High', status: 'Awaiting reply', assignee: 'Nathan Smith', opened: 'Apr 25' }, { id: 'T-2089', subject: 'Pause "Spring Breaks — Broad" ad group', priority: 'Normal', status: 'Resolved', assignee: 'Joe Marshall', opened: 'Apr 22' }, { id: 'T-2076', subject: 'Request: weekly spend cap notification', priority: 'Low', status: 'Resolved', assignee: 'Matt Jones', opened: 'Apr 14' }, ]; const ACCOUNTS = [ { name: 'Evergreen Escapes', id: '482-209-7716', spend: '£980.40', status: 'Active' }, { name: 'Evergreen Ownership', id: '931-554-2280', spend: '£570.58', status: 'Active' }, ]; const ASK_AMPLIFY_SUGGESTIONS = [ 'Why did bookings jump in week 16?', 'Which keywords are driving the highest cost per booking?', 'Suggest 3 negative keywords for Evergreen Ownership', 'Compare Google Ads spend this month vs last month', ]; const CONTRACTS = [ { id: 'C-2042', name: 'Google Ads Management — Evergreen Escapes', start: '12 Jan 2026', renews: '12 Jan 2027', term: '12 months', monthly: '£1,250.00', status: 'Active' }, { id: 'C-2043', name: 'Google Ads Management — Evergreen Ownership', start: '01 Mar 2026', renews: '01 Mar 2027', term: '12 months', monthly: '£950.00', status: 'Active' }, { id: 'C-2031', name: 'SEO Retainer — Evergreen Escapes', start: '20 May 2025', renews: '20 May 2026', term: '12 months', monthly: '£900.00', status: 'Renewing', renewing: true, daysToRenew: 18 }, { id: 'C-2050', name: 'Events & Training — Ad-hoc', start: '01 Jan 2026', renews: '—', term: 'Ad-hoc', monthly: 'Per event', status: 'Active' }, { id: 'C-2044', name: 'Conversion Tracking & GA4 Setup', start: '01 Mar 2026', renews: '—', term: 'One-off', monthly: '£1,800.00', status: 'Completed' }, { id: 'C-2061', name: 'Landing Page Build — Spring Breaks', start: '15 Apr 2026', renews: '—', term: '6 weeks', monthly: '£3,400.00', status: 'In progress' }, ]; // Each invoice now carries `lines` linking line-items to the contracts // that generated them. An invoice with `contractId: null` lines is a // one-off (e.g. event tickets) that doesn't sit under a contract. const INVOICES = [ // May 2026 — Google Ads combined retainer { id: 'INV-10421', date: '01 May 2026', period: 'May 2026 · Google Ads retainers', amount: '£2,200.00', status: 'Due', due: '15 May 2026', lines: [ { contractId: 'C-2042', description: 'Google Ads — Evergreen Escapes (May)', amount: 1250 }, { contractId: 'C-2043', description: 'Google Ads — Evergreen Ownership (May)', amount: 950 }, ], }, // May 2026 — SEO retainer { id: 'INV-10422', date: '01 May 2026', period: 'May 2026 · SEO retainer', amount: '£900.00', status: 'Due', due: '15 May 2026', lines: [ { contractId: 'C-2031', description: 'SEO Retainer — Evergreen Escapes (May)', amount: 900 }, ], }, // Event ticket — under the Events & Training ad-hoc contract { id: 'INV-10405', date: '15 Apr 2026', period: 'Performance Day · Manchester', amount: '£395.00', status: 'Overdue', due: '29 Apr 2026', lines: [ { contractId: 'C-2050', description: 'Clicky Performance Day — 2 tickets', amount: 395 }, ], }, // Landing page deposit { id: 'INV-10410', date: '20 Apr 2026', period: 'Landing Page Build · Milestone 1', amount: '£1,700.00', status: 'Paid', due: '04 May 2026', lines: [ { contractId: 'C-2061', description: 'Landing Page Build — Spring Breaks (50% deposit)', amount: 1700 }, ], }, // Apr 2026 — Google Ads { id: 'INV-10398', date: '01 Apr 2026', period: 'Apr 2026 · Google Ads retainers', amount: '£2,200.00', status: 'Paid', due: '15 Apr 2026', lines: [ { contractId: 'C-2042', description: 'Google Ads — Evergreen Escapes (Apr)', amount: 1250 }, { contractId: 'C-2043', description: 'Google Ads — Evergreen Ownership (Apr)', amount: 950 }, ], }, // Apr 2026 — SEO { id: 'INV-10399', date: '01 Apr 2026', period: 'Apr 2026 · SEO retainer', amount: '£900.00', status: 'Paid', due: '15 Apr 2026', lines: [ { contractId: 'C-2031', description: 'SEO Retainer — Evergreen Escapes (Apr)', amount: 900 }, ], }, // Mar 2026 — Google Ads { id: 'INV-10371', date: '01 Mar 2026', period: 'Mar 2026 · Google Ads retainers', amount: '£2,200.00', status: 'Paid', due: '15 Mar 2026', lines: [ { contractId: 'C-2042', description: 'Google Ads — Evergreen Escapes (Mar)', amount: 1250 }, { contractId: 'C-2043', description: 'Google Ads — Evergreen Ownership (Mar)', amount: 950 }, ], }, // Mar 2026 — SEO { id: 'INV-10372', date: '01 Mar 2026', period: 'Mar 2026 · SEO retainer', amount: '£900.00', status: 'Paid', due: '15 Mar 2026', lines: [ { contractId: 'C-2031', description: 'SEO Retainer — Evergreen Escapes (Mar)', amount: 900 }, ], }, // GA4 setup one-off { id: 'INV-10355', date: '15 Mar 2026', period: 'GA4 Setup · One-off', amount: '£1,800.00', status: 'Paid', due: '29 Mar 2026', lines: [ { contractId: 'C-2044', description: 'Conversion Tracking & GA4 Setup (one-off)', amount: 1800 }, ], }, // Feb 2026 — Google Ads (Ownership not yet active) { id: 'INV-10342', date: '01 Feb 2026', period: 'Feb 2026 · Google Ads retainer', amount: '£1,250.00', status: 'Paid', due: '15 Feb 2026', lines: [ { contractId: 'C-2042', description: 'Google Ads — Evergreen Escapes (Feb)', amount: 1250 }, ], }, // Feb 2026 — SEO { id: 'INV-10343', date: '01 Feb 2026', period: 'Feb 2026 · SEO retainer', amount: '£900.00', status: 'Paid', due: '15 Feb 2026', lines: [ { contractId: 'C-2031', description: 'SEO Retainer — Evergreen Escapes (Feb)', amount: 900 }, ], }, // Jan 2026 — Google Ads { id: 'INV-10314', date: '01 Jan 2026', period: 'Jan 2026 · Google Ads retainer', amount: '£1,250.00', status: 'Paid', due: '15 Jan 2026', lines: [ { contractId: 'C-2042', description: 'Google Ads — Evergreen Escapes (Jan)', amount: 1250 }, ], }, // Jan 2026 — SEO { id: 'INV-10315', date: '01 Jan 2026', period: 'Jan 2026 · SEO retainer', amount: '£900.00', status: 'Paid', due: '15 Jan 2026', lines: [ { contractId: 'C-2031', description: 'SEO Retainer — Evergreen Escapes (Jan)', amount: 900 }, ], }, ]; // Agreed business KPIs — quarter targets, current actuals, and direction const AGREED_KPIS = [ { key: 'bookings', label: 'Lodge bookings', sub: 'Confirmed nights, all sources', target: 480, actual: 412, unit: 'nights', progress: 86, // % of quarter target timeProgress: 67, // % through Q2 status: 'on-track', delta: '+18% YoY', deltaTone: 'positive', trend: spark(11, 24, 'up'), note: 'Pacing 2.7% ahead of Q2 target. Easter +bank holiday delivered 96 nights vs forecast 78.', owner: 'Joe Marshall', source: 'manual', sourceDetail: 'Logged weekly from Sykes + direct booking export', lastUpdated: 'Updated 2 days ago', }, { key: 'revenue', label: 'Booking revenue', sub: 'Net of cancellations', target: 184000, actual: 158420, unit: '£', progress: 86, timeProgress: 67, status: 'on-track', delta: '+22% YoY', deltaTone: 'positive', trend: spark(12, 24, 'up'), note: 'AOV up £41 vs LY thanks to longer mid-week stays in 3-bed lodges.', owner: 'Joe Marshall', source: 'manual', sourceDetail: 'Logged weekly from Sykes + direct booking export', lastUpdated: 'Updated 2 days ago', }, { key: 'cpb', label: 'Cost per booking', sub: 'Paid media · all channels', target: 38, actual: 31.40, unit: '£', progress: 100, timeProgress: 67, status: 'ahead', delta: '−17% vs target', deltaTone: 'positive', trend: spark(13, 24, 'down'), note: 'Branded auctions softening + Performance Max reallocation has pulled CPB below target.', owner: 'Matt Jones', source: 'google-ads', sourceDetail: 'Live from Google Ads · Cost ÷ booking conversions', lastUpdated: 'Synced 14 min ago', }, { key: 'roas', label: 'ROAS', sub: 'Paid media revenue / spend', target: 6.5, actual: 7.4, unit: 'x', progress: 100, timeProgress: 67, status: 'ahead', delta: '+0.9x vs target', deltaTone: 'positive', trend: spark(14, 24, 'up'), note: 'Search ROAS 11.2x is doing the heavy lifting; PMax holding 4.1x.', owner: 'Matt Jones', source: 'google-ads', sourceDetail: 'Live from Google Ads · Conv. value ÷ cost', lastUpdated: 'Synced 14 min ago', }, { key: 'directshare', label: 'Direct booking share', sub: 'Direct vs OTAs', target: 70, actual: 64, unit: '%', progress: 91, timeProgress: 67, status: 'watch', delta: '−6pp vs target', deltaTone: 'warning', trend: spark(15, 24, 'flat'), note: 'Sykes commissions ticking up. Brand search investment in May should reverse this.', owner: 'Joe Marshall', source: 'manual', sourceDetail: 'Calculated monthly · direct ÷ (direct + OTA)', lastUpdated: 'Updated 6 days ago', }, { key: 'ownership', label: 'Ownership enquiries', sub: 'Lodge purchase leads', target: 60, actual: null, unit: 'leads', progress: 0, timeProgress: 67, status: 'pending', delta: null, deltaTone: 'neutral', trend: null, note: 'Awaiting CRM setup — Joe to connect HubSpot lead pipeline before next review.', owner: 'Hayley Roberts', source: 'pending', sourceDetail: 'Pending — needs HubSpot pipeline mapping', lastUpdated: 'Not yet tracking', }, ]; // Brand info for the active client const CLIENT = { name: 'Evergreen Escapes', shortName: 'Evergreen', tagline: 'Peaceful self-catering lodge holidays in Cornwall', url: 'st-mabyn-escape.co.uk', contact: 'Daniel Trevethan', contactRole: 'Owner / Marketing Lead', tier: 'Premier', sites: [ { id: 'lodge', name: 'Evergreen Escapes', url: 'st-mabyn-escape.co.uk', status: 'active', campaigns: 4, role: 'Holiday breaks', preview: 'assets/stmabyn-website.png' }, { id: 'ownership', name: 'Evergreen Ownership', url: 'st-mabyn-escape.co.uk/ownership', status: 'active', campaigns: 2, role: 'Lodge ownership leads', preview: 'assets/stmabyn-website.png' }, { id: 'parkex', name: 'Park Experience', url: 'st-mabyn-escape.co.uk/park', status: 'active', campaigns: 1, role: 'On-park amenities & events', preview: 'assets/stmabyn-website.png' }, { id: 'planned-1', name: 'Cornwall Lodges Group', url: 'cornwall-lodges-group.co.uk', status: 'planned', campaigns: 0, role: 'New build · launching Aug' }, ], siteCapacity: 6, }; Object.assign(window, { SPEND_TREND, CONV_TREND, KPIS, REPORTS, TICKETS, ACCOUNTS, ASK_AMPLIFY_SUGGESTIONS, spark, CONTRACTS, INVOICES, AGREED_KPIS, CLIENT, });