diff --git a/frontend/src/app/(dashboard)/linting/page.tsx b/frontend/src/app/(dashboard)/linting/page.tsx index c603226..d53547d 100644 --- a/frontend/src/app/(dashboard)/linting/page.tsx +++ b/frontend/src/app/(dashboard)/linting/page.tsx @@ -45,8 +45,6 @@ const RULE_CATALOG = [ { code: 'REMOTE_CONFLICT', severity: 'ERROR', label: 'Remote conflict', desc: 'The video was modified on YouTube after the last sync — local and remote diverged.' }, ] as const; -type RuleCode = typeof RULE_CATALOG[number]['code']; - // ── Helpers ─────────────────────────────────────────────────────────────────── function SevBadge({ sev }: { sev: string }) { @@ -156,7 +154,7 @@ export default function LintingPage() { function toggleSelect(id: string) { setSelected((prev) => { const next = new Set(prev); - next.has(id) ? next.delete(id) : next.add(id); + if (next.has(id)) next.delete(id); else next.add(id); return next; }); } @@ -172,7 +170,7 @@ export default function LintingPage() { function toggleFix(id: string) { setExpandedFix((prev) => { const next = new Set(prev); - next.has(id) ? next.delete(id) : next.add(id); + if (next.has(id)) next.delete(id); else next.add(id); return next; }); } diff --git a/frontend/src/app/(dashboard)/settings/page.tsx b/frontend/src/app/(dashboard)/settings/page.tsx index 6f402f4..332f362 100644 --- a/frontend/src/app/(dashboard)/settings/page.tsx +++ b/frontend/src/app/(dashboard)/settings/page.tsx @@ -483,7 +483,7 @@ export default function SettingsPage() {

Publishing Schedule

- Define the time slots when videos are allowed to publish. Used by the "Next free slot" feature in the video editor. + Define the time slots when videos are allowed to publish. Used by the "Next free slot" feature in the video editor.

