From 3d3ae57ee3595b2e8f901950d1744d57d91df13a Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 14:36:49 +0000 Subject: [PATCH] testing changes with virtual file cleanup --- .../moderation/DetailedViewCollapsible.tsx | 54 +++++++++++++++++++ .../moderation/SubmissionItemsList.tsx | 38 +++++-------- src/hooks/useDetailedViewState.ts | 48 +++++++++++++++++ 3 files changed, 115 insertions(+), 25 deletions(-) create mode 100644 src/components/moderation/DetailedViewCollapsible.tsx create mode 100644 src/hooks/useDetailedViewState.ts diff --git a/src/components/moderation/DetailedViewCollapsible.tsx b/src/components/moderation/DetailedViewCollapsible.tsx new file mode 100644 index 00000000..1be331ce --- /dev/null +++ b/src/components/moderation/DetailedViewCollapsible.tsx @@ -0,0 +1,54 @@ +import { ChevronDown, ChevronUp } from 'lucide-react'; +import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '@/components/ui/collapsible'; +import { Button } from '@/components/ui/button'; +import { cn } from '@/lib/utils'; + +interface DetailedViewCollapsibleProps { + isCollapsed: boolean; + onToggle: () => void; + children: React.ReactNode; + className?: string; +} + +/** + * Collapsible wrapper for detailed field-by-field view sections + * Provides expand/collapse functionality with visual indicators + */ +export function DetailedViewCollapsible({ + isCollapsed, + onToggle, + children, + className +}: DetailedViewCollapsibleProps) { + return ( + onToggle()}> + + + + + All Fields (Detailed View) + + + + {isCollapsed ? 'Show' : 'Hide'} + + {isCollapsed ? ( + + ) : ( + + )} + + + + + + {children} + + + + ); +} diff --git a/src/components/moderation/SubmissionItemsList.tsx b/src/components/moderation/SubmissionItemsList.tsx index b9bac9f5..f81baca7 100644 --- a/src/components/moderation/SubmissionItemsList.tsx +++ b/src/components/moderation/SubmissionItemsList.tsx @@ -7,6 +7,7 @@ import { RichRideDisplay } from './displays/RichRideDisplay'; import { RichCompanyDisplay } from './displays/RichCompanyDisplay'; import { RichRideModelDisplay } from './displays/RichRideModelDisplay'; import { RichTimelineEventDisplay } from './displays/RichTimelineEventDisplay'; +import { DetailedViewCollapsible } from './DetailedViewCollapsible'; import { Skeleton } from '@/components/ui/skeleton'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Badge } from '@/components/ui/badge'; @@ -17,6 +18,7 @@ import type { ParkSubmissionData, RideSubmissionData, CompanySubmissionData, Rid import type { TimelineSubmissionData } from '@/types/timeline'; import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler'; import { ModerationErrorBoundary } from '@/components/error/ModerationErrorBoundary'; +import { useDetailedViewState } from '@/hooks/useDetailedViewState'; interface SubmissionItemsListProps { submissionId: string; @@ -34,6 +36,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({ const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [error, setError] = useState(null); + const { isCollapsed, toggle } = useDetailedViewState(); useEffect(() => { fetchSubmissionItems(); @@ -188,17 +191,14 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({ data={entityData as unknown as ParkSubmissionData} actionType={actionType} /> - - - All Fields (Detailed View) - + - + > ); } @@ -211,17 +211,14 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({ data={entityData as unknown as RideSubmissionData} actionType={actionType} /> - - - All Fields (Detailed View) - + - + > ); } @@ -234,17 +231,14 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({ data={entityData as unknown as CompanySubmissionData} actionType={actionType} /> - - - All Fields (Detailed View) - + - + > ); } @@ -257,17 +251,14 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({ data={entityData as unknown as RideModelSubmissionData} actionType={actionType} /> - - - All Fields (Detailed View) - + - + > ); } @@ -280,17 +271,14 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({ data={entityData as unknown as TimelineSubmissionData} actionType={actionType} /> - - - All Fields (Detailed View) - + - + > ); } diff --git a/src/hooks/useDetailedViewState.ts b/src/hooks/useDetailedViewState.ts new file mode 100644 index 00000000..922d3f93 --- /dev/null +++ b/src/hooks/useDetailedViewState.ts @@ -0,0 +1,48 @@ +import { useState, useEffect } from 'react'; +import { logger } from '@/lib/logger'; + +const STORAGE_KEY = 'detailed-view-collapsed'; + +interface UseDetailedViewStateReturn { + isCollapsed: boolean; + toggle: () => void; + setCollapsed: (value: boolean) => void; +} + +/** + * Hook to manage detailed view collapsed/expanded state + * Syncs with localStorage for persistence across sessions + * Defaults to collapsed to reduce visual clutter + */ +export function useDetailedViewState(): UseDetailedViewStateReturn { + const [isCollapsed, setIsCollapsed] = useState(() => { + // Initialize from localStorage on mount + try { + const stored = localStorage.getItem(STORAGE_KEY); + // Default to collapsed (true) to reduce visual clutter + return stored ? JSON.parse(stored) : true; + } catch (error) { + logger.warn('Error reading detailed view state from localStorage', { error }); + return true; + } + }); + + // Sync to localStorage when state changes + useEffect(() => { + try { + localStorage.setItem(STORAGE_KEY, JSON.stringify(isCollapsed)); + } catch (error) { + logger.warn('Error saving detailed view state to localStorage', { error }); + } + }, [isCollapsed]); + + const toggle = () => setIsCollapsed(prev => !prev); + + const setCollapsed = (value: boolean) => setIsCollapsed(value); + + return { + isCollapsed, + toggle, + setCollapsed, + }; +}