122 lines
5.7 KiB
TypeScript
122 lines
5.7 KiB
TypeScript
/**
|
|
* Dashboard Hero Section Component
|
|
* Displays the main dashboard header with title and quick actions
|
|
*/
|
|
|
|
import { Card, CardContent } from '@/components/ui/card';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Switch } from '@/components/ui/switch';
|
|
import { Label } from '@/components/ui/label';
|
|
import { User, Building2 } from 'lucide-react';
|
|
import { QuickAction } from '../utils/dashboardNavigation';
|
|
|
|
interface DashboardHeroProps {
|
|
isAdmin: boolean;
|
|
effectiveIsAdmin: boolean;
|
|
viewAsUser: boolean;
|
|
onToggleView: (viewAsUser: boolean) => void;
|
|
quickActions: QuickAction[];
|
|
userDisplayName?: string;
|
|
userEmail?: string;
|
|
}
|
|
|
|
export function DashboardHero({ isAdmin, effectiveIsAdmin, viewAsUser, onToggleView, quickActions, userDisplayName, userEmail }: DashboardHeroProps) {
|
|
// Get user's name for welcome message
|
|
const userName = userDisplayName || userEmail?.split('@')[0] || 'User';
|
|
return (
|
|
<Card className="relative overflow-hidden shadow-xl border-0" data-testid="dashboard-hero">
|
|
<div className="absolute inset-0 bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900"></div>
|
|
|
|
<CardContent className="relative z-10 p-4 sm:p-6 lg:p-12">
|
|
{/* Toggle for admin to switch between admin and personal view - Top Right Corner */}
|
|
{isAdmin && (
|
|
<div className="absolute top-4 right-4 sm:top-6 sm:right-6 z-20" data-testid="view-toggle">
|
|
<div className="flex items-center gap-1.5 sm:gap-2 p-1.5 sm:p-2 bg-white/10 backdrop-blur-sm rounded-lg border border-white/20 shadow-lg">
|
|
<div
|
|
className={`flex items-center gap-1 sm:gap-1.5 px-1.5 sm:px-2 py-0.5 sm:py-1 rounded transition-all cursor-pointer ${
|
|
!viewAsUser
|
|
? 'bg-red-600/20 border border-red-600/50'
|
|
: 'opacity-60 hover:opacity-80'
|
|
}`}
|
|
onClick={() => onToggleView(false)}
|
|
>
|
|
<Building2 className={`w-3 h-3 sm:w-3.5 sm:h-3.5 ${!viewAsUser ? 'text-red-600' : 'text-gray-300'}`} />
|
|
<Label htmlFor="view-toggle-switch" className={`text-[10px] sm:text-xs font-medium cursor-pointer whitespace-nowrap ${
|
|
!viewAsUser ? 'text-red-600' : 'text-gray-300'
|
|
}`}>
|
|
Org
|
|
</Label>
|
|
</div>
|
|
<Switch
|
|
id="view-toggle-switch"
|
|
checked={viewAsUser}
|
|
onCheckedChange={onToggleView}
|
|
className="data-[state=checked]:bg-red-600 data-[state=unchecked]:bg-gray-600 shrink-0 scale-90 sm:scale-100"
|
|
data-testid="view-toggle-switch"
|
|
/>
|
|
<div
|
|
className={`flex items-center gap-1 sm:gap-1.5 px-1.5 sm:px-2 py-0.5 sm:py-1 rounded transition-all cursor-pointer ${
|
|
viewAsUser
|
|
? 'bg-red-600/20 border border-red-600/50'
|
|
: 'opacity-60 hover:opacity-80'
|
|
}`}
|
|
onClick={() => onToggleView(true)}
|
|
>
|
|
<User className={`w-3 h-3 sm:w-3.5 sm:h-3.5 ${viewAsUser ? 'text-red-600' : 'text-gray-300'}`} />
|
|
<Label htmlFor="view-toggle-switch" className={`text-[10px] sm:text-xs font-medium cursor-pointer whitespace-nowrap ${
|
|
viewAsUser ? 'text-red-600' : 'text-gray-300'
|
|
}`}>
|
|
Personal
|
|
</Label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex flex-col lg:flex-row items-start lg:items-center justify-between gap-4 sm:gap-6">
|
|
<div className={`text-white w-full lg:w-auto ${isAdmin ? 'pt-12 sm:pt-0' : ''}`}>
|
|
<div className="flex items-center gap-3 sm:gap-4 mb-4 sm:mb-6">
|
|
<div className="pr-2 sm:pr-0">
|
|
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-bold mb-1 sm:mb-2 text-white" data-testid="hero-title">
|
|
Welcome, {userName}!
|
|
</h1>
|
|
<p className="text-sm sm:text-lg lg:text-xl text-gray-200" data-testid="hero-subtitle">
|
|
{effectiveIsAdmin ? 'Organization-wide analytics and insights' : 'Track your requests and approvals'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-wrap gap-2 sm:gap-4 mt-4 sm:mt-8" data-testid="quick-actions">
|
|
{quickActions.map((action, index) => (
|
|
<Button
|
|
key={index}
|
|
onClick={action.action}
|
|
className={`${action.color} text-white border-0 shadow-lg hover:shadow-xl transition-all duration-200`}
|
|
size={window.innerWidth < 640 ? "sm" : "lg"}
|
|
data-testid={`quick-action-${action.label.toLowerCase().replace(/\s+/g, '-')}`}
|
|
>
|
|
<action.icon className="w-4 h-4 sm:w-5 sm:h-5 mr-1 sm:mr-2" />
|
|
{action.label}
|
|
</Button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Decorative Elements */}
|
|
{/* <div className="hidden lg:flex items-center gap-4" data-testid="hero-decorations">
|
|
<div className="w-24 h-24 bg-yellow-400/20 rounded-full flex items-center justify-center">
|
|
<div className="w-16 h-16 bg-yellow-400/30 rounded-full flex items-center justify-center">
|
|
<Zap className="w-8 h-8 text-yellow-400" />
|
|
</div>
|
|
</div>
|
|
<div className="w-16 h-16 bg-white/10 rounded-full flex items-center justify-center">
|
|
<Activity className="w-6 h-6 text-white/80" />
|
|
</div>
|
|
</div> */}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|
|
|