From 3e10a8116233d98babccf84984abbfdd201df23b Mon Sep 17 00:00:00 2001 From: Guido X Jansen Date: Sun, 22 Feb 2026 22:26:13 +0100 Subject: [PATCH] refactor(web): split 16 oversized components into focused modules (#74) * fix(test): stabilize auth mocks to prevent infinite re-render loops The useAuth mock created new function references on every call, causing components with getAccessToken in useCallback/useEffect deps to enter infinite re-render loops. Extract mock object to a stable reference. Also add maxWorkers (cpuCount/2) and testTimeout (10s) to vitest config to reduce CPU contention and give axe-core tests adequate time. * refactor(web): split 16 oversized components into ~38 focused modules Enforce ~150-line limit for non-page TSX files by extracting cohesive sub-components. All 606 tests pass, typecheck clean, zero regressions. Priority 1 (400+ lines): admin/moderation, admin/sybil-detection, admin/settings, settings, community-profile-settings, admin/plugins. Priority 2 (250-400 lines): admin/onboarding, admin/trust-seeds, admin/categories, onboarding-modal, topic-form, settings/reports. Priority 3 (150-250 lines): report-dialog, markdown-editor, community-profile-settings, search-input. Also adds formatDateShort to shared format utilities and extracts useCommunityProfile hook. --- src/app/admin/categories/page.tsx | 181 +------ src/app/admin/moderation/page.tsx | 470 +----------------- src/app/admin/onboarding/page.tsx | 213 +------- src/app/admin/plugins/page.tsx | 268 +--------- src/app/admin/settings/page.tsx | 460 +---------------- src/app/admin/sybil-detection/page.tsx | 390 +-------------- src/app/admin/trust-seeds/page.tsx | 239 +-------- src/app/settings/page.tsx | 292 ++--------- src/app/settings/reports/page.tsx | 164 +----- .../admin/categories/category-form.tsx | 103 ++++ .../admin/categories/category-row.tsx | 85 ++++ .../admin/moderation/action-log-tab.tsx | 54 ++ .../admin/moderation/first-post-tab.tsx | 153 ++++++ .../admin/moderation/reported-users-tab.tsx | 40 ++ .../admin/moderation/reports-tab.tsx | 88 ++++ .../admin/moderation/thresholds-tab.tsx | 159 ++++++ .../onboarding/onboarding-field-form.tsx | 142 ++++++ .../onboarding/onboarding-field-item.tsx | 99 ++++ src/components/admin/plugins/plugin-card.tsx | 115 +++++ .../admin/plugins/plugin-settings-modal.tsx | 84 ++++ .../admin/plugins/settings-field.tsx | 89 ++++ .../settings/community-settings-form.tsx | 143 ++++++ .../admin/settings/pds-override-dialog.tsx | 124 +++++ .../admin/settings/pds-trust-section.tsx | 138 +++++ .../admin/sybil/behavioral-flags-section.tsx | 51 ++ .../admin/sybil/cluster-detail-view.tsx | 115 +++++ .../admin/sybil/cluster-list-view.tsx | 52 ++ src/components/admin/sybil/status-badge.tsx | 32 ++ src/components/admin/sybil/suspicion-bar.tsx | 28 ++ .../admin/sybil/trust-graph-status-card.tsx | 58 +++ .../admin/trust-seeds/add-seed-dialog.tsx | 104 ++++ .../admin/trust-seeds/trust-seed-card.tsx | 62 +++ .../community-profile-form-fields.tsx | 77 +++ src/components/community-profile-settings.tsx | 381 ++------------ src/components/markdown-editor.tsx | 88 +--- src/components/markdown-toolbar-actions.ts | 88 ++++ src/components/onboarding-field-input.tsx | 175 +++++++ src/components/onboarding-modal.tsx | 169 +------ src/components/report-dialog.tsx | 117 +---- src/components/report-form-content.tsx | 121 +++++ src/components/search-input.tsx | 55 +- src/components/search-suggestion-list.tsx | 55 ++ .../settings/community-overrides-section.tsx | 121 +++++ .../settings/content-safety-section.tsx | 71 +++ .../settings/cross-posting-section.tsx | 76 +++ .../settings/notifications-section.tsx | 59 +++ .../settings/report-appeal-form.tsx | 82 +++ src/components/settings/report-card.tsx | 121 +++++ src/components/source-profile-preview.tsx | 38 ++ src/components/topic-content-editor.tsx | 84 ++++ src/components/topic-cross-post-section.tsx | 70 +++ src/components/topic-form-validation.ts | 39 ++ src/components/topic-form.tsx | 257 +--------- src/components/topic-meta-fields.tsx | 104 ++++ src/hooks/use-community-profile.ts | 245 +++++++++ src/lib/format.ts | 30 ++ 56 files changed, 4025 insertions(+), 3493 deletions(-) create mode 100644 src/components/admin/categories/category-form.tsx create mode 100644 src/components/admin/categories/category-row.tsx create mode 100644 src/components/admin/moderation/action-log-tab.tsx create mode 100644 src/components/admin/moderation/first-post-tab.tsx create mode 100644 src/components/admin/moderation/reported-users-tab.tsx create mode 100644 src/components/admin/moderation/reports-tab.tsx create mode 100644 src/components/admin/moderation/thresholds-tab.tsx create mode 100644 src/components/admin/onboarding/onboarding-field-form.tsx create mode 100644 src/components/admin/onboarding/onboarding-field-item.tsx create mode 100644 src/components/admin/plugins/plugin-card.tsx create mode 100644 src/components/admin/plugins/plugin-settings-modal.tsx create mode 100644 src/components/admin/plugins/settings-field.tsx create mode 100644 src/components/admin/settings/community-settings-form.tsx create mode 100644 src/components/admin/settings/pds-override-dialog.tsx create mode 100644 src/components/admin/settings/pds-trust-section.tsx create mode 100644 src/components/admin/sybil/behavioral-flags-section.tsx create mode 100644 src/components/admin/sybil/cluster-detail-view.tsx create mode 100644 src/components/admin/sybil/cluster-list-view.tsx create mode 100644 src/components/admin/sybil/status-badge.tsx create mode 100644 src/components/admin/sybil/suspicion-bar.tsx create mode 100644 src/components/admin/sybil/trust-graph-status-card.tsx create mode 100644 src/components/admin/trust-seeds/add-seed-dialog.tsx create mode 100644 src/components/admin/trust-seeds/trust-seed-card.tsx create mode 100644 src/components/community-profile-form-fields.tsx create mode 100644 src/components/markdown-toolbar-actions.ts create mode 100644 src/components/onboarding-field-input.tsx create mode 100644 src/components/report-form-content.tsx create mode 100644 src/components/search-suggestion-list.tsx create mode 100644 src/components/settings/community-overrides-section.tsx create mode 100644 src/components/settings/content-safety-section.tsx create mode 100644 src/components/settings/cross-posting-section.tsx create mode 100644 src/components/settings/notifications-section.tsx create mode 100644 src/components/settings/report-appeal-form.tsx create mode 100644 src/components/settings/report-card.tsx create mode 100644 src/components/source-profile-preview.tsx create mode 100644 src/components/topic-content-editor.tsx create mode 100644 src/components/topic-cross-post-section.tsx create mode 100644 src/components/topic-form-validation.ts create mode 100644 src/components/topic-meta-fields.tsx create mode 100644 src/hooks/use-community-profile.ts diff --git a/src/app/admin/categories/page.tsx b/src/app/admin/categories/page.tsx index 7850144..1ca4ff4 100644 --- a/src/app/admin/categories/page.tsx +++ b/src/app/admin/categories/page.tsx @@ -8,103 +8,16 @@ 'use client' import { useState, useEffect, useCallback } from 'react' -import { PencilSimple, Plus, TrashSimple } from '@phosphor-icons/react' +import { Plus } from '@phosphor-icons/react' import { AdminLayout } from '@/components/admin/admin-layout' import { ErrorAlert } from '@/components/error-alert' +import { CategoryRow } from '@/components/admin/categories/category-row' +import { CategoryForm } from '@/components/admin/categories/category-form' +import type { EditingCategory } from '@/components/admin/categories/category-form' import { getCategories, createCategory, updateCategory, deleteCategory } from '@/lib/api/client' -import { cn } from '@/lib/utils' -import type { CategoryTreeNode, MaturityRating } from '@/lib/api/types' +import type { CategoryTreeNode } from '@/lib/api/types' import { useAuth } from '@/hooks/use-auth' -const MATURITY_LABELS: Record = { - safe: 'Safe', - mature: 'Mature', - adult: 'Adult', -} - -const MATURITY_COLORS: Record = { - safe: 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400', - mature: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400', - adult: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400', -} - -interface EditingCategory { - id: string | null - name: string - slug: string - description: string - parentId: string | null - maturityRating: MaturityRating -} - -function CategoryRow({ - category, - depth, - onEdit, - onDelete, -}: { - category: CategoryTreeNode - depth: number - onEdit: (cat: CategoryTreeNode) => void - onDelete: (id: string) => void -}) { - return ( - <> -
0 && 'ml-6' - )} - > -
-
-

{category.name}

- {category.description && ( -

{category.description}

- )} -
-
-
- - {MATURITY_LABELS[category.maturityRating]} - - - -
-
- {category.children.map((child) => ( - - ))} - - ) -} - export default function AdminCategoriesPage() { const { getAccessToken } = useAuth() const [categories, setCategories] = useState([]) @@ -214,87 +127,15 @@ export default function AdminCategoriesPage() { {actionError && setActionError(null)} />} - {/* Edit form */} {editing && ( -
-

- {editing.id ? 'Edit Category' : 'New Category'} -

-
-
- - setEditing({ ...editing, name: e.target.value })} - className="mt-1 w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground" - /> -
-
- - setEditing({ ...editing, slug: e.target.value })} - className="mt-1 w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground" - /> -
-
- -