Compare commits

..

9 Commits

Author SHA1 Message Date
gpt-engineer-app[bot]
87c7cf7d40 Changes 2025-11-12 14:55:58 +00:00
gpt-engineer-app[bot]
2fbaf4ef08 Changes 2025-11-12 14:55:45 +00:00
gpt-engineer-app[bot]
3a6bb59475 Changes 2025-11-12 14:55:33 +00:00
gpt-engineer-app[bot]
d7158756ef Animate detailed view transitions
Improve user experience by adding smooth animation transitions to expand/collapse of All Fields (Detailed View) sections, enhance collapsible base to support animation, and apply transitions to detailed view wrapper and chevron indicators.

X-Lovable-Edit-ID: edt-9a567ba5-b52f-46b3-bdef-b847b9ba7963
2025-11-12 14:53:19 +00:00
gpt-engineer-app[bot]
3330a8fac9 testing changes with virtual file cleanup 2025-11-12 14:53:18 +00:00
gpt-engineer-app[bot]
c09a343d08 Add moderation_preferences column
Adds a JSONB moderation_preferences column to user_preferences (with default '{}'), plus comment and GIN index, enabling per-user persistence of detailed view state and resolving TS errors.

X-Lovable-Edit-ID: edt-b953d926-c053-45f2-b434-2b776f3d9569
2025-11-12 14:50:57 +00:00
gpt-engineer-app[bot]
9893567a30 testing changes with virtual file cleanup 2025-11-12 14:50:56 +00:00
gpt-engineer-app[bot]
771405961f Add tooltip for expanded count
Enhance persistence for moderator preferences

- Add tooltip to moderation queue toggle showing number of items with detailed views expanded (based on global state, tooltip adapts to expanded/collapsed).
- Persist expanded/collapsed state per moderator in the database instead of localStorage, integrating with user preferences and Supabase backend.

X-Lovable-Edit-ID: edt-61e75a20-f83d-40b2-8bc4-b6ff40b23450
2025-11-12 14:45:07 +00:00
gpt-engineer-app[bot]
437e2b353c testing changes with virtual file cleanup 2025-11-12 14:45:06 +00:00
5 changed files with 65 additions and 14 deletions

View File

@@ -1,4 +1,4 @@
import { ChevronDown, ChevronUp } from 'lucide-react';
import { ChevronDown } from 'lucide-react';
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '@/components/ui/collapsible';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
@@ -10,6 +10,7 @@ interface DetailedViewCollapsibleProps {
children: React.ReactNode;
fieldCount?: number;
className?: string;
staggerIndex?: number;
}
/**
@@ -21,8 +22,11 @@ export function DetailedViewCollapsible({
onToggle,
children,
fieldCount,
className
className,
staggerIndex = 0
}: DetailedViewCollapsibleProps) {
// Calculate stagger delay: 50ms per item, max 300ms
const staggerDelay = Math.min(staggerIndex * 50, 300);
return (
<Collapsible open={!isCollapsed} onOpenChange={() => onToggle()}>
<div className={cn("mt-6 pt-6 border-t", className)}>
@@ -49,16 +53,23 @@ export function DetailedViewCollapsible({
<span className="text-xs text-muted-foreground normal-case font-normal">
{isCollapsed ? 'Show' : 'Hide'}
</span>
{isCollapsed ? (
<ChevronDown className="h-4 w-4 text-muted-foreground transition-transform duration-200" />
) : (
<ChevronUp className="h-4 w-4 text-muted-foreground transition-transform duration-200" />
)}
<ChevronDown
className={cn(
"h-4 w-4 text-muted-foreground transition-all duration-300 ease-out",
!isCollapsed && "rotate-180"
)}
/>
</div>
</Button>
</CollapsibleTrigger>
<CollapsibleContent className="mt-3 data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down">
<CollapsibleContent
className="mt-3"
style={{
animationDelay: `${staggerDelay}ms`,
transitionDelay: `${staggerDelay}ms`
}}
>
{children}
</CollapsibleContent>
</div>

View File

@@ -135,7 +135,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
}
// Render item with appropriate display component
const renderItem = (item: SubmissionItemData) => {
const renderItem = (item: SubmissionItemData, index: number = 0) => {
// SubmissionItemData from submissions.ts has item_data property
const entityData = item.item_data;
const actionType = item.action_type || 'create';
@@ -201,6 +201,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
isCollapsed={isCollapsed}
onToggle={toggle}
fieldCount={countFields(entityData)}
staggerIndex={index}
>
<SubmissionChangesDisplay
item={item}
@@ -225,6 +226,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
isCollapsed={isCollapsed}
onToggle={toggle}
fieldCount={countFields(entityData)}
staggerIndex={index}
>
<SubmissionChangesDisplay
item={item}
@@ -249,6 +251,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
isCollapsed={isCollapsed}
onToggle={toggle}
fieldCount={countFields(entityData)}
staggerIndex={index}
>
<SubmissionChangesDisplay
item={item}
@@ -273,6 +276,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
isCollapsed={isCollapsed}
onToggle={toggle}
fieldCount={countFields(entityData)}
staggerIndex={index}
>
<SubmissionChangesDisplay
item={item}
@@ -297,6 +301,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
isCollapsed={isCollapsed}
onToggle={toggle}
fieldCount={countFields(entityData)}
staggerIndex={index}
>
<SubmissionChangesDisplay
item={item}
@@ -334,9 +339,9 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
)}
{/* Show regular submission items */}
{items.map((item) => (
{items.map((item, index) => (
<div key={item.id} className={view === 'summary' ? 'border-l-2 border-primary/20 pl-3' : ''}>
{renderItem(item)}
{renderItem(item, index)}
</div>
))}

View File

@@ -1,9 +1,30 @@
import * as React from "react";
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
import { cn } from "@/lib/utils";
const Collapsible = CollapsiblePrimitive.Root;
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;
const CollapsibleContent = React.forwardRef<
React.ElementRef<typeof CollapsiblePrimitive.Content>,
React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Content>
>(({ className, children, ...props }, ref) => (
<CollapsiblePrimitive.Content
ref={ref}
className={cn(
"overflow-hidden transition-all duration-300 ease-out",
"data-[state=closed]:animate-accordion-up",
"data-[state=open]:animate-accordion-down",
className
)}
{...props}
>
<div className="animate-fade-in">
{children}
</div>
</CollapsiblePrimitive.Content>
));
CollapsibleContent.displayName = "CollapsibleContent";
export { Collapsible, CollapsibleTrigger, CollapsibleContent };

View File

@@ -50,8 +50,10 @@ export function useDetailedViewState(): UseDetailedViewStateReturn {
});
}
if (data?.moderation_preferences) {
const prefs = data.moderation_preferences as ModerationPreferences;
// Type assertion needed until Supabase regenerates types after migration
const preferences = (data as any)?.moderation_preferences;
if (preferences) {
const prefs = preferences as ModerationPreferences;
setIsCollapsed(prefs.detailed_view_collapsed ?? true);
}
} else {

View File

@@ -0,0 +1,12 @@
-- Add moderation_preferences column to user_preferences table
-- This stores moderator UI preferences like detailed view collapsed state
ALTER TABLE public.user_preferences
ADD COLUMN IF NOT EXISTS moderation_preferences JSONB NOT NULL DEFAULT '{}'::jsonb;
COMMENT ON COLUMN public.user_preferences.moderation_preferences IS
'Stores moderator UI preferences like detailed view collapsed state';
-- Add GIN index for efficient JSONB queries
CREATE INDEX IF NOT EXISTS idx_user_preferences_moderation_prefs
ON public.user_preferences USING gin(moderation_preferences);