// web/src/components/Header.tsx import React, { useState } from "react"; import { Button } from "./ui/button"; import { Menu, Sun, Moon, Languages, ChevronDown, LogOut, Plus, X, Edit, Star } from "lucide-react"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/tooltip"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator, } from "./ui/dropdown-menu"; import clareAvatar from "../assets/dfe44dab3ad8cd93953eac4a3e68bd1a5f999653.png"; import type { Workspace, CourseInfo } from "../App"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "./ui/dialog"; import { Input } from "./ui/input"; import { Label } from "./ui/label"; import { RadioGroup, RadioGroupItem } from "./ui/radio-group"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select"; import { toast } from "sonner"; import { ProfileEditor } from "./ProfileEditor"; type UserType = { name: string; email: string; }; type Language = "auto" | "en" | "zh"; interface HeaderProps { user: UserType | null; onMenuClick: () => void; onUserClick: () => void; isDarkMode: boolean; onToggleDarkMode: () => void; language: Language; onLanguageChange: (lang: Language) => void; workspaces: Workspace[]; currentWorkspace: Workspace | undefined; onWorkspaceChange: (workspaceId: string) => void; onCreateWorkspace?: (payload: { name: string; category: "course" | "personal"; courseId?: string; invites: string[]; }) => void; onLogout: () => void; availableCourses?: CourseInfo[]; onUserUpdate?: (user: UserType) => void; // ✅ NEW: controlled review-star display + click behavior reviewStarOpacity?: number; // 0..1 reviewEnergyPct?: number; // 0..100 onStarClick?: () => void; // recommended: switch to Review } export function Header({ user, onMenuClick, onUserClick, isDarkMode, onToggleDarkMode, language, onLanguageChange, workspaces, currentWorkspace, onWorkspaceChange, onLogout, onCreateWorkspace, availableCourses = [], onUserUpdate, reviewStarOpacity, reviewEnergyPct, onStarClick, }: HeaderProps) { const [showProfileEditor, setShowProfileEditor] = useState(false); const [createOpen, setCreateOpen] = useState(false); const [workspaceName, setWorkspaceName] = useState(""); const [category, setCategory] = useState<"course" | "personal">("course"); const [courseId, setCourseId] = useState(""); const [inviteEmail, setInviteEmail] = useState(""); const [invites, setInvites] = useState([]); const opacity = typeof reviewStarOpacity === "number" ? reviewStarOpacity : 0.15; const energy = typeof reviewEnergyPct === "number" ? reviewEnergyPct : Math.round(opacity * 100); const getStarStyle = () => { if (energy <= 0) { return { fill: "transparent", stroke: "white", strokeWidth: 1.5, strokeDasharray: "2 2" }; } if (energy >= 60) return { fill: "#fbbf24", stroke: "#fbbf24", strokeWidth: 0 }; if (energy >= 25) return { fill: "#fcd34d", stroke: "#fcd34d", strokeWidth: 0 }; return { fill: "#fde68a", stroke: "#fde68a", strokeWidth: 0 }; }; const addInvite = () => { const email = inviteEmail.trim(); if (!email) return; if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { toast.error("Please enter a valid email"); return; } if (invites.includes(email)) return; setInvites((prev) => [...prev, email]); setInviteEmail(""); }; const removeInvite = (email: string) => { setInvites((prev) => prev.filter((e) => e !== email)); }; const handleCreate = () => { if (!workspaceName.trim()) { toast.error("Please enter a workspace name"); return; } if (category === "course" && !courseId) { toast.error("Please select a course"); return; } if (invites.length === 0) { toast.error("Please add at least one member"); return; } onCreateWorkspace?.({ name: workspaceName.trim(), category, courseId: courseId || undefined, invites, }); setWorkspaceName(""); setCourseId(""); setCategory("course"); setInvites([]); setInviteEmail(""); setCreateOpen(false); }; return (
Clare AI

Clare{" "} Your Personalized AI Tutor

Personalized guidance, review, and intelligent reinforcement

onLanguageChange("auto")}> {language === "auto" && "✓ "}Auto onLanguageChange("en")}> {language === "en" && "✓ "}English onLanguageChange("zh")}> {language === "zh" && "✓ "}简体中文 {user && currentWorkspace ? ( <> {workspaces.map((workspace) => ( onWorkspaceChange(workspace.id)} className={`gap-3 ${currentWorkspace.id === workspace.id ? "bg-accent" : ""}`} > {workspace.name} {workspace.name} {currentWorkspace.id === workspace.id && } ))} setCreateOpen(true)}> New Group Workspace {/* Profile Avatar Button */}

{user.name}

ID: {user.email.split("@")[0] || user.email}

= 85 ? "drop-shadow(0 0 2px rgba(251, 191, 36, 0.8))" : "none", }} />
{energy}%
setShowProfileEditor(true)}> Edit Profile Log out {/* Star badge in top-right corner of avatar */}

Energy: {energy}%

Enter Review and complete at least 1 action today to recharge.

) : null}
{/* Create Group Workspace Dialog */} e.preventDefault()} onInteractOutside={(e) => e.preventDefault()} > Create Group Workspace
setWorkspaceName(e.target.value)} placeholder="e.g., CS 101 Study Group" />
setCategory(val as "course" | "personal")} className="flex gap-4" >
{category === "course" && (
)}
setInviteEmail(e.target.value)} placeholder="Enter email and click Add" onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); addInvite(); } }} />
{invites.length > 0 && (
{invites.map((email) => ( {email} ))}
)}
{/* Profile Editor Dialog */} {user && showProfileEditor && ( { if (onUserUpdate) onUserUpdate(updatedUser); setShowProfileEditor(false); }} onClose={() => setShowProfileEditor(false)} /> )}
); }