- Replaced `DailyCalendar` with a new `Calendar` component for improved functionality and consistency. - Introduced `AlertBanner` to replace `DeadlineReminder`, providing a more flexible way to display urgent tasks. - Updated `DailyAddForm` to use new options for task types, enhancing user experience when adding tasks. - Removed unused state and components, streamlining the DailyPageClient for better performance and maintainability. - Enhanced `DailySection` to utilize new `CheckboxItem` format for better integration with the UI. - Cleaned up imports and improved overall structure for better readability.
256 lines
10 KiB
TypeScript
256 lines
10 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { ManagerSummary } from '@/services/analytics/manager-summary';
|
|
import { Card, CardHeader, CardContent } from '@/components/ui/Card';
|
|
import { Button } from '@/components/ui/Button';
|
|
import { MetricCard } from '@/components/ui/MetricCard';
|
|
import { Tabs, TabItem } from '@/components/ui/Tabs';
|
|
import { AchievementCard } from '@/components/ui/AchievementCard';
|
|
import { ChallengeCard } from '@/components/ui/ChallengeCard';
|
|
import { useTasksContext } from '@/contexts/TasksContext';
|
|
import { MetricsTab } from './MetricsTab';
|
|
import { format } from 'date-fns';
|
|
import { fr } from 'date-fns/locale';
|
|
import { Tag } from '@/lib/types';
|
|
|
|
interface ManagerWeeklySummaryProps {
|
|
initialSummary: ManagerSummary;
|
|
}
|
|
|
|
export default function ManagerWeeklySummary({ initialSummary }: ManagerWeeklySummaryProps) {
|
|
const [summary] = useState<ManagerSummary>(initialSummary);
|
|
const [activeView, setActiveView] = useState<'narrative' | 'accomplishments' | 'challenges' | 'metrics'>('narrative');
|
|
const { tags: availableTags } = useTasksContext();
|
|
|
|
const handleTabChange = (tabId: string) => {
|
|
setActiveView(tabId as 'narrative' | 'accomplishments' | 'challenges' | 'metrics');
|
|
};
|
|
|
|
const handleRefresh = () => {
|
|
// SSR - refresh via page reload
|
|
window.location.reload();
|
|
};
|
|
|
|
|
|
const formatPeriod = () => {
|
|
return `7 derniers jours (${format(summary.period.start, 'dd MMM', { locale: fr })} - ${format(summary.period.end, 'dd MMM yyyy', { locale: fr })})`;
|
|
};
|
|
|
|
// Configuration des onglets
|
|
const tabItems: TabItem[] = [
|
|
{ id: 'narrative', label: 'Vue Executive', icon: '📝' },
|
|
{ id: 'accomplishments', label: 'Accomplissements', icon: '✅', count: summary.keyAccomplishments.length },
|
|
{ id: 'challenges', label: 'Enjeux à venir', icon: '🎯', count: summary.upcomingChallenges.length },
|
|
{ id: 'metrics', label: 'Métriques', icon: '📊' }
|
|
];
|
|
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Header avec navigation */}
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-[var(--foreground)]">👔 Résumé Manager</h1>
|
|
<p className="text-[var(--muted-foreground)]">{formatPeriod()}</p>
|
|
</div>
|
|
<Button
|
|
onClick={handleRefresh}
|
|
variant="secondary"
|
|
size="sm"
|
|
>
|
|
🔄 Actualiser
|
|
</Button>
|
|
</div>
|
|
|
|
{/* Navigation des vues */}
|
|
<Tabs
|
|
items={tabItems}
|
|
activeTab={activeView}
|
|
onTabChange={handleTabChange}
|
|
/>
|
|
|
|
{/* Vue Executive / Narrative */}
|
|
{activeView === 'narrative' && (
|
|
<div className="space-y-6">
|
|
{/* Résumé narratif */}
|
|
<Card>
|
|
<CardHeader>
|
|
<h2 className="text-lg font-semibold flex items-center gap-2">
|
|
📊 Résumé de la semaine
|
|
</h2>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="outline-card-blue p-4">
|
|
<h3 className="font-medium mb-2">🎯 Points clés accomplis</h3>
|
|
<p>{summary.narrative.weekHighlight}</p>
|
|
</div>
|
|
|
|
<div className="outline-card-yellow p-4">
|
|
<h3 className="font-medium mb-2">⚡ Défis traités</h3>
|
|
<p>{summary.narrative.mainChallenges}</p>
|
|
</div>
|
|
|
|
<div className="outline-card-green p-4">
|
|
<h3 className="font-medium mb-2">🔮 Focus 7 prochains jours</h3>
|
|
<p>{summary.narrative.nextWeekFocus}</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Métriques rapides */}
|
|
<Card>
|
|
<CardHeader>
|
|
<h2 className="text-lg font-semibold">📈 Métriques en bref</h2>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
|
<MetricCard
|
|
title="Tâches complétées"
|
|
value={summary.metrics.totalTasksCompleted}
|
|
subtitle={`dont ${summary.metrics.highPriorityTasksCompleted} priorité haute`}
|
|
color="primary"
|
|
/>
|
|
|
|
<MetricCard
|
|
title="Todos complétés"
|
|
value={summary.metrics.totalCheckboxesCompleted}
|
|
subtitle={`dont ${summary.metrics.meetingCheckboxesCompleted} meetings`}
|
|
color="success"
|
|
/>
|
|
|
|
<MetricCard
|
|
title="Items à fort impact"
|
|
value={summary.keyAccomplishments.filter(a => a.impact === 'high').length}
|
|
subtitle={`/ ${summary.keyAccomplishments.length} accomplissements`}
|
|
color="warning"
|
|
/>
|
|
|
|
<MetricCard
|
|
title="Priorités critiques"
|
|
value={summary.upcomingChallenges.filter(c => c.priority === 'high').length}
|
|
subtitle={`/ ${summary.upcomingChallenges.length} enjeux`}
|
|
color="destructive"
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Top accomplissements */}
|
|
<Card>
|
|
<CardHeader>
|
|
<h2 className="text-lg font-semibold">🏆 Top accomplissements</h2>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
{summary.keyAccomplishments.length === 0 ? (
|
|
<div className="col-span-3 text-center py-8 text-[var(--muted-foreground)]">
|
|
<p>Aucun accomplissement significatif trouvé cette semaine.</p>
|
|
<p className="text-sm mt-2">Ajoutez des tâches avec priorité haute/medium ou des meetings.</p>
|
|
</div>
|
|
) : (
|
|
summary.keyAccomplishments.slice(0, 6).map((accomplishment, index) => (
|
|
<AchievementCard
|
|
key={accomplishment.id}
|
|
achievement={accomplishment}
|
|
availableTags={availableTags as (Tag & { usage: number })[]}
|
|
index={index}
|
|
showDescription={true}
|
|
maxTags={2}
|
|
/>
|
|
))
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Top challenges */}
|
|
<Card>
|
|
<CardHeader>
|
|
<h2 className="text-lg font-semibold">🎯 Top enjeux à venir</h2>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
{summary.upcomingChallenges.length === 0 ? (
|
|
<div className="col-span-3 text-center py-8 text-[var(--muted-foreground)]">
|
|
<p>Aucun enjeu prioritaire trouvé.</p>
|
|
<p className="text-sm mt-2">Ajoutez des tâches non complétées avec priorité haute/medium.</p>
|
|
</div>
|
|
) : (
|
|
summary.upcomingChallenges.slice(0, 6).map((challenge, index) => (
|
|
<ChallengeCard
|
|
key={challenge.id}
|
|
challenge={challenge}
|
|
availableTags={availableTags as (Tag & { usage: number })[]}
|
|
index={index}
|
|
showDescription={true}
|
|
maxTags={2}
|
|
/>
|
|
))
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
)}
|
|
|
|
{/* Vue détaillée des accomplissements */}
|
|
{activeView === 'accomplishments' && (
|
|
<Card>
|
|
<CardHeader>
|
|
<h2 className="text-lg font-semibold">✅ Accomplissements des 7 derniers jours</h2>
|
|
<p className="text-sm text-[var(--muted-foreground)]">
|
|
{summary.keyAccomplishments.length} accomplissements significatifs • {summary.metrics.totalTasksCompleted} tâches • {summary.metrics.totalCheckboxesCompleted} todos complétés
|
|
</p>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{summary.keyAccomplishments.map((accomplishment, index) => (
|
|
<AchievementCard
|
|
key={accomplishment.id}
|
|
achievement={accomplishment}
|
|
availableTags={availableTags as (Tag & { usage: number })[]}
|
|
index={index}
|
|
showDescription={true}
|
|
maxTags={3}
|
|
/>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{/* Vue détaillée des challenges */}
|
|
{activeView === 'challenges' && (
|
|
<Card>
|
|
<CardHeader>
|
|
<h2 className="text-lg font-semibold">🎯 Enjeux et défis à venir</h2>
|
|
<p className="text-sm text-[var(--muted-foreground)]">
|
|
{summary.upcomingChallenges.length} défis identifiés • {summary.upcomingChallenges.filter(c => c.priority === 'high').length} priorité haute • {summary.upcomingChallenges.filter(c => c.blockers.length > 0).length} avec blockers
|
|
</p>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{summary.upcomingChallenges.map((challenge, index) => (
|
|
<ChallengeCard
|
|
key={challenge.id}
|
|
challenge={challenge}
|
|
availableTags={availableTags as (Tag & { usage: number })[]}
|
|
index={index}
|
|
showDescription={true}
|
|
maxTags={3}
|
|
/>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{/* Vue Métriques */}
|
|
{activeView === 'metrics' && (
|
|
<MetricsTab />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|