From 0aecf5b41ce147ef35471ba1a20be72dbe3a981a Mon Sep 17 00:00:00 2001 From: Jakob Wennberg Date: Fri, 13 Feb 2026 15:39:13 +0100 Subject: [PATCH] Refactor to generic ERP base Remove influencer-specific features (campaigns, TikTok, gifts, shadow ledger, contracts, briefings) and consolidate into a clean ERP foundation with core bookkeeping, invoicing, receipts, tax reporting, and calendar functionality. Reorganize database migrations into a clean numbered sequence. Co-Authored-By: Claude Opus 4.6 --- app/(auth)/login/page.tsx | 4 +- app/(dashboard)/analytics/page.tsx | 333 ---- app/(dashboard)/campaigns/[id]/page.tsx | 103 -- app/(dashboard)/campaigns/import/page.tsx | 40 - app/(dashboard)/campaigns/new/page.tsx | 351 ----- app/(dashboard)/campaigns/page.tsx | 85 -- app/(dashboard)/customers/[id]/page.tsx | 63 +- app/(dashboard)/gifts/page.tsx | 366 ----- app/(dashboard)/invoices/new/page.tsx | 35 - app/(dashboard)/page.tsx | 176 +-- app/(dashboard)/receipts/page.tsx | 27 +- app/(dashboard)/reports/page.tsx | 76 +- app/(dashboard)/settings/page.tsx | 330 +--- app/(dashboard)/shadow-ledger/new/page.tsx | 140 -- app/(dashboard)/shadow-ledger/page.tsx | 237 --- app/(onboarding)/onboarding/page.tsx | 107 +- app/api/briefings/[id]/download/route.ts | 65 - app/api/briefings/[id]/route.ts | 159 -- app/api/briefings/summarize/route.ts | 57 - app/api/calendar/feed/[token]/route.ts | 29 +- app/api/calendar/feed/route.ts | 10 +- app/api/campaigns/[id]/briefings/route.ts | 146 -- .../campaigns/[id]/briefings/upload/route.ts | 117 -- app/api/campaigns/[id]/contracts/route.ts | 185 --- app/api/campaigns/[id]/deliverables/route.ts | 126 -- app/api/campaigns/[id]/exclusivities/route.ts | 159 -- app/api/campaigns/[id]/route.ts | 204 --- app/api/campaigns/from-contract/route.ts | 321 ---- app/api/campaigns/route.ts | 173 --- app/api/campaigns/workload/route.ts | 144 -- app/api/contracts/[id]/download/route.ts | 55 - app/api/contracts/[id]/extract/route.ts | 244 --- app/api/contracts/[id]/route.ts | 163 -- app/api/customers/[id]/route.ts | 11 +- app/api/deliverables/[id]/route.ts | 153 -- app/api/deliverables/[id]/status/route.ts | 126 -- app/api/exclusivities/[id]/route.ts | 145 -- app/api/exclusivities/conflicts/route.ts | 102 -- app/api/gifts/[id]/route.ts | 168 -- app/api/gifts/estimate/route.ts | 51 - app/api/gifts/route.ts | 170 --- app/api/gifts/summary/route.ts | 81 - app/api/push/cron/route.ts | 14 +- app/api/push/subscribe/route.ts | 1 - app/api/receipts/product/route.ts | 156 -- app/api/reports/sie-export/route.ts | 2 +- app/api/settings/route.ts | 4 +- app/api/shadow-ledger/[id]/route.ts | 85 -- app/api/shadow-ledger/route.ts | 121 -- app/api/shadow-ledger/summary/route.ts | 85 -- app/api/tiktok/accounts/route.ts | 49 - app/api/tiktok/callback/route.ts | 117 -- app/api/tiktok/connect/route.ts | 47 - app/api/tiktok/cron/route.ts | 62 - app/api/tiktok/disconnect/route.ts | 61 - app/api/tiktok/stats/route.ts | 60 - app/api/tiktok/sync/route.ts | 78 - app/api/tiktok/videos/[id]/link/route.ts | 153 -- app/api/tiktok/videos/route.ts | 63 - app/api/transactions/[id]/categorize/route.ts | 27 - app/layout.tsx | 6 +- app/page.tsx | 58 +- components/benefits/GiftForm.tsx | 290 ---- components/benefits/GiftList.tsx | 198 --- components/benefits/GiftSummaryCard.tsx | 55 - components/calendar/DeadlineForm.tsx | 5 - components/campaigns/BriefingForm.tsx | 478 ------ components/campaigns/BriefingList.tsx | 359 ----- components/campaigns/CampaignCard.tsx | 175 --- components/campaigns/CampaignDetail.tsx | 514 ------- components/campaigns/CampaignForm.tsx | 392 ----- .../campaigns/CampaignInvoiceSummary.tsx | 195 --- components/campaigns/CampaignList.tsx | 201 --- components/campaigns/CampaignStatusBadge.tsx | 37 - components/campaigns/CampaignsWidget.tsx | 159 -- components/campaigns/ContractList.tsx | 326 ---- components/campaigns/ContractUpload.tsx | 214 --- components/campaigns/DeliverableCard.tsx | 247 --- components/campaigns/DeliverableForm.tsx | 251 --- components/campaigns/DeliverableList.tsx | 190 --- components/campaigns/ExclusivityForm.tsx | 381 ----- components/campaigns/ExclusivityList.tsx | 202 --- components/campaigns/index.ts | 14 - components/chat/ChatPanel.tsx | 10 +- components/contracts/ConfidenceIndicator.tsx | 100 -- components/contracts/ContractImportWizard.tsx | 1356 ----------------- .../contracts/ExtractionStatusBadge.tsx | 68 - components/dashboard/DashboardContent.tsx | 102 +- components/dashboard/DashboardNav.tsx | 43 +- components/dashboard/GiftTaxDebtCard.tsx | 79 - .../dashboard/LightDashboardContent.tsx | 134 -- components/dashboard/RecentPayoutsCard.tsx | 94 -- components/dashboard/SGIShieldWidget.tsx | 107 -- components/dashboard/SafeToSpendGauge.tsx | 131 -- components/onboarding/DashboardTour.tsx | 2 +- components/onboarding/NewUserChecklist.tsx | 2 +- components/onboarding/Step1EntityType.tsx | 8 +- components/onboarding/Step2CompanyDetails.tsx | 2 +- .../onboarding/Step2LightPersonalInfo.tsx | 100 -- .../onboarding/Step3LightTaxProfile.tsx | 526 ------- .../onboarding/Step3TaxRegistration.tsx | 2 +- components/receipts/ProductCapture.tsx | 473 ------ components/receipts/ReceiptDashboard.tsx | 14 +- components/receipts/index.ts | 1 - components/settings/CalendarFeedSettings.tsx | 33 - components/settings/NotificationSettings.tsx | 17 - components/shadow-ledger/PayoutWaterfall.tsx | 139 -- components/shadow-ledger/ShadowLedgerForm.tsx | 388 ----- components/shadow-ledger/ShadowLedgerList.tsx | 199 --- components/tiktok/TikTokAccountCard.tsx | 225 --- components/tiktok/TikTokConnectButton.tsx | 84 - components/tiktok/TikTokGrowthChart.tsx | 174 --- components/tiktok/TikTokROITable.tsx | 142 -- components/tiktok/TikTokStatsWidget.tsx | 162 -- components/tiktok/TikTokVideoCard.tsx | 132 -- components/tiktok/TikTokVideoList.tsx | 117 -- components/tiktok/VideoLinkModal.tsx | 249 --- components/tiktok/index.ts | 8 - .../transactions/SwipeCategorizationView.tsx | 2 - components/transactions/TransactionForm.tsx | 2 - components/ui/empty-state.tsx | 28 - lib/ai/chatbot/prompts.ts | 15 +- lib/ai/ingestion/ingest.ts | 4 +- lib/benefits/gift-booking.ts | 219 --- lib/benefits/gift-classifier.ts | 291 ---- lib/bookkeeping/category-mapping.ts | 5 - lib/calendar/ics-generator.ts | 111 +- lib/calendar/utils.ts | 198 +-- lib/campaigns/deadline-generator.ts | 267 ---- lib/campaigns/exclusivity-checker.ts | 212 --- lib/campaigns/index.ts | 4 - lib/campaigns/payment-tracker.ts | 252 --- lib/campaigns/workload-analyzer.ts | 287 ---- lib/contracts/contract-analyzer.ts | 424 ------ lib/contracts/pdf-extractor.ts | 33 - lib/customers/customer-matcher.ts | 231 --- lib/email/resend.ts | 6 +- lib/invoices/reminder-processor.ts | 2 +- lib/light/dashboard-data.ts | 193 --- lib/push/notification-scheduler.ts | 111 -- lib/push/web-push.ts | 31 +- lib/receipts/receipt-categorizer.ts | 4 - lib/reports/ne-declaration.ts | 78 - lib/reports/sie-export.ts | 2 +- lib/reports/sru-generator.ts | 2 +- lib/reports/vat-declaration.ts | 2 - lib/supabase/middleware.ts | 11 +- lib/tax/deadline-config.ts | 2 +- lib/tax/expense-warnings.ts | 2 - lib/tax/light-calculator.ts | 145 -- lib/tiktok/api.ts | 164 -- lib/tiktok/encryption.ts | 105 -- lib/tiktok/metrics.ts | 318 ---- lib/tiktok/oauth.ts | 251 --- lib/tiktok/rate-limiter.ts | 107 -- lib/tiktok/sync.ts | 394 ----- lib/tiktok/types.ts | 101 -- lib/transactions/category-suggestions.ts | 2 - package-lock.json | 4 +- package.json | 2 +- public/manifest.json | 6 +- public/sw.js | 2 +- .../migrations/20240101000001_core_schema.sql | 403 +++++ .../migrations/20240101000002_bookkeeping.sql | 285 ++++ .../20240101000003_deadlines_calendar.sql | 88 ++ .../migrations/20240101000004_receipts.sql | 118 ++ .../20240101000005_invoice_reminders.sql | 33 + .../20240101000006_schablonavdrag.sql | 36 + .../migrations/20240101000007_sie_imports.sql | 82 + .../20240101000008_push_notifications.sql | 89 ++ .../20240101000009_functions_triggers.sql | 171 +++ .../20250129_add_authorization_id.sql | 14 - .../20250129_add_potential_invoice_id.sql | 13 - .../20250129_add_schablonavdrag.sql | 60 - .../20250130_create_gifts_table.sql | 69 - .../20250130_create_sie_imports.sql | 122 -- .../migrations/20250201_create_campaigns.sql | 548 ------- .../migrations/20250201_create_deadlines.sql | 76 - .../20250202_create_tiktok_integration.sql | 315 ---- .../migrations/20250203_create_briefings.sql | 83 - .../migrations/20250204_create_receipts.sql | 179 --- .../20250205_create_invoice_reminders.sql | 75 - .../20250206_calendar_enhancements.sql | 229 --- types/index.ts | 1069 +------------ 184 files changed, 1418 insertions(+), 24763 deletions(-) delete mode 100644 app/(dashboard)/analytics/page.tsx delete mode 100644 app/(dashboard)/campaigns/[id]/page.tsx delete mode 100644 app/(dashboard)/campaigns/import/page.tsx delete mode 100644 app/(dashboard)/campaigns/new/page.tsx delete mode 100644 app/(dashboard)/campaigns/page.tsx delete mode 100644 app/(dashboard)/gifts/page.tsx delete mode 100644 app/(dashboard)/shadow-ledger/new/page.tsx delete mode 100644 app/(dashboard)/shadow-ledger/page.tsx delete mode 100644 app/api/briefings/[id]/download/route.ts delete mode 100644 app/api/briefings/[id]/route.ts delete mode 100644 app/api/briefings/summarize/route.ts delete mode 100644 app/api/campaigns/[id]/briefings/route.ts delete mode 100644 app/api/campaigns/[id]/briefings/upload/route.ts delete mode 100644 app/api/campaigns/[id]/contracts/route.ts delete mode 100644 app/api/campaigns/[id]/deliverables/route.ts delete mode 100644 app/api/campaigns/[id]/exclusivities/route.ts delete mode 100644 app/api/campaigns/[id]/route.ts delete mode 100644 app/api/campaigns/from-contract/route.ts delete mode 100644 app/api/campaigns/route.ts delete mode 100644 app/api/campaigns/workload/route.ts delete mode 100644 app/api/contracts/[id]/download/route.ts delete mode 100644 app/api/contracts/[id]/extract/route.ts delete mode 100644 app/api/contracts/[id]/route.ts delete mode 100644 app/api/deliverables/[id]/route.ts delete mode 100644 app/api/deliverables/[id]/status/route.ts delete mode 100644 app/api/exclusivities/[id]/route.ts delete mode 100644 app/api/exclusivities/conflicts/route.ts delete mode 100644 app/api/gifts/[id]/route.ts delete mode 100644 app/api/gifts/estimate/route.ts delete mode 100644 app/api/gifts/route.ts delete mode 100644 app/api/gifts/summary/route.ts delete mode 100644 app/api/receipts/product/route.ts delete mode 100644 app/api/shadow-ledger/[id]/route.ts delete mode 100644 app/api/shadow-ledger/route.ts delete mode 100644 app/api/shadow-ledger/summary/route.ts delete mode 100644 app/api/tiktok/accounts/route.ts delete mode 100644 app/api/tiktok/callback/route.ts delete mode 100644 app/api/tiktok/connect/route.ts delete mode 100644 app/api/tiktok/cron/route.ts delete mode 100644 app/api/tiktok/disconnect/route.ts delete mode 100644 app/api/tiktok/stats/route.ts delete mode 100644 app/api/tiktok/sync/route.ts delete mode 100644 app/api/tiktok/videos/[id]/link/route.ts delete mode 100644 app/api/tiktok/videos/route.ts delete mode 100644 components/benefits/GiftForm.tsx delete mode 100644 components/benefits/GiftList.tsx delete mode 100644 components/benefits/GiftSummaryCard.tsx delete mode 100644 components/campaigns/BriefingForm.tsx delete mode 100644 components/campaigns/BriefingList.tsx delete mode 100644 components/campaigns/CampaignCard.tsx delete mode 100644 components/campaigns/CampaignDetail.tsx delete mode 100644 components/campaigns/CampaignForm.tsx delete mode 100644 components/campaigns/CampaignInvoiceSummary.tsx delete mode 100644 components/campaigns/CampaignList.tsx delete mode 100644 components/campaigns/CampaignStatusBadge.tsx delete mode 100644 components/campaigns/CampaignsWidget.tsx delete mode 100644 components/campaigns/ContractList.tsx delete mode 100644 components/campaigns/ContractUpload.tsx delete mode 100644 components/campaigns/DeliverableCard.tsx delete mode 100644 components/campaigns/DeliverableForm.tsx delete mode 100644 components/campaigns/DeliverableList.tsx delete mode 100644 components/campaigns/ExclusivityForm.tsx delete mode 100644 components/campaigns/ExclusivityList.tsx delete mode 100644 components/campaigns/index.ts delete mode 100644 components/contracts/ConfidenceIndicator.tsx delete mode 100644 components/contracts/ContractImportWizard.tsx delete mode 100644 components/contracts/ExtractionStatusBadge.tsx delete mode 100644 components/dashboard/GiftTaxDebtCard.tsx delete mode 100644 components/dashboard/LightDashboardContent.tsx delete mode 100644 components/dashboard/RecentPayoutsCard.tsx delete mode 100644 components/dashboard/SGIShieldWidget.tsx delete mode 100644 components/dashboard/SafeToSpendGauge.tsx delete mode 100644 components/onboarding/Step2LightPersonalInfo.tsx delete mode 100644 components/onboarding/Step3LightTaxProfile.tsx delete mode 100644 components/receipts/ProductCapture.tsx delete mode 100644 components/shadow-ledger/PayoutWaterfall.tsx delete mode 100644 components/shadow-ledger/ShadowLedgerForm.tsx delete mode 100644 components/shadow-ledger/ShadowLedgerList.tsx delete mode 100644 components/tiktok/TikTokAccountCard.tsx delete mode 100644 components/tiktok/TikTokConnectButton.tsx delete mode 100644 components/tiktok/TikTokGrowthChart.tsx delete mode 100644 components/tiktok/TikTokROITable.tsx delete mode 100644 components/tiktok/TikTokStatsWidget.tsx delete mode 100644 components/tiktok/TikTokVideoCard.tsx delete mode 100644 components/tiktok/TikTokVideoList.tsx delete mode 100644 components/tiktok/VideoLinkModal.tsx delete mode 100644 components/tiktok/index.ts delete mode 100644 lib/benefits/gift-booking.ts delete mode 100644 lib/benefits/gift-classifier.ts delete mode 100644 lib/campaigns/deadline-generator.ts delete mode 100644 lib/campaigns/exclusivity-checker.ts delete mode 100644 lib/campaigns/index.ts delete mode 100644 lib/campaigns/payment-tracker.ts delete mode 100644 lib/campaigns/workload-analyzer.ts delete mode 100644 lib/contracts/contract-analyzer.ts delete mode 100644 lib/contracts/pdf-extractor.ts delete mode 100644 lib/customers/customer-matcher.ts delete mode 100644 lib/light/dashboard-data.ts delete mode 100644 lib/tax/light-calculator.ts delete mode 100644 lib/tiktok/api.ts delete mode 100644 lib/tiktok/encryption.ts delete mode 100644 lib/tiktok/metrics.ts delete mode 100644 lib/tiktok/oauth.ts delete mode 100644 lib/tiktok/rate-limiter.ts delete mode 100644 lib/tiktok/sync.ts delete mode 100644 lib/tiktok/types.ts create mode 100644 supabase/migrations/20240101000001_core_schema.sql create mode 100644 supabase/migrations/20240101000002_bookkeeping.sql create mode 100644 supabase/migrations/20240101000003_deadlines_calendar.sql create mode 100644 supabase/migrations/20240101000004_receipts.sql create mode 100644 supabase/migrations/20240101000005_invoice_reminders.sql create mode 100644 supabase/migrations/20240101000006_schablonavdrag.sql create mode 100644 supabase/migrations/20240101000007_sie_imports.sql create mode 100644 supabase/migrations/20240101000008_push_notifications.sql create mode 100644 supabase/migrations/20240101000009_functions_triggers.sql delete mode 100644 supabase/migrations/20250129_add_authorization_id.sql delete mode 100644 supabase/migrations/20250129_add_potential_invoice_id.sql delete mode 100644 supabase/migrations/20250129_add_schablonavdrag.sql delete mode 100644 supabase/migrations/20250130_create_gifts_table.sql delete mode 100644 supabase/migrations/20250130_create_sie_imports.sql delete mode 100644 supabase/migrations/20250201_create_campaigns.sql delete mode 100644 supabase/migrations/20250201_create_deadlines.sql delete mode 100644 supabase/migrations/20250202_create_tiktok_integration.sql delete mode 100644 supabase/migrations/20250203_create_briefings.sql delete mode 100644 supabase/migrations/20250204_create_receipts.sql delete mode 100644 supabase/migrations/20250205_create_invoice_reminders.sql delete mode 100644 supabase/migrations/20250206_calendar_enhancements.sql diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx index b83fcd1a..489f82d7 100644 --- a/app/(auth)/login/page.tsx +++ b/app/(auth)/login/page.tsx @@ -89,9 +89,9 @@ export default function LoginPage() {
- Influencer Assistant + ERP Base - Logga in med din e-post för att hantera din verksamhet + Logga in med din e-post för att hantera din ekonomi diff --git a/app/(dashboard)/analytics/page.tsx b/app/(dashboard)/analytics/page.tsx deleted file mode 100644 index 6a58d0a4..00000000 --- a/app/(dashboard)/analytics/page.tsx +++ /dev/null @@ -1,333 +0,0 @@ -'use client' - -import { useState, useEffect } from 'react' -import { useRouter } from 'next/navigation' -import { createClient } from '@/lib/supabase/client' -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' -import { Button } from '@/components/ui/button' -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' -import { - TikTokConnectButton, - TikTokAccountCard, - TikTokStatsWidget, - TikTokGrowthChart, - TikTokVideoList, - VideoLinkModal, - TikTokROITable, -} from '@/components/tiktok' -import type { TikTokAccount, TikTokStatsSummary, TikTokVideo, TikTokCampaignROI } from '@/types' -import { - Loader2, - TrendingUp, - Video, - Target, - BarChart3, -} from 'lucide-react' - -export default function AnalyticsPage() { - const router = useRouter() - const supabase = createClient() - - const [isLoading, setIsLoading] = useState(true) - const [accounts, setAccounts] = useState([]) - const [stats, setStats] = useState(null) - const [roiData, setRoiData] = useState([]) - const [selectedVideo, setSelectedVideo] = useState(null) - const [isLinkModalOpen, setIsLinkModalOpen] = useState(false) - const [isSyncing, setIsSyncing] = useState(false) - - useEffect(() => { - checkAuth() - }, []) - - const checkAuth = async () => { - const { data: { user } } = await supabase.auth.getUser() - if (!user) { - router.push('/login') - return - } - fetchData() - } - - const fetchData = async () => { - setIsLoading(true) - await Promise.all([ - fetchAccounts(), - fetchStats(), - fetchROI(), - ]) - setIsLoading(false) - } - - const fetchAccounts = async () => { - try { - const response = await fetch('/api/tiktok/accounts') - const data = await response.json() - setAccounts(data.accounts || []) - } catch (error) { - console.error('Failed to fetch accounts:', error) - } - } - - const fetchStats = async () => { - try { - const response = await fetch('/api/tiktok/stats') - const data = await response.json() - setStats(data.summary || null) - } catch (error) { - console.error('Failed to fetch stats:', error) - } - } - - const fetchROI = async () => { - // Fetch campaigns with TikTok videos for ROI calculation - try { - const response = await fetch('/api/tiktok/videos?limit=100') - const data = await response.json() - - // Group videos by campaign and calculate ROI - // This is a simplified version - the actual calculation is in the API - const campaignVideos = new Map() - for (const video of data.videos || []) { - if (video.campaign_id) { - if (!campaignVideos.has(video.campaign_id)) { - campaignVideos.set(video.campaign_id, []) - } - campaignVideos.get(video.campaign_id)!.push(video) - } - } - - // For now, just set empty - actual ROI data would come from a dedicated endpoint - setRoiData([]) - } catch (error) { - console.error('Failed to fetch ROI data:', error) - } - } - - const handleSync = async () => { - if (accounts.length === 0) return - - setIsSyncing(true) - try { - const activeAccount = accounts.find(a => a.status === 'active') - if (activeAccount) { - await fetch('/api/tiktok/sync', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ account_id: activeAccount.id, sync_type: 'full' }), - }) - await fetchData() - } - } catch (error) { - console.error('Sync failed:', error) - } - setIsSyncing(false) - } - - const handleVideoLinkClick = (video: TikTokVideo) => { - setSelectedVideo(video) - setIsLinkModalOpen(true) - } - - if (isLoading) { - return ( -
- -
- ) - } - - const activeAccount = accounts.find(a => a.status === 'active') - - return ( -
-
-

Analytics

-

- Analysera din sociala medieprestanda och kampanj-ROI -

-
- - {/* No connected account */} - {accounts.length === 0 && ( - - - Koppla TikTok - - Anslut ditt TikTok-konto för att se statistik och analysera kampanjprestanda - - - - - - - )} - - {/* Connected account */} - {activeAccount && ( - <> - {/* Stats overview */} -
- - -
- - Följare -
-

- {stats?.currentFollowers.toLocaleString('sv-SE') || '0'} -

- {stats?.followerChange7d !== undefined && ( -

= 0 ? 'text-success' : 'text-destructive'}`}> - {stats.followerChange7d >= 0 ? '+' : ''}{stats.followerChange7d.toLocaleString('sv-SE')} senaste 7 dagar -

- )} -
-
- - - -
-
-

- {stats?.totalVideos || 0} -

-

- {stats?.totalLikes.toLocaleString('sv-SE') || '0'} totala likes -

-
-
- - - -
- - Engagement Rate -
-

- {stats?.engagementRate.toFixed(1) || '0'}% -

-

- Genomsnitt senaste videor -

-
-
- - - -
- - 30-dagars tillväxt -
-

- {stats?.followerChange30d !== undefined ? ( - <> - {stats.followerChange30d >= 0 ? '+' : ''} - {stats.followerChange30d.toLocaleString('sv-SE')} - - ) : '0'} -

-

- nya följare -

-
-
-
- - {/* Tabs for different views */} - - - Tillväxt - Videor - Kampanj-ROI - - - - - - {/* Recent videos with metrics */} - - - Senaste videor - - Prestanda för dina senaste publiceringar - - - - - - - - - - - -
-
- Alla videor - - Klicka på länk-ikonen för att koppla en video till en kampanj - -
-
-
- - - -
-
- - - - - Kampanj-ROI - - Analysera avkastningen på dina influencer-kampanjer baserat på TikTok-prestanda - - - - - - - -
- - {/* Account info at bottom */} - - - Kopplat konto - - - - - - - )} - - {/* Video link modal */} - { - setIsLinkModalOpen(false) - setSelectedVideo(null) - }} - onSuccess={fetchData} - /> -
- ) -} diff --git a/app/(dashboard)/campaigns/[id]/page.tsx b/app/(dashboard)/campaigns/[id]/page.tsx deleted file mode 100644 index 72b7c3ef..00000000 --- a/app/(dashboard)/campaigns/[id]/page.tsx +++ /dev/null @@ -1,103 +0,0 @@ -'use client' - -import { useState, useEffect, use } from 'react' -import { createClient } from '@/lib/supabase/client' -import { Campaign, Customer } from '@/types' -import { CampaignDetail, CampaignForm } from '@/components/campaigns' -import { useToast } from '@/components/ui/use-toast' -import { Skeleton } from '@/components/ui/skeleton' - -interface PageProps { - params: Promise<{ id: string }> -} - -export default function CampaignDetailPage({ params }: PageProps) { - const { id } = use(params) - const supabase = createClient() - const { toast } = useToast() - const [campaign, setCampaign] = useState(null) - const [customers, setCustomers] = useState([]) - const [loading, setLoading] = useState(true) - const [editFormOpen, setEditFormOpen] = useState(false) - - const fetchCampaign = async () => { - try { - const response = await fetch(`/api/campaigns/${id}`) - if (response.ok) { - const { data } = await response.json() - setCampaign(data) - } else { - toast({ - title: 'Fel', - description: 'Samarbetet hittades inte', - variant: 'destructive', - }) - } - } catch (error) { - toast({ - title: 'Fel', - description: 'Kunde inte ladda samarbetet', - variant: 'destructive', - }) - } finally { - setLoading(false) - } - } - - const fetchCustomers = async () => { - const { data } = await supabase - .from('customers') - .select('*') - .order('name') - setCustomers(data || []) - } - - useEffect(() => { - fetchCampaign() - fetchCustomers() - }, [id]) - - if (loading) { - return ( -
- - -
- {[1, 2, 3, 4].map(i => ( - - ))} -
- -
- ) - } - - if (!campaign) { - return ( -
-

Samarbetet hittades inte

-
- ) - } - - return ( - <> - setEditFormOpen(true)} - /> - - { - setEditFormOpen(false) - fetchCampaign() - }} - /> - - ) -} diff --git a/app/(dashboard)/campaigns/import/page.tsx b/app/(dashboard)/campaigns/import/page.tsx deleted file mode 100644 index 95bf8f95..00000000 --- a/app/(dashboard)/campaigns/import/page.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { createClient } from '@/lib/supabase/server' -import { redirect } from 'next/navigation' -import { ContractImportWizard } from '@/components/contracts/ContractImportWizard' - -export const metadata = { - title: 'Importera avtal | Samarbeten', - description: 'Importera och analysera avtal med AI', -} - -export default async function CampaignImportPage() { - const supabase = await createClient() - - const { - data: { user }, - } = await supabase.auth.getUser() - - if (!user) { - redirect('/login') - } - - // Fetch customers for matching - const { data: customers } = await supabase - .from('customers') - .select('*') - .eq('user_id', user.id) - .order('name') - - return ( -
-
-

Importera avtal

-

- Ladda upp ett avtal och låt AI extrahera samarbetsinformation automatiskt -

-
- - -
- ) -} diff --git a/app/(dashboard)/campaigns/new/page.tsx b/app/(dashboard)/campaigns/new/page.tsx deleted file mode 100644 index d2c17712..00000000 --- a/app/(dashboard)/campaigns/new/page.tsx +++ /dev/null @@ -1,351 +0,0 @@ -'use client' - -import { useState, useEffect } from 'react' -import { useRouter } from 'next/navigation' -import { createClient } from '@/lib/supabase/client' -import { Customer, CreateCampaignInput, CampaignType, BillingFrequency } from '@/types' -import { - CAMPAIGN_TYPE_LABELS, - BILLING_FREQUENCY_LABELS, -} from '@/types' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' -import { Textarea } from '@/components/ui/textarea' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select' -import { Switch } from '@/components/ui/switch' -import { useToast } from '@/components/ui/use-toast' -import { ArrowLeft } from 'lucide-react' -import Link from 'next/link' - -const CURRENCIES = ['SEK', 'EUR', 'USD', 'GBP', 'NOK', 'DKK'] - -export default function NewCampaignPage() { - const router = useRouter() - const supabase = createClient() - const { toast } = useToast() - const [customers, setCustomers] = useState([]) - const [isLoading, setIsLoading] = useState(false) - - const [formData, setFormData] = useState({ - name: '', - description: '', - customer_id: '', - brand_name: '', - campaign_type: 'influencer', - total_value: undefined, - currency: 'SEK', - vat_included: false, - payment_terms: 30, - billing_frequency: undefined, - publication_date: '', - draft_deadline: '', - notes: '', - }) - - useEffect(() => { - const fetchCustomers = async () => { - const { data } = await supabase - .from('customers') - .select('*') - .order('name') - setCustomers(data || []) - } - fetchCustomers() - }, []) - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault() - - if (!formData.name) { - toast({ title: 'Namn krävs', variant: 'destructive' }) - return - } - - setIsLoading(true) - - try { - const response = await fetch('/api/campaigns', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - ...formData, - customer_id: formData.customer_id || null, - brand_name: formData.brand_name || null, - total_value: formData.total_value || null, - payment_terms: formData.payment_terms || null, - billing_frequency: formData.billing_frequency || null, - publication_date: formData.publication_date || null, - draft_deadline: formData.draft_deadline || null, - }), - }) - - if (!response.ok) { - const error = await response.json() - throw new Error(error.error || 'Failed to create campaign') - } - - const { data } = await response.json() - - toast({ - title: 'Samarbete skapat', - description: formData.name, - }) - - router.push(`/campaigns/${data.id}`) - } catch (error) { - toast({ - title: 'Fel', - description: error instanceof Error ? error.message : 'Något gick fel', - variant: 'destructive', - }) - } finally { - setIsLoading(false) - } - } - - return ( -
-
- - - Tillbaka till samarbeten - -

Nytt samarbete

-

- Skapa ett nytt samarbete för att spåra innehåll, avtal och betalningar -

-
- -
- - - Grundläggande information - - -
- - setFormData({ ...formData, name: e.target.value })} - placeholder="T.ex. Sommarkampanj 2025" - required - /> -
- -
- -