cohorta/src/components/focus-group-session/CollapsibleDiscussionGuide.tsx

155 lines
No EOL
5.2 KiB
TypeScript

import React, { useState, useRef, useCallback } from 'react';
import {
ChevronDown,
ChevronUp,
ClipboardList,
Download,
Loader2
} from 'lucide-react';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import DiscussionGuideViewer from './DiscussionGuideViewer';
import { cn } from '@/lib/utils';
import { toast } from 'sonner';
import { focusGroupsApi } from '@/lib/api';
interface CollapsibleDiscussionGuideProps {
discussionGuide: any;
moderatorStatus?: any;
onSectionSelect?: (sectionId: string, itemId?: string) => void;
onSetPosition?: (sectionId: string, itemId: string, content: string, sectionTitle: string, itemTitle?: string, itemType?: string) => void;
onSave?: (updatedGuide: any) => void;
focusGroupId: string;
isOpen: boolean;
onToggle: () => void;
className?: string;
onEditingChange?: (isEditing: boolean) => void;
}
const CollapsibleDiscussionGuide: React.FC<CollapsibleDiscussionGuideProps> = ({
discussionGuide,
moderatorStatus,
onSectionSelect,
onSetPosition,
onSave,
focusGroupId,
isOpen,
onToggle,
className,
onEditingChange
}) => {
// Track editing state to prevent re-renders
const isEditingRef = useRef(false);
// Wrapper for onEditingChange to track editing state
const handleEditingChange = useCallback((editing: boolean) => {
isEditingRef.current = editing;
onEditingChange?.(editing);
}, [onEditingChange]);
// Download state
const [isDownloadingGuide, setIsDownloadingGuide] = useState(false);
// Function to download discussion guide
const handleDownloadDiscussionGuide = async () => {
if (!discussionGuide) {
toast.error("No discussion guide available", {
description: "The discussion guide is not available for download"
});
return;
}
setIsDownloadingGuide(true);
try {
await focusGroupsApi.downloadDiscussionGuide(focusGroupId);
toast.success("Discussion guide downloaded", {
description: "The guide has been saved to your downloads folder"
});
} catch (error) {
console.error('Error downloading discussion guide:', error);
toast.error("Download failed", {
description: "Unable to download the discussion guide. Please try again."
});
} finally {
setIsDownloadingGuide(false);
}
};
// Check if we have a valid structured discussion guide
const hasStructuredGuide = discussionGuide && typeof discussionGuide === 'object' && discussionGuide.sections;
return (
<div className={cn("w-full border-b bg-white shadow-sm", className)}>
<Collapsible open={isOpen} onOpenChange={onToggle}>
<CollapsibleTrigger asChild>
<div className="w-full px-4 py-3 flex items-center justify-between hover:bg-slate-50 transition-colors cursor-pointer">
<div className="flex items-center gap-3">
<ClipboardList className="h-5 w-5 text-slate-600" />
<div>
<h2 className="font-semibold text-slate-900">Discussion Guide</h2>
{hasStructuredGuide && (
<p className="text-xs text-slate-500">
{discussionGuide.title} {discussionGuide.total_duration} minutes
</p>
)}
</div>
</div>
<div className="flex items-center gap-2">
<Button
variant="ghost"
size="sm"
onClick={(e) => {
e.stopPropagation();
handleDownloadDiscussionGuide();
}}
disabled={!discussionGuide || isDownloadingGuide}
className="h-8"
>
{isDownloadingGuide ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<Download className="h-4 w-4" />
)}
</Button>
{isOpen ? (
<ChevronUp className="h-4 w-4 text-slate-500" />
) : (
<ChevronDown className="h-4 w-4 text-slate-500" />
)}
</div>
</div>
</CollapsibleTrigger>
<CollapsibleContent>
<div className="border-t bg-slate-50">
<Card className="mx-4 mb-4 mt-2">
<CardContent className="p-4">
<div className="max-h-[70vh] overflow-y-auto">
<DiscussionGuideViewer
discussionGuide={discussionGuide}
moderatorStatus={moderatorStatus}
onSectionSelect={onSectionSelect}
onSetPosition={onSetPosition}
onSave={onSave}
showProgress={true}
collapsible={true}
defaultExpanded={true}
focusGroupId={focusGroupId}
onEditingChange={handleEditingChange}
/>
</div>
</CardContent>
</Card>
</div>
</CollapsibleContent>
</Collapsible>
</div>
);
};
export default CollapsibleDiscussionGuide;