@@ -581,7 +581,7 @@ export default function SettingsPage() { /> Show Canva link in video editor - Adds a link next to YouTube Studio that searches Canva for the video's Game Title. + Adds a link next to YouTube Studio that searches Canva for the video's Game Title. ) : ( @@ -601,7 +601,7 @@ export default function SettingsPage() { /> Show deleted videos tab - Reveals a "Deleted" tab in the video list for videos removed from YouTube. They are kept locally for 30 days before being permanently deleted. + Reveals a "Deleted" tab in the video list for videos removed from YouTube. They are kept locally for 30 days before being permanently deleted. ) : ( diff --git a/frontend/src/app/(dashboard)/videos/PushPendingModal.tsx b/frontend/src/app/(dashboard)/videos/PushPendingModal.tsx index 2630ff6..3f9a9c5 100644 --- a/frontend/src/app/(dashboard)/videos/PushPendingModal.tsx +++ b/frontend/src/app/(dashboard)/videos/PushPendingModal.tsx @@ -38,8 +38,7 @@ function TagsDiff({ before, after }: { before: string[]; after: string[] }) { function DiffRow({ field, item }: { field: string; item: PushPendingPreviewItem }) { const label = FIELD_LABELS[field] ?? field; - const diff = item.diff as any; - const d = diff[field]; + const d = item.diff[field as keyof typeof item.diff]; if (!d) return null; if (field === 'tags') { @@ -47,7 +46,7 @@ function DiffRow({ field, item }: { field: string; item: PushPendingPreviewItem {label} {(d.before as string[]).join(', ') || '—'} - + ); } @@ -60,7 +59,7 @@ function DiffRow({ field, item }: { field: string; item: PushPendingPreviewItem ); } - const fmt = (v: any) => { + const fmt = (v: string | number | boolean | string[] | null | undefined) => { if (v === null || v === undefined) return '—'; if (typeof v === 'boolean') return v ? 'Yes' : 'No'; return String(v); diff --git a/frontend/src/app/(dashboard)/videos/[id]/page.tsx b/frontend/src/app/(dashboard)/videos/[id]/page.tsx index 9b2bece..20de68d 100644 --- a/frontend/src/app/(dashboard)/videos/[id]/page.tsx +++ b/frontend/src/app/(dashboard)/videos/[id]/page.tsx @@ -13,7 +13,7 @@ import { SortableContext, verticalListSortingStrategy, arrayMove } from '@dnd-ki import { ArrowLeft, ExternalLink, Loader2, AlertCircle, CheckCircle2, Save, Tag, Shield, Calendar, Hash, RefreshCw, RotateCcw, - Plus, Minus, Layers3, X, Upload, CloudOff, Eye, EyeOff, Search, CalendarPlus, + Layers3, X, Upload, CloudOff, Eye, EyeOff, Search, CalendarPlus, ChevronDown, ChevronUp, } from 'lucide-react'; import { formatDistanceToNow } from 'date-fns'; @@ -34,7 +34,7 @@ import SortableSection from '@/components/shared/SortableSection'; import f from '@/components/shared/FormField.module.css'; import styles from './page.module.css'; -const PRIVACY_LABELS = { PUBLIC: 'Public', PRIVATE: 'Private', UNLISTED: 'Unlisted' } as const; +const PRIVACY_LABELS: Record = { PUBLIC: 'Public', PRIVATE: 'Private', UNLISTED: 'Unlisted' }; function utcToLocalInput(utcIso: string): string { const d = new Date(utcIso); diff --git a/frontend/src/app/(dashboard)/videos/page.tsx b/frontend/src/app/(dashboard)/videos/page.tsx index 62a7d9c..fd98e76 100644 --- a/frontend/src/app/(dashboard)/videos/page.tsx +++ b/frontend/src/app/(dashboard)/videos/page.tsx @@ -3,8 +3,8 @@ import { useState, useEffect, useCallback, useMemo } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useSearchParams, useRouter } from 'next/navigation'; -import { Download, Loader2, AlertCircle, RefreshCw, CheckCircle2, X, Plus } from 'lucide-react'; -import { type SortingState, type ColumnVisibilityState } from '@tanstack/react-table'; +import { Download, Loader2, AlertCircle, RefreshCw, CheckCircle2, Plus } from 'lucide-react'; +import { type SortingState, type VisibilityState } from '@tanstack/react-table'; import VideoTable, { VideoRow, VIDEO_COLUMN_DEFS } from '@/components/video-table/VideoTable'; import ColumnPicker from '@/components/shared/ColumnPicker'; import SavedViewManager from '@/components/shared/SavedViewManager'; @@ -107,9 +107,9 @@ function parseExtraFilters(searchParams: URLSearchParams): Partial const v = searchParams.get(k); if (v !== null) { if (k === 'embeddable' || k === 'selfDeclaredMadeForKids') { - (result as any)[k] = v === 'true'; + (result as Record)[k] = v === 'true'; } else { - (result as any)[k] = v; + (result as Record)[k] = v; } } } @@ -133,7 +133,7 @@ export default function VideosPage() { const { visible, order, setColumns } = useColumnPreferences('videos'); - const columnVisibility = useMemo(() => { + const columnVisibility = useMemo(() => { const allIds = VIDEO_COLUMN_DEFS.map((c) => c.id); return Object.fromEntries(allIds.map((id) => [id, visible.includes(id)])); }, [visible]); @@ -193,14 +193,6 @@ export default function VideosPage() { setPage(1); }, [searchParams, router]); - const clearExtraFilters = useCallback(() => { - const params = new URLSearchParams(searchParams.toString()); - for (const k of EXTRA_FILTER_KEYS) params.delete(k); - params.delete('pendingSync'); params.delete('remoteConflict'); - params.delete('lintStatus'); params.delete('privacyStatus'); params.delete('search'); - router.replace(`/videos?${params.toString()}`); - }, [searchParams, router]); - // Build combined filters for API (base tab query + extra overlays) const urlSearch = searchParams.get('search') ?? undefined; const urlLintStatus = searchParams.get('lintStatus') ?? undefined; diff --git a/frontend/src/components/shared/SavedViewManager.tsx b/frontend/src/components/shared/SavedViewManager.tsx index a17b61c..ee52f39 100644 --- a/frontend/src/components/shared/SavedViewManager.tsx +++ b/frontend/src/components/shared/SavedViewManager.tsx @@ -5,7 +5,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { X, Plus, Pin, PinOff, Trash2, ChevronUp, ChevronDown, Loader2 } from 'lucide-react'; import { fetchSavedViews, createSavedView, updateSavedView, deleteSavedView, - type SavedView, type VideosQuery, type UserPreferences, + type SavedView, type VideosQuery, } from '@/lib/api'; import styles from './SavedViewManager.module.css'; diff --git a/frontend/src/components/video-table/VideoTable.tsx b/frontend/src/components/video-table/VideoTable.tsx index fca997b..41e94da 100644 --- a/frontend/src/components/video-table/VideoTable.tsx +++ b/frontend/src/components/video-table/VideoTable.tsx @@ -8,7 +8,8 @@ import { createColumnHelper, type SortingState, type OnChangeFn, - type ColumnVisibilityState, + type VisibilityState, + type Updater, } from '@tanstack/react-table'; import { useRouter } from 'next/navigation'; import { @@ -522,8 +523,8 @@ export default function VideoTable({ data: VideoRow[]; sorting: SortingState; onSortingChange: OnChangeFn; - columnVisibility?: ColumnVisibilityState; - onColumnVisibilityChange?: (v: ColumnVisibilityState) => void; + columnVisibility?: VisibilityState; + onColumnVisibilityChange?: (v: VisibilityState) => void; columnOrder?: string[]; filters?: Partial; onFiltersChange?: (patch: Partial) => void; @@ -542,7 +543,10 @@ export default function VideoTable({ columnOrder: columnOrder ?? [], }, onSortingChange, - onColumnVisibilityChange: onColumnVisibilityChange as any, + onColumnVisibilityChange: ((updater: Updater) => { + const next = typeof updater === 'function' ? updater(columnVisibility ?? {}) : updater; + onColumnVisibilityChange?.(next); + }) as OnChangeFn, onColumnOrderChange: undefined, getCoreRowModel: getCoreRowModel(), manualSorting: true, @@ -561,7 +565,7 @@ export default function VideoTable({ const clearFilters = () => { const clear: Partial = {}; - ACTIVE_FILTER_KEYS.forEach((k) => { (clear as any)[k] = undefined; }); + ACTIVE_FILTER_KEYS.forEach((k) => { (clear as Record)[k] = undefined; }); onFiltersChange?.(clear); }; diff --git a/frontend/src/hooks/useColumnPreferences.ts b/frontend/src/hooks/useColumnPreferences.ts index b3c1ecf..b5afd6c 100644 --- a/frontend/src/hooks/useColumnPreferences.ts +++ b/frontend/src/hooks/useColumnPreferences.ts @@ -1,7 +1,7 @@ 'use client'; import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { fetchPreferences, patchPreferences } from '@/lib/api'; +import { fetchPreferences, patchPreferences, type UserPreferences } from '@/lib/api'; import { useCallback } from 'react'; export type TableKey = 'videos' | 'linting'; @@ -37,7 +37,7 @@ export function useColumnPreferences(tableKey: TableKey) { [tableKey]: { visible: nextVisible, order: nextOrder }, }, }; - qc.setQueryData(['preferences'], (old: any) => ({ ...old, ...patch })); + qc.setQueryData(['preferences'], (old: UserPreferences | undefined) => ({ ...old, ...patch })); await patchPreferences(patch); }, [prefs, tableKey, qc], diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index bb90421..3e1f900 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -630,6 +630,8 @@ export interface UserPreferences { systemOrder?: string[]; hiddenSystem?: string[]; }; + videoEditLeftCol?: string[]; + videoEditRightCol?: string[]; } export const fetchSavedViews = () =>