Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 102 additions & 56 deletions frontend/src/app/audit/page.tsx

Large diffs are not rendered by default.

31 changes: 22 additions & 9 deletions frontend/src/app/dashboard/components/ActivityHeatmap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useEffect, useState } from 'react';
import { useSupabase } from '@/contexts/SupabaseProvider';
import { useLanguage } from '@/contexts/LanguageContext';
import { Activity, TrendingUp } from 'lucide-react';

interface HourlyActivity {
Expand All @@ -12,13 +13,22 @@ interface HourlyActivity {

export default function ActivityHeatmap() {
const { supabase, user } = useSupabase();
const { t } = useLanguage();
const [hourlyData, setHourlyData] = useState<HourlyActivity[]>([]);
const [loading, setLoading] = useState(true);
const [maxActivity, setMaxActivity] = useState(0);
const [totalActions, setTotalActions] = useState(0);
const [weeklyActions, setWeeklyActions] = useState(0);

const days = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
const days = [
t('dashboard', 'sundayShort'),
t('dashboard', 'mondayShort'),
t('dashboard', 'tuesdayShort'),
t('dashboard', 'wednesdayShort'),
t('dashboard', 'thursdayShort'),
t('dashboard', 'fridayShort'),
t('dashboard', 'saturdayShort'),
];
const hours = Array.from({ length: 24 }, (_, i) => i);

useEffect(() => {
Expand Down Expand Up @@ -121,10 +131,10 @@ export default function ActivityHeatmap() {
</div>
<div>
<h3 className="text-sm font-semibold text-gray-900 dark:text-white">
Activity Pattern
{t('dashboard', 'activityPattern')}
</h3>
<p className="text-xs text-gray-500 dark:text-gray-400">
Last 30 days
{t('dashboard', 'last30Days')}
</p>
</div>
</div>
Expand All @@ -134,11 +144,11 @@ export default function ActivityHeatmap() {
<span className="text-xs font-bold text-violet-700 dark:text-violet-300">
{totalActions.toLocaleString()}
</span>
<span className="text-xs text-violet-600 dark:text-violet-400">total</span>
<span className="text-xs text-violet-600 dark:text-violet-400">{t('dashboard', 'total')}</span>
</div>
<div className="flex items-center gap-1 text-xs text-gray-500 dark:text-gray-400">
<TrendingUp className="h-3 w-3" />
<span>{avgDailyActions}/day avg</span>
<span>{t('dashboard', 'dayAverage').replace('{count}', String(avgDailyActions))}</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -184,7 +194,10 @@ export default function ActivityHeatmap() {
hover:scale-125 hover:z-10 hover:shadow-lg cursor-pointer
${getHeatmapColor(count)}
`}
title={`${days[dayIndex]} ${hour}:00 - ${count} actions`}
title={t('dashboard', 'activityCellTitle')
.replace('{day}', days[dayIndex])
.replace('{hour}', String(hour))
.replace('{count}', String(count))}
/>
);
})}
Expand All @@ -196,7 +209,7 @@ export default function ActivityHeatmap() {

{/* Compact Legend */}
<div className="flex items-center justify-center gap-2 mt-3 pt-2 border-t border-gray-200 dark:border-gray-700/50">
<span className="text-[10px] text-gray-500 dark:text-gray-400">Less</span>
<span className="text-[10px] text-gray-500 dark:text-gray-400">{t('dashboard', 'less')}</span>
<div className="flex gap-[2px]">
{[0, 20, 40, 60, 80, 100].map((_, i) => (
<div
Expand All @@ -212,9 +225,9 @@ export default function ActivityHeatmap() {
/>
))}
</div>
<span className="text-[10px] text-gray-500 dark:text-gray-400">More</span>
<span className="text-[10px] text-gray-500 dark:text-gray-400">{t('dashboard', 'more')}</span>
</div>
</div>
</div>
);
}
}
16 changes: 9 additions & 7 deletions frontend/src/app/dashboard/components/CompactQuickAccess.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useRouter } from 'next/navigation';
import { Network, Home, Layout, ArrowRight, Sparkles } from 'lucide-react';
import { useLanguage } from '@/contexts/LanguageContext';

interface QuickAccessItem {
icon: React.ReactNode;
Expand All @@ -14,29 +15,30 @@ interface QuickAccessItem {

export default function CompactQuickAccess() {
const router = useRouter();
const { t } = useLanguage();

const items: QuickAccessItem[] = [
{
icon: <Home className="h-5 w-5" />,
title: "Cockpit",
title: t('dashboard', 'cockpit'),
href: "/cockpit",
gradient: "from-violet-500 to-purple-600",
description: "Control & monitor your robot",
description: t('dashboard', 'cockpitDescription'),
highlight: true
},
{
icon: <Network className="h-5 w-5" />,
title: "Fleet Manager",
title: t('dashboard', 'fleetManager'),
href: "/fleet",
gradient: "from-blue-500 to-cyan-600",
description: "Manage all your robots"
description: t('dashboard', 'fleetManagerDescription')
},
{
icon: <Layout className="h-5 w-5" />,
title: "My UI",
title: t('dashboard', 'myUI'),
href: "/my-ui",
gradient: "from-green-500 to-emerald-600",
description: "Customize your workspace"
description: t('dashboard', 'myUIDescription')
}
];

Expand Down Expand Up @@ -113,4 +115,4 @@ export default function CompactQuickAccess() {
))}
</div>
);
}
}
72 changes: 37 additions & 35 deletions frontend/src/app/dashboard/components/EnhancedQuickStats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from 'lucide-react';
import { useRobotConnection } from '@/contexts/RobotConnectionContext';
import { useSupabase } from '@/contexts/SupabaseProvider';
import { useLanguage } from '@/contexts/LanguageContext';
import type { Database } from '@/types/database.types';

type Robot = Database['public']['Tables']['robots']['Row'];
Expand Down Expand Up @@ -112,6 +113,7 @@ function StatCard({
export default function EnhancedQuickStats() {
const { connection } = useRobotConnection();
const { supabase, user } = useSupabase();
const { t } = useLanguage();
const [loading, setLoading] = useState(true);

// Basic stats
Expand All @@ -123,9 +125,9 @@ export default function EnhancedQuickStats() {
const [monthlyActions, setMonthlyActions] = useState<number>(0);

// Enhanced stats
const [memberDuration, setMemberDuration] = useState<string>('New');
const [memberDuration, setMemberDuration] = useState<string>('');
const [peakHour, setPeakHour] = useState<string>('--');
const [mostUsedRobot, setMostUsedRobot] = useState<string>('None');
const [mostUsedRobot, setMostUsedRobot] = useState<string>('');
const [activeDays, setActiveDays] = useState<number>(0);
const [missionsTotal, setMissionsTotal] = useState<number>(0);
const [detectionsCount, setDetectionsCount] = useState<number>(0);
Expand Down Expand Up @@ -159,13 +161,13 @@ export default function EnhancedQuickStats() {
const diffYears = Math.floor(diffDays / 365);

if (diffYears > 0) {
setMemberDuration(`${diffYears}+ year${diffYears > 1 ? 's' : ''}`);
setMemberDuration(`${diffYears}+ ${t('dashboard', diffYears > 1 ? 'years' : 'year')}`);
} else if (diffMonths > 0) {
setMemberDuration(`${diffMonths} month${diffMonths > 1 ? 's' : ''}`);
setMemberDuration(`${diffMonths} ${t('dashboard', diffMonths > 1 ? 'months' : 'month')}`);
} else if (diffDays > 0) {
setMemberDuration(`${diffDays} day${diffDays > 1 ? 's' : ''}`);
setMemberDuration(`${diffDays} ${t('dashboard', diffDays > 1 ? 'days' : 'day')}`);
} else {
setMemberDuration('New member');
setMemberDuration(t('dashboard', 'newMember'));
}
}

Expand Down Expand Up @@ -325,7 +327,7 @@ export default function EnhancedQuickStats() {
};

fetchAllStats();
}, [user, supabase]);
}, [user, supabase, t]);

const onlineRobots = connection.online ? 1 : 0;

Expand All @@ -335,32 +337,32 @@ export default function EnhancedQuickStats() {
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
<StatCard
icon={<Bot className="h-5 w-5 text-white" />}
label="Fleet Size"
label={t('dashboard', 'fleetSize')}
value={robots.length}
subValue={`${onlineRobots} online now`}
subValue={`${onlineRobots} ${t('dashboard', 'onlineNow')}`}
trend={robots.length > 0 ? 'up' : 'neutral'}
trendValue={onlineRobots > 0 ? 'Active' : 'Offline'}
trendValue={onlineRobots > 0 ? t('dashboard', 'active') : t('dashboard', 'offline')}
gradient="from-violet-500 to-purple-600"
variant="gradient"
loading={loading}
/>

<StatCard
icon={<Activity className="h-5 w-5 text-white" />}
label="Total Actions"
label={t('dashboard', 'totalActions')}
value={totalActions > 9999 ? `${(totalActions / 1000).toFixed(1)}k` : totalActions}
subValue={`${activeDays} active days`}
subValue={`${activeDays} ${t('dashboard', 'activeDays')}`}
trend={monthlyActions > 500 ? 'up' : 'down'}
trendValue={`${monthlyActions} this month`}
trendValue={`${monthlyActions} ${t('dashboard', 'thisMonth')}`}
gradient="from-blue-500 to-cyan-600"
variant="glass"
loading={loading}
/>

<StatCard
icon={<Calendar className="h-5 w-5 text-white" />}
label="User Since"
value={memberDuration}
label={t('dashboard', 'userSince')}
value={memberDuration || t('dashboard', 'new')}
subValue={userProfile ? new Date(userProfile.created_at).toLocaleDateString() : '--'}
gradient="from-emerald-500 to-teal-600"
variant="default"
Expand All @@ -369,9 +371,9 @@ export default function EnhancedQuickStats() {

<StatCard
icon={<Star className="h-5 w-5 text-white" />}
label="Favorite Robot"
value={mostUsedRobot}
subValue={robots.filter(r => r.is_favorite).length > 0 ? 'Most used' : 'No favorite set'}
label={t('dashboard', 'favoriteRobot')}
value={mostUsedRobot || t('dashboard', 'noFavoriteSet')}
subValue={robots.filter(r => r.is_favorite).length > 0 ? t('dashboard', 'mostUsed') : t('dashboard', 'noFavoriteSet')}
gradient="from-yellow-500 to-orange-600"
variant="neon"
loading={loading}
Expand All @@ -382,11 +384,11 @@ export default function EnhancedQuickStats() {
<div className="grid grid-cols-3 gap-4">
<StatCard
icon={<Clock className="h-4 w-4 text-white" />}
label="Today"
label={t('dashboard', 'today')}
value={todayActions}
subValue="actions"
subValue={t('dashboard', 'actions')}
trend={todayActions > 50 ? 'up' : todayActions > 10 ? 'neutral' : 'down'}
trendValue={todayActions > 50 ? 'Very active' : todayActions > 10 ? 'Active' : 'Quiet'}
trendValue={todayActions > 50 ? t('dashboard', 'veryActive') : todayActions > 10 ? t('dashboard', 'active') : t('dashboard', 'quiet')}
gradient="from-indigo-500 to-blue-600"
variant="glass"
size="small"
Expand All @@ -395,11 +397,11 @@ export default function EnhancedQuickStats() {

<StatCard
icon={<TrendingUp className="h-4 w-4 text-white" />}
label="This Week"
label={t('dashboard', 'thisWeek')}
value={weeklyActions}
subValue="actions"
subValue={t('dashboard', 'actions')}
trend={weeklyActions > 200 ? 'up' : 'neutral'}
trendValue={`Avg ${Math.round(weeklyActions / 7)}/day`}
trendValue={t('dashboard', 'avgPerDay').replace('{count}', String(Math.round(weeklyActions / 7)))}
gradient="from-pink-500 to-rose-600"
variant="glass"
size="small"
Expand All @@ -408,9 +410,9 @@ export default function EnhancedQuickStats() {

<StatCard
icon={<Gauge className="h-4 w-4 text-white" />}
label="Peak Hour"
label={t('dashboard', 'peakHour')}
value={peakHour}
subValue="most active"
subValue={t('dashboard', 'mostActive')}
gradient="from-purple-500 to-violet-600"
variant="glass"
size="small"
Expand All @@ -422,9 +424,9 @@ export default function EnhancedQuickStats() {
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
<StatCard
icon={<Target className="h-4 w-4 text-white" />}
label="Missions"
label={t('dashboard', 'missions')}
value={missionsTotal}
subValue="created"
subValue={t('dashboard', 'created')}
gradient="from-red-500 to-pink-600"
variant="default"
size="small"
Expand All @@ -433,9 +435,9 @@ export default function EnhancedQuickStats() {

<StatCard
icon={<Brain className="h-4 w-4 text-white" />}
label="AI Detections"
label={t('dashboard', 'aiDetections')}
value={detectionsCount}
subValue={avgConfidence > 0 ? `${(avgConfidence * 100).toFixed(0)}% conf` : 'YOLO active'}
subValue={avgConfidence > 0 ? `${(avgConfidence * 100).toFixed(0)}% ${t('dashboard', 'confidenceAbbrev')}` : t('dashboard', 'yoloActive')}
gradient="from-green-500 to-emerald-600"
variant="default"
size="small"
Expand All @@ -444,9 +446,9 @@ export default function EnhancedQuickStats() {

<StatCard
icon={<Music className="h-4 w-4 text-white" />}
label="Sound Library"
label={t('dashboard', 'soundLibrary')}
value={soundsCount}
subValue="audio clips"
subValue={t('dashboard', 'audioClips')}
gradient="from-orange-500 to-red-600"
variant="default"
size="small"
Expand All @@ -455,9 +457,9 @@ export default function EnhancedQuickStats() {

<StatCard
icon={<DatabaseIcon className="h-4 w-4 text-white" />}
label="Storage"
label={t('dashboard', 'storage')}
value={storageUsed}
subValue="used"
subValue={t('dashboard', 'used')}
gradient="from-gray-600 to-gray-800"
variant="default"
size="small"
Expand All @@ -466,4 +468,4 @@ export default function EnhancedQuickStats() {
</div>
</div>
);
}
}
Loading