diff --git a/src/app/jira-dashboard/JiraDashboardPageClient.tsx b/src/app/jira-dashboard/JiraDashboardPageClient.tsx index 3d70313..2b166c6 100644 --- a/src/app/jira-dashboard/JiraDashboardPageClient.tsx +++ b/src/app/jira-dashboard/JiraDashboardPageClient.tsx @@ -9,6 +9,9 @@ import { Header } from '@/components/ui/Header'; import { Card, CardHeader, CardContent } from '@/components/ui/Card'; import { Button } from '@/components/ui/Button'; import { Badge } from '@/components/ui/Badge'; +import { PeriodSelector, SkeletonGrid, MetricsGrid } from '@/components/ui'; +import { AlertBanner } from '@/components/ui/AlertBanner'; +import { Tabs } from '@/components/ui/Tabs'; import { VelocityChart } from '@/components/jira/VelocityChart'; import { TeamDistributionChart } from '@/components/jira/TeamDistributionChart'; import { CycleTimeChart } from '@/components/jira/CycleTimeChart'; @@ -197,26 +200,16 @@ export function JiraDashboardPageClient({ initialJiraConfig, initialAnalytics }:
{/* Sélecteur de période */} -
- {[ + ( - - ))} -
+ ]} + selectedValue={selectedPeriod} + onValueChange={(value) => setSelectedPeriod(value as PeriodFilter)} + />
{analytics && ( @@ -260,40 +253,27 @@ export function JiraDashboardPageClient({ initialJiraConfig, initialAnalytics }: {/* Contenu principal */} {error && ( - - -
- - {error} -
-
-
+ )} {exportError && ( - - -
- ⚠️ - Erreur d'export: {exportError} -
-
-
+ )} {isLoading && !analytics && ( -
- {/* Skeleton loading */} - {[1, 2, 3, 4, 5, 6].map(i => ( - - -
-
-
-
-
- ))} -
+ )} {analytics && ( @@ -313,40 +293,30 @@ export function JiraDashboardPageClient({ initialJiraConfig, initialAnalytics }: )} -
-
-
- {analytics.project.totalIssues} -
-
- Tickets -
-
-
-
- {analytics.teamMetrics.totalAssignees} -
-
- Équipe -
-
-
-
- {analytics.teamMetrics.activeAssignees} -
-
- Actifs -
-
-
-
- {analytics.velocityMetrics.currentSprintPoints} -
-
- Points -
-
-
+
@@ -363,28 +333,16 @@ export function JiraDashboardPageClient({ initialJiraConfig, initialAnalytics }: {/* Onglets de navigation */} -
- -
+ setActiveTab(tabId as 'overview' | 'velocity' | 'analytics' | 'quality')} + /> {/* Contenu des onglets */} {activeTab === 'overview' && ( diff --git a/src/components/ui-showcase/UIShowcaseClient.tsx b/src/components/ui-showcase/UIShowcaseClient.tsx index 5814dea..ac080d4 100644 --- a/src/components/ui-showcase/UIShowcaseClient.tsx +++ b/src/components/ui-showcase/UIShowcaseClient.tsx @@ -8,7 +8,7 @@ import { Alert as ShadcnAlert, AlertTitle, AlertDescription } from '@/components import { Input } from '@/components/ui/Input'; import { StyledCard } from '@/components/ui/StyledCard'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'; -import { StatCard, ProgressBar, ActionCard, TaskCard, MetricCard, ToggleButton, SearchInput, ControlPanel, ControlSection, ControlGroup, FilterSummary, FilterChip, ColumnHeader, EmptyState, DropZone, Tabs, PriorityBadge, AchievementCard, ChallengeCard } from '@/components/ui'; +import { StatCard, ProgressBar, ActionCard, TaskCard, MetricCard, ToggleButton, SearchInput, ControlPanel, ControlSection, ControlGroup, FilterSummary, FilterChip, ColumnHeader, EmptyState, DropZone, Tabs, PriorityBadge, AchievementCard, ChallengeCard, PeriodSelector, SkeletonCard, SkeletonGrid, MetricsGrid } from '@/components/ui'; import { CheckboxItem, CheckboxItemData } from '@/components/ui/CheckboxItem'; import { Calendar } from '@/components/ui/Calendar'; import { DailyAddForm } from '@/components/ui/DailyAddForm'; @@ -22,6 +22,7 @@ import { ChallengeData } from '@/components/ui/ChallengeCard'; export function UIShowcaseClient() { const [inputValue, setInputValue] = useState(''); const [selectedDate, setSelectedDate] = useState(new Date()); + const [selectedPeriod, setSelectedPeriod] = useState('7d'); const [checkboxItems, setCheckboxItems] = useState([ { id: '1', text: 'Tâche complétée', isChecked: true, type: 'task' }, { id: '2', text: 'Réunion importante', isChecked: false, type: 'meeting' }, @@ -1081,6 +1082,93 @@ export function UIShowcaseClient() {
+ {/* Jira Dashboard Components Section */} +
+

+ Jira Dashboard Components +

+ +
+ {/* PeriodSelector */} +
+

PeriodSelector

+
+
+
+ PeriodSelector - Sélecteur de période +
+ +
+ Période sélectionnée: {selectedPeriod} +
+
+
+
+ + {/* MetricsGrid */} +
+

MetricsGrid

+
+
+
+ MetricsGrid - Grille de métriques +
+ + + + + +
+
+
+ + {/* SkeletonCard */} +
+

SkeletonCard

+
+
+
+ SkeletonCard - Carte de chargement +
+
+ + +
+
+
+
+ + {/* SkeletonGrid */} +
+

SkeletonGrid

+
+
+
+ SkeletonGrid - Grille de chargement +
+ +
+
+
+
+
+ {/* Daily Components Section */}

diff --git a/src/components/ui/MetricsGrid.tsx b/src/components/ui/MetricsGrid.tsx new file mode 100644 index 0000000..f786889 --- /dev/null +++ b/src/components/ui/MetricsGrid.tsx @@ -0,0 +1,57 @@ +import { ReactNode } from 'react'; +import { cn } from '@/lib/utils'; + +interface MetricsGridProps { + metrics: Array<{ + title: string; + value: string | number; + subtitle?: string; + icon?: ReactNode; + color?: 'default' | 'primary' | 'success' | 'warning' | 'destructive'; + }>; + className?: string; + columns?: 2 | 3 | 4; +} + +export function MetricsGrid({ + metrics, + className, + columns = 4 +}: MetricsGridProps) { + const gridCols = { + 2: 'grid-cols-2', + 3: 'grid-cols-3', + 4: 'grid-cols-2 lg:grid-cols-4' + }; + + return ( +
+ {metrics.map((metric, index) => ( +
+
+ {metric.value} +
+
+ {metric.title} +
+ {metric.subtitle && ( +
+ {metric.subtitle} +
+ )} +
+ ))} +
+ ); +} diff --git a/src/components/ui/PeriodSelector.tsx b/src/components/ui/PeriodSelector.tsx new file mode 100644 index 0000000..7232a82 --- /dev/null +++ b/src/components/ui/PeriodSelector.tsx @@ -0,0 +1,45 @@ +import { ReactNode } from 'react'; +import { cn } from '@/lib/utils'; + +export interface PeriodOption { + value: string; + label: string; + icon?: ReactNode; +} + +interface PeriodSelectorProps { + options: PeriodOption[]; + selectedValue: string; + onValueChange: (value: string) => void; + className?: string; +} + +export function PeriodSelector({ + options, + selectedValue, + onValueChange, + className +}: PeriodSelectorProps) { + return ( +
+ {options.map((option) => ( + + ))} +
+ ); +} diff --git a/src/components/ui/SkeletonCard.tsx b/src/components/ui/SkeletonCard.tsx new file mode 100644 index 0000000..fc4e185 --- /dev/null +++ b/src/components/ui/SkeletonCard.tsx @@ -0,0 +1,50 @@ +import { Card, CardContent } from './Card'; +import { cn } from '@/lib/utils'; + +interface SkeletonCardProps { + className?: string; + lines?: number; +} + +export function SkeletonCard({ className, lines = 3 }: SkeletonCardProps) { + return ( + + +
+ {/* Titre */} +
+ + {/* Valeur principale */} +
+ + {/* Lignes supplémentaires */} + {Array.from({ length: lines - 2 }).map((_, i) => ( +
+ ))} +
+
+
+ ); +} + +interface SkeletonGridProps { + count?: number; + className?: string; + lines?: number; +} + +export function SkeletonGrid({ count = 6, className, lines = 3 }: SkeletonGridProps) { + return ( +
+ {Array.from({ length: count }).map((_, i) => ( + + ))} +
+ ); +} diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index 12a3e8f..c3b4e81 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -35,6 +35,11 @@ export { DailyAddForm } from './DailyAddForm'; export { AlertBanner } from './AlertBanner'; export { CollapsibleSection } from './CollapsibleSection'; +// Composants Jira Dashboard +export { PeriodSelector } from './PeriodSelector'; +export { SkeletonCard, SkeletonGrid } from './SkeletonCard'; +export { MetricsGrid } from './MetricsGrid'; + // Composants existants export { Card, CardHeader, CardTitle, CardContent, CardFooter } from './Card'; export { FontSizeToggle } from './FontSizeToggle';