Spectaculous-Code avatar

admin-panel-builder

Expert assistant for creating and maintaining admin panel pages in the KR92 Bible Voice project. Use

by Spectaculous-Code|Open Source

Admin Panel Builder

Context Files (Read First)

For structure and conventions, read from Docs/context/:

  • Docs/context/repo-structure.md - File locations
  • Docs/context/conventions.md - Naming and patterns

Quick Reference

File Locations

src/pages/Admin*.tsx           # Admin page components
src/components/admin/*.tsx     # Manager components
src/components/admin/tokens/   # Token-specific components
App.tsx                        # Route definitions (lines 71-81)

Current Admin Pages

PagePathPurpose
Dashboard/adminOverview with section cards
AI/admin/aiPrompts, pricing, quotas, features (6 tabs)
App Config/admin/app-configApplication configuration
Audio/admin/audioTTS voices, version config (2 tabs)
Auth Tokens/admin/auth-tokensAPI key management (collapsible sections)
Backup/admin/backupData backup management
Bibles/admin/biblesBible version management
Changelog/admin/changelogChangelog entries
Cinema/admin/cinemaBackground visuals, music (2 tabs)
Encouragement/admin/encouragementEncouragement messages
Errors/admin/errorsJS + HTTP error reports
FAQ/admin/faqFAQ management
Feature Suggestions/admin/feature-suggestionsUser feature suggestions
Feedback/admin/feedbackApp feedback
I18n/admin/i18nInternationalization
Maintenance Calendar/admin/maintenanceMaintenance scheduling
Onboarding/admin/onboardingOnboarding tours
Practices/admin/practicesPractice templates, prayer sets, spiritual paths (6 tabs)
Prayers/admin/prayersPrayer calendars, prayer CRUD, JSON import
Questions/admin/questionsQ&A management
Reading Plans/admin/reading-plansBible reading plans (global + pending tabs)
Recordings/admin/recordingsAudio recordings
Reels/admin/reelsVideo reels
Slogans/admin/slogansDaily slogans
Subscriptions/admin/subscriptionsPlans, feature limits
Systems/admin/systemsSystem/app registry
System Status/admin/system-statusSystem health
Task Templates/admin/task-templatesTask template management
Testing & Demos/admin/testingComponent test pages
Topics/admin/topicsTopic suggestions, QA issues
Translations/admin/translationsTerm translation cache
Users/admin/usersUser management, history (3 tabs)
Video/admin/videoVideo series/clips
Widget Analytics/admin/widget-analyticsEmbed usage stats

For detailed page structure (tabs, sections, components): See references/admin-panel-structure.md

Creating New Admin Page

1. Create Page File

// src/pages/AdminNewFeaturePage.tsx

import { useUserRole } from "@shared-auth/hooks/useUserRole";
import { SidebarProvider } from "@/components/ui/sidebar";
import { AppSidebar } from "@/components/AppSidebar";
import AdminHeader from "@/components/admin/AdminHeader";
import { FeatureIcon } from "lucide-react";

const AdminNewFeaturePage = () => {
  const { isAdmin } = useUserRole();

  if (!isAdmin) {
    return (
      <div className="flex items-center justify-center min-h-screen">
        <p className="text-muted-foreground">No permission</p>
      </div>
    );
  }

  return (
    <SidebarProvider>
      <div className="min-h-screen flex w-full bg-background">
        <AppSidebar onNavigateToContinueAudio={() => {}} onNavigateToContinueText={() => {}} />
        <main className="flex-1 overflow-auto">
          <AdminHeader
            title="New Feature"
            icon={<FeatureIcon className="h-6 w-6 text-primary" />}
          />
          <div className="p-6">
            <div className="max-w-6xl mx-auto space-y-8">
              {/* Content here */}
            </div>
          </div>
        </main>
      </div>
    </SidebarProvider>
  );
};

export default AdminNewFeaturePage;

2. Add Route

In App.tsx:

import AdminNewFeaturePage from "./pages/AdminNewFeaturePage";

// In routes section:
<Route path="/admin/new-feature" element={<AdminNewFeaturePage />} />

3. Add Dashboard Card

In AdminDashboardPage.tsx, add to sections array:

{
  title: "New Feature",
  description: "Description",
  icon: FeatureIcon,
  path: "/admin/new-feature",
}

Splitting Pages (Refactoring)

When a page has too many tabs or distinct functionality:

  1. Create new page file with subset of managers
  2. Add route in App.tsx
  3. Add dashboard card for new page
  4. Remove tabs from original page
  5. Update imports - remove unused managers

See references/refactoring.md for detailed steps.

AdminHeader Props

<AdminHeader
  title="Page Title"
  description="Optional subtitle"
  icon={<Icon className="h-6 w-6 text-primary" />}
  showBackButton={true}   // Shows back arrow to /admin
  showSidebarTrigger={true}
/>

Tab Structure Pattern

<Tabs defaultValue="first" className="space-y-4">
  <TabsList>
    <TabsTrigger value="first">First Tab</TabsTrigger>
    <TabsTrigger value="second">Second Tab</TabsTrigger>
  </TabsList>
  <TabsContent value="first">
    <Card>
      <CardHeader><CardTitle>Section</CardTitle></CardHeader>
      <CardContent><ManagerComponent /></CardContent>
    </Card>
  </TabsContent>
</Tabs>

Reusable Patterns

JSON Import Dialog

Pattern used in prayer calendar admin (AdminCalendarsTab.tsx):

function ImportDialog() {
  const [json, setJson] = useState("");
  const [result, setResult] = useState<{ success: number; failed: number } | null>(null);

  const handleImport = async () => {
    const parsed = JSON.parse(json);
    // Validate required fields
    // Batch insert with error tracking
    // Invalidate queries on success
    queryClient.invalidateQueries({ queryKey: ["items"] });
    setResult({ success: inserted, failed: errors });
  };

  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="outline"><Upload className="h-4 w-4 mr-2" />Tuo JSON</Button>
      </DialogTrigger>
      <DialogContent>
        <Textarea value={json} onChange={e => setJson(e.target.value)} rows={10} />
        <pre className="text-xs text-muted-foreground">{EXAMPLE_JSON}</pre>
        <Button onClick={handleImport}>Import</Button>
      </DialogContent>
    </Dialog>
  );
}

Summary-to-Entity Creation ("Luo koosteesta")

Pattern for creating entities from AI summaries:

<Button variant="outline" asChild>
  <Link to="/summaries">
    <List className="h-4 w-4 mr-2" />
    Luo koosteesta
  </Link>
</Button>

Used in: AdminReadingPlansPage for creating reading plans from summaries.

Essential Patterns

Role Check

const { isAdmin } = useUserRole();
if (!isAdmin) return <NoPermission />;

Data Query

const { data, isLoading } = useQuery({
  queryKey: ['feature'],
  queryFn: async () => {
    const { data, error } = await supabase.from('table').select('*');
    if (error) throw error;
    return data;
  },
});

Mutation with Toast

const mutation = useMutation({
  mutationFn: async (id: string) => {
    const { error } = await supabase.from('table').delete().eq('id', id);
    if (error) throw error;
  },
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['feature'] });
    toast({ title: "Success" });
  },
  onError: (error: Error) => {
    toast({ title: "Error", description: error.message, variant: "destructive" });
  },
});

Cross-cutting learnings: See .claude/LEARNINGS.md → "Supabase/Database" section for RLS+GRANT patterns and admin role checks.

References