SarahXia0405's picture
Upload 72 files
760b33c verified
raw
history blame
13.8 kB
import React, { useState } from 'react';
import { Button } from './ui/button';
import { Input } from './ui/input';
import { Label } from './ui/label';
import { Card } from './ui/card';
import { Separator } from './ui/separator';
import { Textarea } from './ui/textarea';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select';
import {
LogIn,
LogOut,
Download,
ClipboardList,
FileText,
Sparkles,
ChevronUp,
ChevronDown,
PanelRightClose,
MessageSquare
} from 'lucide-react';
import type { User } from '../App';
import { toast } from 'sonner@2.0.3';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
DialogFooter,
} from './ui/dialog';
interface RightPanelProps {
user: User | null;
onLogin: (user: User) => void;
onLogout: () => void;
isLoggedIn: boolean;
onClose?: () => void;
exportResult: string;
setExportResult: (result: string) => void;
resultType: 'export' | 'quiz' | 'summary' | null;
setResultType: (type: 'export' | 'quiz' | 'summary' | null) => void;
}
export function RightPanel({ user, onLogin, onLogout, isLoggedIn, onClose, exportResult, setExportResult, resultType, setResultType }: RightPanelProps) {
const [showLoginForm, setShowLoginForm] = useState(false);
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [isExpanded, setIsExpanded] = useState(true);
const [feedbackDialogOpen, setFeedbackDialogOpen] = useState(false);
const [feedbackText, setFeedbackText] = useState('');
const [feedbackCategory, setFeedbackCategory] = useState<'general' | 'bug' | 'feature'>('general');
const handleLogin = () => {
if (!name.trim() || !email.trim()) {
toast.error('Please fill in all fields');
return;
}
onLogin({ name: name.trim(), email: email.trim() });
setShowLoginForm(false);
setName('');
setEmail('');
toast.success(`Welcome, ${name}!`);
};
const handleLogout = () => {
onLogout();
setShowLoginForm(false);
toast.success('Logged out successfully');
};
const handleExport = () => {
const result = `# Conversation Export
Date: ${new Date().toLocaleDateString()}
Student: ${user?.name}
## Summary
This conversation covered key concepts in Module 10 – Responsible AI, including ethical considerations, fairness, transparency, and accountability in AI systems.
## Key Takeaways
1. Understanding the principles of Responsible AI
2. Real-world applications and implications
3. Best practices for ethical AI development
Exported successfully! ✓`;
setExportResult(result);
setResultType('export');
toast.success('Conversation exported!');
};
const handleQuiz = () => {
const quiz = `# Micro-Quiz: Responsible AI
**Question 1:** Which of the following is a key principle of Responsible AI?
a) Profit maximization
b) Transparency
c) Rapid deployment
d) Cost reduction
**Question 2:** What is algorithmic fairness?
(Short answer expected)
**Question 3:** True or False: AI systems should always prioritize accuracy over fairness.
Generate quiz based on your conversation!`;
setExportResult(quiz);
setResultType('quiz');
toast.success('Quiz generated!');
};
const handleSummary = () => {
const summary = `# Learning Summary
## Today's Session
**Duration:** 25 minutes
**Topics Covered:** 3
**Messages Exchanged:** 12
## Key Concepts Discussed
• Principles of Responsible AI
• Ethical considerations in AI development
• Fairness and transparency in algorithms
## Recommended Next Steps
1. Review Module 10, Section 2.3
2. Complete practice quiz on algorithmic fairness
3. Read additional resources on AI ethics
## Progress Update
You've covered 65% of Module 10 content. Keep up the great work! 🎉`;
setExportResult(summary);
setResultType('summary');
toast.success('Summary generated!');
};
const handleFeedbackSubmit = () => {
if (!feedbackText.trim()) {
toast.error('Please provide feedback text');
return;
}
// Here you can add logic to send feedback to your server or handle it as needed
console.log('Feedback submitted:', feedbackText, feedbackCategory);
setFeedbackDialogOpen(false);
setFeedbackText('');
toast.success('Feedback submitted!');
};
return (
<div className="flex-1 overflow-auto p-4 space-y-4">
{isExpanded && (
<>
{/* Login Section */}
<Card className="p-4">
{!isLoggedIn ? (
<div className="space-y-4">
<div className="flex flex-col items-center py-4">
<img
src="https://images.unsplash.com/photo-1588912914049-d2664f76a947?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxzdHVkZW50JTIwc3R1ZHlpbmclMjBpbGx1c3RyYXRpb258ZW58MXx8fHwxNzY2MDY2NjcyfDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
alt="Student studying"
className="w-20 h-20 rounded-full object-cover mb-4"
/>
<h3 className="mb-2">Welcome to Clare!</h3>
<p className="text-sm text-muted-foreground text-center mb-4">
Log in to start your personalized learning journey
</p>
</div>
{!showLoginForm ? (
<Button onClick={() => setShowLoginForm(true)} className="w-full gap-2">
<LogIn className="h-4 w-4" />
Student Login
</Button>
) : (
<div className="space-y-3">
<div className="space-y-2">
<Label htmlFor="name">Name</Label>
<Input
id="name"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter your name"
/>
</div>
<div className="space-y-2">
<Label htmlFor="email">Email / Student ID</Label>
<Input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email or ID"
/>
</div>
<div className="flex gap-2">
<Button onClick={handleLogin} className="flex-1">
Enter
</Button>
<Button
variant="outline"
onClick={() => setShowLoginForm(false)}
>
Cancel
</Button>
</div>
</div>
)}
</div>
) : (
<div className="space-y-4">
<div className="flex items-center gap-3">
<div className="w-12 h-12 rounded-full bg-gradient-to-br from-purple-500 to-blue-500 flex items-center justify-center text-white">
{user.name.charAt(0).toUpperCase()}
</div>
<div className="flex-1 min-w-0">
<h4 className="truncate">{user.name}</h4>
<p className="text-sm text-muted-foreground truncate">{user.email}</p>
</div>
</div>
<Button
variant="destructive"
onClick={handleLogout}
className="w-full gap-2"
>
<LogOut className="h-4 w-4" />
Log Out
</Button>
</div>
)}
</Card>
<Separator />
{/* Actions section removed - functionality available via floating buttons */}
{/* <div className="space-y-3">
<h3>Actions</h3>
<Dialog>
<DialogTrigger asChild>
<Button
variant="outline"
className="w-full justify-start gap-2"
disabled={!isLoggedIn}
onClick={handleExport}
>
<Download className="h-4 w-4" />
Export Conversation
</Button>
</DialogTrigger>
</Dialog>
<Dialog>
<DialogTrigger asChild>
<Button
variant="outline"
className="w-full justify-start gap-2"
disabled={!isLoggedIn}
onClick={handleQuiz}
>
<ClipboardList className="h-4 w-4" />
Let's Try (Micro-Quiz)
</Button>
</DialogTrigger>
</Dialog>
<Dialog>
<DialogTrigger asChild>
<Button
variant="outline"
className="w-full justify-start gap-2"
disabled={!isLoggedIn}
onClick={handleSummary}
>
<Sparkles className="h-4 w-4" />
Summarization
</Button>
</DialogTrigger>
</Dialog>
{!isLoggedIn && (
<p className="text-xs text-muted-foreground text-center pt-2">
Log in to unlock all features
</p>
)}
</div> */}
<Separator />
{/* Results Section */}
<div className="space-y-3">
<h3>
{resultType === 'export' && 'Exported Conversation'}
{resultType === 'quiz' && 'Micro-Quiz'}
{resultType === 'summary' && 'Summarization'}
{!resultType && 'Results'}
</h3>
<Card className="p-4 min-h-[200px] bg-muted/30">
{exportResult ? (
<div className="space-y-3">
<div className="flex items-center justify-between">
<FileText className="h-4 w-4 text-muted-foreground" />
<Button
variant="ghost"
size="sm"
onClick={() => {
navigator.clipboard.writeText(exportResult);
toast.success('Copied to clipboard!');
}}
>
Copy
</Button>
</div>
<div className="text-sm whitespace-pre-wrap text-foreground">
{exportResult}
</div>
</div>
) : (
<div className="flex items-center justify-center h-full text-sm text-muted-foreground text-left">
Results (export / summary / quiz) will appear here after using the actions above
</div>
)}
</Card>
</div>
<Separator />
{/* Feedback Section */}
<div className="space-y-3">
<h3>Feedback</h3>
<Button
variant="outline"
className="w-full justify-start gap-2"
onClick={() => setFeedbackDialogOpen(true)}
>
<MessageSquare className="h-4 w-4" />
Provide Feedback
</Button>
</div>
{/* Feedback Dialog */}
<Dialog open={feedbackDialogOpen} onOpenChange={setFeedbackDialogOpen}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Provide Feedback</DialogTitle>
<DialogDescription>
Help us improve Clare by sharing your thoughts and suggestions.
</DialogDescription>
</DialogHeader>
<div className="space-y-3">
<div className="space-y-2">
<Label htmlFor="feedbackCategory">Category</Label>
<Select value={feedbackCategory} onValueChange={(value) => setFeedbackCategory(value as 'general' | 'bug' | 'feature')}>
<SelectTrigger>
<SelectValue placeholder="Select a category" />
</SelectTrigger>
<SelectContent>
<SelectItem value="general">General Feedback</SelectItem>
<SelectItem value="bug">Bug Report</SelectItem>
<SelectItem value="feature">Feature Request</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="feedbackText">Feedback</Label>
<Textarea
id="feedbackText"
value={feedbackText}
onChange={(e) => setFeedbackText(e.target.value)}
placeholder="Enter your feedback here..."
className="min-h-[100px]"
/>
</div>
</div>
<DialogFooter>
<Button
variant="outline"
onClick={() => setFeedbackDialogOpen(false)}
>
Cancel
</Button>
<Button
variant="primary"
onClick={handleFeedbackSubmit}
>
Submit
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
)}
</div>
);
}