video preview version

This commit is contained in:
fahed
2026-02-08 22:51:42 +03:00
parent 5f7d922f92
commit 9b58e5e9aa
23 changed files with 890 additions and 544 deletions
+29 -26
View File
@@ -1,14 +1,20 @@
import { useContext, useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { format, isAfter, isBefore, addDays } from 'date-fns'
import { FileText, Megaphone, AlertTriangle, Users, ArrowRight, Clock, Wallet, TrendingUp, DollarSign, PiggyBank } from 'lucide-react'
import { FileText, Megaphone, AlertTriangle, ArrowRight, Clock, Wallet, TrendingUp, DollarSign, PiggyBank } from 'lucide-react'
import { AppContext } from '../App'
import { useLanguage } from '../i18n/LanguageContext'
import { api } from '../utils/api'
import { api, PRIORITY_CONFIG } from '../utils/api'
import StatCard from '../components/StatCard'
import StatusBadge from '../components/StatusBadge'
import BrandBadge from '../components/BrandBadge'
function getBudgetBarColor(percentage) {
if (percentage > 90) return 'bg-red-500'
if (percentage > 70) return 'bg-amber-500'
return 'bg-emerald-500'
}
function FinanceMini({ finance }) {
const { t } = useLanguage()
if (!finance) return null
@@ -17,7 +23,7 @@ function FinanceMini({ finance }) {
const remaining = finance.remaining || 0
const roi = finance.roi || 0
const pct = totalReceived > 0 ? (spent / totalReceived) * 100 : 0
const barColor = pct > 90 ? 'bg-red-500' : pct > 70 ? 'bg-amber-500' : 'bg-emerald-500'
const barColor = getBudgetBarColor(pct)
return (
<div className="bg-white rounded-xl border border-border p-5">
@@ -74,6 +80,7 @@ function FinanceMini({ finance }) {
}
function ActiveCampaignsList({ campaigns, finance }) {
const { t } = useLanguage()
const active = campaigns.filter(c => c.status === 'active')
const campaignData = (finance?.campaigns || []).filter(c => c.status === 'active')
@@ -93,7 +100,7 @@ function ActiveCampaignsList({ campaigns, finance }) {
const spent = cd.tracks_spent || 0
const allocated = cd.tracks_allocated || 0
const pct = allocated > 0 ? (spent / allocated) * 100 : 0
const barColor = pct > 90 ? 'bg-red-500' : pct > 70 ? 'bg-amber-500' : 'bg-emerald-500'
const barColor = getBudgetBarColor(pct)
return (
<Link key={c._id || c.id} to={`/campaigns/${c._id || c.id}`} className="flex items-center gap-4 px-5 py-3 hover:bg-surface-secondary transition-colors">
<div className="flex-1 min-w-0">
@@ -190,10 +197,10 @@ export default function Dashboard() {
{/* Welcome */}
<div>
<h1 className="text-2xl font-bold text-text-primary">
Welcome back, {currentUser?.name || 'there'} 👋
{t('dashboard.welcomeBack')}, {currentUser?.name || 'there'}
</h1>
<p className="text-text-secondary mt-1">
Here's what's happening with your marketing today.
{t('dashboard.happeningToday')}
</p>
</div>
@@ -201,30 +208,30 @@ export default function Dashboard() {
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 stagger-children">
<StatCard
icon={FileText}
label="Total Posts"
label={t('dashboard.totalPosts')}
value={posts.length || 0}
subtitle={`${posts.filter(p => p.status === 'published').length} published`}
subtitle={`${posts.filter(p => p.status === 'published').length} ${t('dashboard.published')}`}
color="brand-primary"
/>
<StatCard
icon={Megaphone}
label="Active Campaigns"
label={t('dashboard.activeCampaigns')}
value={activeCampaigns}
subtitle={`${campaigns.length} total`}
subtitle={`${campaigns.length} ${t('dashboard.total')}`}
color="brand-secondary"
/>
<StatCard
icon={Wallet}
label="Budget Spent"
value={`${((finance?.spent || 0)).toLocaleString()}`}
subtitle={finance?.totalReceived ? `of ${finance.totalReceived.toLocaleString()} SAR` : 'No budget yet'}
label={t('dashboard.budgetSpent')}
value={`${(finance?.spent || 0).toLocaleString()}`}
subtitle={finance?.totalReceived ? `${t('dashboard.of')} ${finance.totalReceived.toLocaleString()} ${t('dashboard.sar')}` : t('dashboard.noBudget')}
color="brand-tertiary"
/>
<StatCard
icon={AlertTriangle}
label="Overdue Tasks"
label={t('dashboard.overdueTasks')}
value={overdueTasks}
subtitle={overdueTasks > 0 ? 'Needs attention' : 'All on track'}
subtitle={overdueTasks > 0 ? t('dashboard.needsAttention') : t('dashboard.allOnTrack')}
color="brand-quaternary"
/>
</div>
@@ -245,15 +252,15 @@ export default function Dashboard() {
{/* Recent Posts */}
<div className="bg-white rounded-xl border border-border">
<div className="flex items-center justify-between px-5 py-4 border-b border-border">
<h3 className="font-semibold text-text-primary">Recent Posts</h3>
<h3 className="font-semibold text-text-primary">{t('dashboard.recentPosts')}</h3>
<Link to="/posts" className="text-sm text-brand-primary hover:text-brand-primary-light font-medium flex items-center gap-1">
View all <ArrowRight className="w-3.5 h-3.5" />
{t('dashboard.viewAll')} <ArrowRight className="w-3.5 h-3.5" />
</Link>
</div>
<div className="divide-y divide-border-light">
{posts.length === 0 ? (
<div className="py-12 text-center text-sm text-text-tertiary">
No posts yet. Create your first post!
{t('dashboard.noPostsYet')}
</div>
) : (
posts.slice(0, 8).map((post) => (
@@ -274,24 +281,20 @@ export default function Dashboard() {
{/* Upcoming Deadlines */}
<div className="bg-white rounded-xl border border-border">
<div className="flex items-center justify-between px-5 py-4 border-b border-border">
<h3 className="font-semibold text-text-primary">Upcoming Deadlines</h3>
<h3 className="font-semibold text-text-primary">{t('dashboard.upcomingDeadlines')}</h3>
<Link to="/tasks" className="text-sm text-brand-primary hover:text-brand-primary-light font-medium flex items-center gap-1">
View all <ArrowRight className="w-3.5 h-3.5" />
{t('dashboard.viewAll')} <ArrowRight className="w-3.5 h-3.5" />
</Link>
</div>
<div className="divide-y divide-border-light">
{upcomingDeadlines.length === 0 ? (
<div className="py-12 text-center text-sm text-text-tertiary">
No upcoming deadlines this week. 🎉
{t('dashboard.noUpcomingDeadlines')}
</div>
) : (
upcomingDeadlines.map((task) => (
<div key={task._id} className="flex items-center gap-3 px-5 py-3 hover:bg-surface-secondary transition-colors">
<div className={`w-2 h-2 rounded-full ${
task.priority === 'urgent' ? 'bg-red-500' :
task.priority === 'high' ? 'bg-orange-500' :
task.priority === 'medium' ? 'bg-amber-400' : 'bg-gray-400'
}`} />
<div className={`w-2 h-2 rounded-full ${(PRIORITY_CONFIG[task.priority] || PRIORITY_CONFIG.medium).color}`} />
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-text-primary truncate">{task.title}</p>
<StatusBadge status={task.status} size="xs" />