Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions components/settings/components/report-settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'use client'

import React, { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { FileDown, Loader2 } from 'lucide-react'
import { useAIState } from 'ai/rsc'
import { useMapData } from '@/components/map/map-data-context'
import { useMap } from '@/components/map/map-context'
import { generateReport } from '@/lib/utils/report-generator'
import { toast } from 'sonner'

export function ReportSettings() {
const [aiState] = useAIState()
const { mapData } = useMapData()
const { map } = useMap()
const [isGenerating, setIsGenerating] = useState(false)

const handleDownloadReport = async () => {
if (isGenerating) return

setIsGenerating(true)
try {
const mapSnapshot = map ? map.getCanvas().toDataURL('image/png') : ''
const chatTitle = aiState.chatId ? `Chat-${aiState.chatId.substring(0, 8)}` : 'QCX-Analysis'

await generateReport({
messages: aiState.messages,
drawnFeatures: mapData.drawnFeatures || [],
mapSnapshot,
chatTitle
})

toast.success('Report generated successfully')
} catch (error) {
console.error('Failed to generate report:', error)
toast.error('Failed to generate report')
} finally {
setIsGenerating(false)
}
}

return (
<Card>
<CardHeader>
<CardTitle>Reports</CardTitle>
<CardDescription>
Generate and download a PDF report of your current analysis session, including chat history, map snapshot, and drawn feature measurements.
</CardDescription>
</CardHeader>
<CardContent>
<Button onClick={handleDownloadReport} disabled={isGenerating}>
{isGenerating ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Generating Report...
</>
) : (
<>
<FileDown className="mr-2 h-4 w-4" />
Download PDF Report
</>
)}
</Button>
</CardContent>
</Card>
)
}
34 changes: 5 additions & 29 deletions components/settings/components/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ import { SystemPromptForm } from './system-prompt-form'
import { ModelSelectionForm } from './model-selection-form'
import { UserManagementForm } from './user-management-form';
import { Form } from "@/components/ui/form"
import { useSettingsStore, MapProvider } from "@/lib/store/settings";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Label } from "@/components/ui/label";
import { useToast } from "@/components/ui/hooks/use-toast"
import { ReportSettings } from './report-settings'
import { getSystemPrompt, saveSystemPrompt } from "../../../lib/actions/chat"
import { getSelectedModel, saveSelectedModel } from "../../../lib/actions/users"
import { useCurrentUser } from "@/lib/auth/use-current-user"
Expand Down Expand Up @@ -67,7 +65,6 @@ export function Settings({ initialTab = "system-prompt" }: SettingsProps) {
const router = useRouter()
const [isSaving, setIsSaving] = useState(false)
const [currentTab, setCurrentTab] = useState(initialTab);
const { mapProvider, setMapProvider } = useSettingsStore();
const { user, loading: authLoading } = useCurrentUser();

useEffect(() => {
Expand Down Expand Up @@ -166,7 +163,7 @@ export function Settings({ initialTab = "system-prompt" }: SettingsProps) {
<Tabs.Trigger value="system-prompt" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">System Prompt</Tabs.Trigger>
<Tabs.Trigger value="model" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">Model Selection</Tabs.Trigger>
<Tabs.Trigger value="user-management" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">User Management</Tabs.Trigger>
<Tabs.Trigger value="map" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">Map</Tabs.Trigger>
<Tabs.Trigger value="reports" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">Reports</Tabs.Trigger>
</Tabs.List>
<AnimatePresence mode="wait">
<motion.div
Expand Down Expand Up @@ -203,33 +200,12 @@ export function Settings({ initialTab = "system-prompt" }: SettingsProps) {
<Tabs.Content value="user-management" className="mt-6">
<UserManagementForm form={form} />
</Tabs.Content>
<Tabs.Content value="map" className="mt-6">
<Card>
<CardHeader>
<CardTitle>Map Provider</CardTitle>
<CardDescription>Choose the map provider to use in the application.</CardDescription>
</CardHeader>
<CardContent>
<RadioGroup
value={mapProvider}
onValueChange={(value) => setMapProvider(value as MapProvider)}
className="space-y-2"
>
<div className="flex items-center space-x-2">
<RadioGroupItem value="mapbox" id="mapbox" />
<Label htmlFor="mapbox">Mapbox</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="google" id="google" />
<Label htmlFor="google">Google Maps</Label>
</div>
</RadioGroup>
</CardContent>
</Card>
<Tabs.Content value="reports" className="mt-6">
<ReportSettings />
</Tabs.Content>
</motion.div>
</AnimatePresence>
</Tabs.Root>


<Card>
<CardFooter className="flex justify-between pt-6">
Expand Down