mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 23:31:11 -05:00
feat: Remove all sorting functionality
This commit is contained in:
@@ -1,14 +1,12 @@
|
|||||||
import { Filter, MessageSquare, FileText, Image, ArrowUp, ArrowDown } from 'lucide-react';
|
import { Filter, MessageSquare, FileText, Image } from 'lucide-react';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import type { EntityFilter, StatusFilter, SortConfig, SortField } from '@/types/moderation';
|
import type { EntityFilter, StatusFilter } from '@/types/moderation';
|
||||||
|
|
||||||
interface ActiveFiltersDisplayProps {
|
interface ActiveFiltersDisplayProps {
|
||||||
entityFilter: EntityFilter;
|
entityFilter: EntityFilter;
|
||||||
statusFilter: StatusFilter;
|
statusFilter: StatusFilter;
|
||||||
sortConfig: SortConfig;
|
|
||||||
defaultEntityFilter?: EntityFilter;
|
defaultEntityFilter?: EntityFilter;
|
||||||
defaultStatusFilter?: StatusFilter;
|
defaultStatusFilter?: StatusFilter;
|
||||||
defaultSortField?: SortField;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getEntityFilterIcon = (filter: EntityFilter) => {
|
const getEntityFilterIcon = (filter: EntityFilter) => {
|
||||||
@@ -20,29 +18,17 @@ const getEntityFilterIcon = (filter: EntityFilter) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSortFieldLabel = (field: SortField): string => {
|
// Removed - sorting functionality deleted
|
||||||
switch (field) {
|
|
||||||
case 'username': return 'Submitter';
|
|
||||||
case 'submission_type': return 'Type';
|
|
||||||
case 'escalated': return 'Escalated';
|
|
||||||
case 'status': return 'Status';
|
|
||||||
case 'created_at': return 'Date';
|
|
||||||
default: return field;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ActiveFiltersDisplay = ({
|
export const ActiveFiltersDisplay = ({
|
||||||
entityFilter,
|
entityFilter,
|
||||||
statusFilter,
|
statusFilter,
|
||||||
sortConfig,
|
|
||||||
defaultEntityFilter = 'all',
|
defaultEntityFilter = 'all',
|
||||||
defaultStatusFilter = 'pending',
|
defaultStatusFilter = 'pending'
|
||||||
defaultSortField = 'created_at'
|
|
||||||
}: ActiveFiltersDisplayProps) => {
|
}: ActiveFiltersDisplayProps) => {
|
||||||
const hasActiveFilters =
|
const hasActiveFilters =
|
||||||
entityFilter !== defaultEntityFilter ||
|
entityFilter !== defaultEntityFilter ||
|
||||||
statusFilter !== defaultStatusFilter ||
|
statusFilter !== defaultStatusFilter;
|
||||||
sortConfig.field !== defaultSortField;
|
|
||||||
|
|
||||||
if (!hasActiveFilters) return null;
|
if (!hasActiveFilters) return null;
|
||||||
|
|
||||||
@@ -60,12 +46,6 @@ export const ActiveFiltersDisplay = ({
|
|||||||
{statusFilter}
|
{statusFilter}
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
{sortConfig.field !== defaultSortField && (
|
|
||||||
<Badge variant="secondary" className="flex items-center gap-1">
|
|
||||||
{sortConfig.direction === 'asc' ? <ArrowUp className="w-3 h-3" /> : <ArrowDown className="w-3 h-3" />}
|
|
||||||
Sort: {getSortFieldLabel(sortConfig.field)}
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -112,11 +112,9 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
|||||||
<QueueFilters
|
<QueueFilters
|
||||||
activeEntityFilter={queueManager.filters.entityFilter}
|
activeEntityFilter={queueManager.filters.entityFilter}
|
||||||
activeStatusFilter={queueManager.filters.statusFilter}
|
activeStatusFilter={queueManager.filters.statusFilter}
|
||||||
sortConfig={queueManager.sort.config}
|
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
onEntityFilterChange={queueManager.filters.setEntityFilter}
|
onEntityFilterChange={queueManager.filters.setEntityFilter}
|
||||||
onStatusFilterChange={queueManager.filters.setStatusFilter}
|
onStatusFilterChange={queueManager.filters.setStatusFilter}
|
||||||
onSortConfigChange={queueManager.sort.setConfig}
|
|
||||||
onClearFilters={queueManager.filters.clearFilters}
|
onClearFilters={queueManager.filters.clearFilters}
|
||||||
showClearButton={queueManager.filters.hasActiveFilters}
|
showClearButton={queueManager.filters.hasActiveFilters}
|
||||||
/>
|
/>
|
||||||
@@ -126,7 +124,6 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
|||||||
<ActiveFiltersDisplay
|
<ActiveFiltersDisplay
|
||||||
entityFilter={queueManager.filters.entityFilter}
|
entityFilter={queueManager.filters.entityFilter}
|
||||||
statusFilter={queueManager.filters.statusFilter}
|
statusFilter={queueManager.filters.statusFilter}
|
||||||
sortConfig={queueManager.sort.config}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,14 @@ import { Filter, MessageSquare, FileText, Image, X } from 'lucide-react';
|
|||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { QueueSortControls } from './QueueSortControls';
|
import type { EntityFilter, StatusFilter } from '@/types/moderation';
|
||||||
import type { EntityFilter, StatusFilter, SortConfig } from '@/types/moderation';
|
|
||||||
|
|
||||||
interface QueueFiltersProps {
|
interface QueueFiltersProps {
|
||||||
activeEntityFilter: EntityFilter;
|
activeEntityFilter: EntityFilter;
|
||||||
activeStatusFilter: StatusFilter;
|
activeStatusFilter: StatusFilter;
|
||||||
sortConfig: SortConfig;
|
|
||||||
isMobile: boolean;
|
isMobile: boolean;
|
||||||
onEntityFilterChange: (filter: EntityFilter) => void;
|
onEntityFilterChange: (filter: EntityFilter) => void;
|
||||||
onStatusFilterChange: (filter: StatusFilter) => void;
|
onStatusFilterChange: (filter: StatusFilter) => void;
|
||||||
onSortConfigChange: (config: SortConfig) => void;
|
|
||||||
onClearFilters: () => void;
|
onClearFilters: () => void;
|
||||||
showClearButton: boolean;
|
showClearButton: boolean;
|
||||||
}
|
}
|
||||||
@@ -29,11 +26,9 @@ const getEntityFilterIcon = (filter: EntityFilter) => {
|
|||||||
export const QueueFilters = ({
|
export const QueueFilters = ({
|
||||||
activeEntityFilter,
|
activeEntityFilter,
|
||||||
activeStatusFilter,
|
activeStatusFilter,
|
||||||
sortConfig,
|
|
||||||
isMobile,
|
isMobile,
|
||||||
onEntityFilterChange,
|
onEntityFilterChange,
|
||||||
onStatusFilterChange,
|
onStatusFilterChange,
|
||||||
onSortConfigChange,
|
|
||||||
onClearFilters,
|
onClearFilters,
|
||||||
showClearButton
|
showClearButton
|
||||||
}: QueueFiltersProps) => {
|
}: QueueFiltersProps) => {
|
||||||
@@ -112,13 +107,6 @@ export const QueueFilters = ({
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Sort Controls */}
|
|
||||||
<QueueSortControls
|
|
||||||
sortConfig={sortConfig}
|
|
||||||
onSortChange={onSortConfigChange}
|
|
||||||
isMobile={isMobile}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Clear Filters Button */}
|
{/* Clear Filters Button */}
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
import { ArrowUp, ArrowDown } from 'lucide-react';
|
|
||||||
import { Label } from '@/components/ui/label';
|
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import type { SortConfig, SortField } from '@/types/moderation';
|
|
||||||
|
|
||||||
interface QueueSortControlsProps {
|
|
||||||
sortConfig: SortConfig;
|
|
||||||
onSortChange: (config: SortConfig) => void;
|
|
||||||
isMobile?: boolean;
|
|
||||||
variant?: 'inline' | 'standalone';
|
|
||||||
showLabel?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSortFieldLabel = (field: SortField): string => {
|
|
||||||
switch (field) {
|
|
||||||
case 'created_at': return 'Date Created';
|
|
||||||
case 'username': return 'Submitter';
|
|
||||||
case 'submission_type': return 'Type';
|
|
||||||
case 'status': return 'Status';
|
|
||||||
case 'escalated': return 'Escalated';
|
|
||||||
default: return field;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const QueueSortControls = ({
|
|
||||||
sortConfig,
|
|
||||||
onSortChange,
|
|
||||||
isMobile = false,
|
|
||||||
variant = 'inline',
|
|
||||||
showLabel = true
|
|
||||||
}: QueueSortControlsProps) => {
|
|
||||||
const handleFieldChange = (field: SortField) => {
|
|
||||||
onSortChange({ ...sortConfig, field });
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDirectionToggle = () => {
|
|
||||||
onSortChange({
|
|
||||||
...sortConfig,
|
|
||||||
direction: sortConfig.direction === 'asc' ? 'desc' : 'asc'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={`space-y-2 ${isMobile ? 'w-full' : 'min-w-[180px]'}`}>
|
|
||||||
{showLabel && (
|
|
||||||
<Label className={`font-medium ${isMobile ? 'text-xs' : 'text-sm'}`}>
|
|
||||||
Sort By
|
|
||||||
</Label>
|
|
||||||
)}
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<Select
|
|
||||||
value={sortConfig.field}
|
|
||||||
onValueChange={handleFieldChange}
|
|
||||||
>
|
|
||||||
<SelectTrigger className={isMobile ? "h-10 flex-1" : "flex-1"}>
|
|
||||||
<SelectValue />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="created_at">{getSortFieldLabel('created_at')}</SelectItem>
|
|
||||||
<SelectItem value="username">{getSortFieldLabel('username')}</SelectItem>
|
|
||||||
<SelectItem value="submission_type">{getSortFieldLabel('submission_type')}</SelectItem>
|
|
||||||
<SelectItem value="status">{getSortFieldLabel('status')}</SelectItem>
|
|
||||||
<SelectItem value="escalated">{getSortFieldLabel('escalated')}</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size={isMobile ? "default" : "sm"}
|
|
||||||
onClick={handleDirectionToggle}
|
|
||||||
className={isMobile ? "h-10" : ""}
|
|
||||||
title={sortConfig.direction === 'asc' ? 'Sort Descending' : 'Sort Ascending'}
|
|
||||||
>
|
|
||||||
{sortConfig.direction === 'asc' ? (
|
|
||||||
<ArrowUp className="w-4 h-4" />
|
|
||||||
) : (
|
|
||||||
<ArrowDown className="w-4 h-4" />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -12,8 +12,7 @@ export type { CachedProfile } from './useProfileCache';
|
|||||||
export { useModerationFilters } from './useModerationFilters';
|
export { useModerationFilters } from './useModerationFilters';
|
||||||
export type { ModerationFilters, ModerationFiltersConfig } from './useModerationFilters';
|
export type { ModerationFilters, ModerationFiltersConfig } from './useModerationFilters';
|
||||||
|
|
||||||
export { useModerationSort } from './useModerationSort';
|
// Removed - sorting functionality deleted
|
||||||
export type { ModerationSort, ModerationSortConfig } from './useModerationSort';
|
|
||||||
|
|
||||||
export { usePagination } from './usePagination';
|
export { usePagination } from './usePagination';
|
||||||
export type { PaginationState, PaginationConfig } from './usePagination';
|
export type { PaginationState, PaginationConfig } from './usePagination';
|
||||||
|
|||||||
@@ -6,13 +6,12 @@ import {
|
|||||||
useEntityCache,
|
useEntityCache,
|
||||||
useProfileCache,
|
useProfileCache,
|
||||||
useModerationFilters,
|
useModerationFilters,
|
||||||
useModerationSort,
|
|
||||||
usePagination,
|
usePagination,
|
||||||
useRealtimeSubscriptions,
|
useRealtimeSubscriptions,
|
||||||
} from "./index";
|
} from "./index";
|
||||||
import { useModerationQueue } from "@/hooks/useModerationQueue";
|
import { useModerationQueue } from "@/hooks/useModerationQueue";
|
||||||
import { smartMergeArray } from "@/lib/smartStateUpdate";
|
import { smartMergeArray } from "@/lib/smartStateUpdate";
|
||||||
import type { ModerationItem, EntityFilter, StatusFilter, LoadingState, SortConfig } from "@/types/moderation";
|
import type { ModerationItem, EntityFilter, StatusFilter, LoadingState } from "@/types/moderation";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for useModerationQueueManager
|
* Configuration for useModerationQueueManager
|
||||||
@@ -44,7 +43,6 @@ export interface ModerationQueueManager {
|
|||||||
// Sub-hooks (exposed for granular control)
|
// Sub-hooks (exposed for granular control)
|
||||||
filters: ReturnType<typeof useModerationFilters>;
|
filters: ReturnType<typeof useModerationFilters>;
|
||||||
pagination: ReturnType<typeof usePagination>;
|
pagination: ReturnType<typeof usePagination>;
|
||||||
sort: ReturnType<typeof useModerationSort>;
|
|
||||||
queue: ReturnType<typeof useModerationQueue>;
|
queue: ReturnType<typeof useModerationQueue>;
|
||||||
|
|
||||||
// Realtime
|
// Realtime
|
||||||
@@ -99,11 +97,7 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const sort = useModerationSort({
|
// Removed - sorting functionality deleted
|
||||||
initialConfig: { field: "created_at", direction: "asc" },
|
|
||||||
persist: true,
|
|
||||||
storageKey: "moderationQueue_sortConfig",
|
|
||||||
});
|
|
||||||
|
|
||||||
const queue = useModerationQueue();
|
const queue = useModerationQueue();
|
||||||
const entityCache = useEntityCache();
|
const entityCache = useEntityCache();
|
||||||
@@ -221,9 +215,7 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
|||||||
status
|
status
|
||||||
)
|
)
|
||||||
`,
|
`,
|
||||||
)
|
);
|
||||||
.order("escalated", { ascending: false })
|
|
||||||
.order("created_at", { ascending: true });
|
|
||||||
|
|
||||||
// Apply tab-based status filtering
|
// Apply tab-based status filtering
|
||||||
const tab = filters.activeTab;
|
const tab = filters.activeTab;
|
||||||
@@ -929,7 +921,6 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
|||||||
actionLoading,
|
actionLoading,
|
||||||
filters,
|
filters,
|
||||||
pagination,
|
pagination,
|
||||||
sort,
|
|
||||||
queue,
|
queue,
|
||||||
newItemsCount,
|
newItemsCount,
|
||||||
pendingNewItems,
|
pendingNewItems,
|
||||||
|
|||||||
@@ -1,145 +0,0 @@
|
|||||||
/**
|
|
||||||
* Moderation Queue Sort Hook
|
|
||||||
*
|
|
||||||
* Manages sort configuration for the moderation queue with persistence.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { useState, useCallback, useEffect } from 'react';
|
|
||||||
import type { SortConfig, SortField, SortDirection } from '@/types/moderation';
|
|
||||||
import {
|
|
||||||
getDefaultSortConfig,
|
|
||||||
loadSortConfig,
|
|
||||||
saveSortConfig,
|
|
||||||
toggleSortDirection as toggleDirection,
|
|
||||||
isDefaultSortConfig,
|
|
||||||
} from '@/lib/moderation/sorting';
|
|
||||||
|
|
||||||
export interface ModerationSortConfig {
|
|
||||||
/** Initial sort configuration */
|
|
||||||
initialConfig?: SortConfig;
|
|
||||||
|
|
||||||
/** Whether to persist sort config */
|
|
||||||
persist?: boolean;
|
|
||||||
|
|
||||||
/** localStorage key for persistence */
|
|
||||||
storageKey?: string;
|
|
||||||
|
|
||||||
/** Callback when sort config changes */
|
|
||||||
onChange?: (config: SortConfig) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ModerationSort {
|
|
||||||
/** Current sort configuration */
|
|
||||||
config: SortConfig;
|
|
||||||
|
|
||||||
/** Sort field */
|
|
||||||
field: SortField;
|
|
||||||
|
|
||||||
/** Sort direction */
|
|
||||||
direction: SortDirection;
|
|
||||||
|
|
||||||
/** Set sort field */
|
|
||||||
setField: (field: SortField) => void;
|
|
||||||
|
|
||||||
/** Set sort direction */
|
|
||||||
setDirection: (direction: SortDirection) => void;
|
|
||||||
|
|
||||||
/** Toggle sort direction */
|
|
||||||
toggleDirection: () => void;
|
|
||||||
|
|
||||||
/** Set both field and direction */
|
|
||||||
setConfig: (config: SortConfig) => void;
|
|
||||||
|
|
||||||
/** Reset to default */
|
|
||||||
reset: () => void;
|
|
||||||
|
|
||||||
/** Check if using default config */
|
|
||||||
isDefault: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook for managing moderation queue sort configuration
|
|
||||||
*
|
|
||||||
* @param config - Configuration options
|
|
||||||
* @returns Sort state and actions
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const sort = useModerationSort({
|
|
||||||
* persist: true,
|
|
||||||
* onChange: (config) => fetchItems(config)
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* // Use in component
|
|
||||||
* <Select value={sort.field} onValueChange={sort.setField}>
|
|
||||||
* <SelectItem value="created_at">Date</SelectItem>
|
|
||||||
* <SelectItem value="username">User</SelectItem>
|
|
||||||
* </Select>
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export function useModerationSort(config: ModerationSortConfig = {}): ModerationSort {
|
|
||||||
const {
|
|
||||||
initialConfig,
|
|
||||||
persist = true,
|
|
||||||
storageKey = 'moderationQueue_sortConfig',
|
|
||||||
onChange,
|
|
||||||
} = config;
|
|
||||||
|
|
||||||
// Load persisted or use initial/default config
|
|
||||||
const [sortConfig, setSortConfig] = useState<SortConfig>(() => {
|
|
||||||
if (initialConfig) return initialConfig;
|
|
||||||
if (persist) return loadSortConfig(storageKey);
|
|
||||||
return getDefaultSortConfig();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Persist changes
|
|
||||||
useEffect(() => {
|
|
||||||
if (persist) {
|
|
||||||
saveSortConfig(sortConfig, storageKey);
|
|
||||||
}
|
|
||||||
onChange?.(sortConfig);
|
|
||||||
}, [sortConfig, persist, storageKey, onChange]);
|
|
||||||
|
|
||||||
// Set sort field (keep direction)
|
|
||||||
const setField = useCallback((field: SortField) => {
|
|
||||||
setSortConfig((prev) => ({ ...prev, field }));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Set sort direction (keep field)
|
|
||||||
const setDirection = useCallback((direction: SortDirection) => {
|
|
||||||
setSortConfig((prev) => ({ ...prev, direction }));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Toggle sort direction
|
|
||||||
const toggleSortDirection = useCallback(() => {
|
|
||||||
setSortConfig((prev) => ({
|
|
||||||
...prev,
|
|
||||||
direction: toggleDirection(prev.direction),
|
|
||||||
}));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Set entire config
|
|
||||||
const setConfig = useCallback((newConfig: SortConfig) => {
|
|
||||||
setSortConfig(newConfig);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Reset to default
|
|
||||||
const reset = useCallback(() => {
|
|
||||||
setSortConfig(getDefaultSortConfig());
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Check if using default config
|
|
||||||
const isDefault = isDefaultSortConfig(sortConfig);
|
|
||||||
|
|
||||||
return {
|
|
||||||
config: sortConfig,
|
|
||||||
field: sortConfig.field,
|
|
||||||
direction: sortConfig.direction,
|
|
||||||
setField,
|
|
||||||
setDirection,
|
|
||||||
toggleDirection: toggleSortDirection,
|
|
||||||
setConfig,
|
|
||||||
reset,
|
|
||||||
isDefault,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -43,18 +43,7 @@ export type {
|
|||||||
DeleteSubmissionConfig,
|
DeleteSubmissionConfig,
|
||||||
} from './actions';
|
} from './actions';
|
||||||
|
|
||||||
// Sorting utilities
|
// Removed - sorting functionality deleted
|
||||||
export {
|
|
||||||
sortModerationItems,
|
|
||||||
getDefaultSortConfig,
|
|
||||||
loadSortConfig,
|
|
||||||
saveSortConfig,
|
|
||||||
toggleSortDirection,
|
|
||||||
getSortFieldLabel,
|
|
||||||
isDefaultSortConfig,
|
|
||||||
} from './sorting';
|
|
||||||
|
|
||||||
export type { SortConfig, SortField, SortDirection } from '@/types/moderation';
|
|
||||||
|
|
||||||
// Realtime subscription utilities
|
// Realtime subscription utilities
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -1,151 +0,0 @@
|
|||||||
/**
|
|
||||||
* Moderation Queue Sorting Utilities
|
|
||||||
*
|
|
||||||
* Provides sorting functions and utilities for moderation queue items.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type { ModerationItem, SortField, SortDirection, SortConfig } from '@/types/moderation';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort moderation items based on configuration
|
|
||||||
*
|
|
||||||
* @param items - Array of moderation items to sort
|
|
||||||
* @param config - Sort configuration
|
|
||||||
* @returns Sorted array of items
|
|
||||||
*/
|
|
||||||
export function sortModerationItems(
|
|
||||||
items: ModerationItem[],
|
|
||||||
config: SortConfig
|
|
||||||
): ModerationItem[] {
|
|
||||||
const { field, direction } = config;
|
|
||||||
|
|
||||||
return [...items].sort((a, b) => {
|
|
||||||
let comparison = 0;
|
|
||||||
|
|
||||||
switch (field) {
|
|
||||||
case 'created_at':
|
|
||||||
comparison = new Date(a.created_at).getTime() - new Date(b.created_at).getTime();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'username':
|
|
||||||
const usernameA = a.user_profile?.username || a.user_profile?.display_name || '';
|
|
||||||
const usernameB = b.user_profile?.username || b.user_profile?.display_name || '';
|
|
||||||
comparison = usernameA.localeCompare(usernameB);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'submission_type':
|
|
||||||
comparison = (a.submission_type || '').localeCompare(b.submission_type || '');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'status':
|
|
||||||
comparison = a.status.localeCompare(b.status);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'escalated':
|
|
||||||
const escalatedA = a.escalated ? 1 : 0;
|
|
||||||
const escalatedB = b.escalated ? 1 : 0;
|
|
||||||
comparison = escalatedB - escalatedA; // Escalated items first
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
comparison = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return direction === 'asc' ? comparison : -comparison;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get default sort configuration
|
|
||||||
*
|
|
||||||
* @returns Default sort config
|
|
||||||
*/
|
|
||||||
export function getDefaultSortConfig(): SortConfig {
|
|
||||||
return {
|
|
||||||
field: 'created_at',
|
|
||||||
direction: 'asc',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load sort configuration from localStorage
|
|
||||||
*
|
|
||||||
* @param key - localStorage key
|
|
||||||
* @returns Saved sort config or default
|
|
||||||
*/
|
|
||||||
export function loadSortConfig(key: string = 'moderationQueue_sortConfig'): SortConfig {
|
|
||||||
try {
|
|
||||||
const saved = localStorage.getItem(key);
|
|
||||||
if (saved) {
|
|
||||||
return JSON.parse(saved);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to load sort config:', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return getDefaultSortConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save sort configuration to localStorage
|
|
||||||
*
|
|
||||||
* @param config - Sort configuration to save
|
|
||||||
* @param key - localStorage key
|
|
||||||
*/
|
|
||||||
export function saveSortConfig(
|
|
||||||
config: SortConfig,
|
|
||||||
key: string = 'moderationQueue_sortConfig'
|
|
||||||
): void {
|
|
||||||
try {
|
|
||||||
localStorage.setItem(key, JSON.stringify(config));
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to save sort config:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggle sort direction
|
|
||||||
*
|
|
||||||
* @param currentDirection - Current sort direction
|
|
||||||
* @returns Toggled direction
|
|
||||||
*/
|
|
||||||
export function toggleSortDirection(currentDirection: SortDirection): SortDirection {
|
|
||||||
return currentDirection === 'asc' ? 'desc' : 'asc';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get human-readable label for sort field
|
|
||||||
*
|
|
||||||
* @param field - Sort field
|
|
||||||
* @returns Human-readable label
|
|
||||||
*/
|
|
||||||
export function getSortFieldLabel(field: SortField): string {
|
|
||||||
switch (field) {
|
|
||||||
case 'created_at':
|
|
||||||
return 'Date Created';
|
|
||||||
case 'username':
|
|
||||||
return 'Submitter';
|
|
||||||
case 'submission_type':
|
|
||||||
return 'Type';
|
|
||||||
case 'status':
|
|
||||||
return 'Status';
|
|
||||||
case 'escalated':
|
|
||||||
return 'Escalated';
|
|
||||||
default:
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if sort config is default
|
|
||||||
*
|
|
||||||
* @param config - Sort configuration to check
|
|
||||||
* @returns True if config matches default
|
|
||||||
*/
|
|
||||||
export function isDefaultSortConfig(config: SortConfig): boolean {
|
|
||||||
const defaultConfig = getDefaultSortConfig();
|
|
||||||
return (
|
|
||||||
config.field === defaultConfig.field &&
|
|
||||||
config.direction === defaultConfig.direction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -99,26 +99,7 @@ export type StatusFilter = 'all' | 'pending' | 'partially_approved' | 'flagged'
|
|||||||
*/
|
*/
|
||||||
export type QueueTab = 'mainQueue' | 'archive';
|
export type QueueTab = 'mainQueue' | 'archive';
|
||||||
|
|
||||||
/**
|
// Removed - sorting functionality deleted
|
||||||
* Fields that can be used for sorting the moderation queue
|
|
||||||
*/
|
|
||||||
export type SortField = 'created_at' | 'username' | 'submission_type' | 'status' | 'escalated';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Direction for sorting (ascending or descending)
|
|
||||||
*/
|
|
||||||
export type SortDirection = 'asc' | 'desc';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration for sorting the moderation queue
|
|
||||||
*/
|
|
||||||
export interface SortConfig {
|
|
||||||
/** Field to sort by */
|
|
||||||
field: SortField;
|
|
||||||
|
|
||||||
/** Direction to sort */
|
|
||||||
direction: SortDirection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loading states for the moderation queue
|
* Loading states for the moderation queue
|
||||||
|
|||||||
Reference in New Issue
Block a user