Admin Panel Builder
Context Files (Read First)
For structure and conventions, read from Docs/context/:
Docs/context/repo-structure.md- File locationsDocs/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
| Page | Path | Purpose |
|------|------|---------|
| Dashboard | /admin | Overview with section cards |
| AI | /admin/ai | Prompts, pricing, quotas, features (6 tabs) |
| App Config | /admin/app-config | Application configuration |
| Audio | /admin/audio | TTS voices, version config (2 tabs) |
| Auth Tokens | /admin/auth-tokens | API key management (collapsible sections) |
| Backup | /admin/backup | Data backup management |
| Bibles | /admin/bibles | Bible version management |
| Changelog | /admin/changelog | Changelog entries |
| Cinema | /admin/cinema | Background visuals, music (2 tabs) |
| Encouragement | /admin/encouragement | Encouragement messages |
| Errors | /admin/errors | JS + HTTP error reports |
| FAQ | /admin/faq | FAQ management |
| Feature Suggestions | /admin/feature-suggestions | User feature suggestions |
| Feedback | /admin/feedback | App feedback |
| I18n | /admin/i18n | Internationalization |
| Maintenance Calendar | /admin/maintenance | Maintenance scheduling |
| Onboarding | /admin/onboarding | Onboarding tours |
| Practices | /admin/practices | Practice templates, prayer sets, spiritual paths (6 tabs) |
| Prayers | /admin/prayers | Prayer calendars, prayer CRUD, JSON import |
| Questions | /admin/questions | Q&A management |
| Reading Plans | /admin/reading-plans | Bible reading plans (global + pending tabs) |
| Recordings | /admin/recordings | Audio recordings |
| Reels | /admin/reels | Video reels |
| Slogans | /admin/slogans | Daily slogans |
| Subscriptions | /admin/subscriptions | Plans, feature limits |
| Systems | /admin/systems | System/app registry |
| System Status | /admin/system-status | System health |
| Task Templates | /admin/task-templates | Task template management |
| Testing & Demos | /admin/testing | Component test pages |
| Topics | /admin/topics | Topic suggestions, QA issues |
| Translations | /admin/translations | Term translation cache |
| Users | /admin/users | User management, history (3 tabs) |
| Video | /admin/video | Video series/clips |
| Widget Analytics | /admin/widget-analytics | Embed 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:
- Create new page file with subset of managers
- Add route in App.tsx
- Add dashboard card for new page
- Remove tabs from original page
- 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
- Admin panel structure: See references/admin-panel-structure.md - Complete mapping of pages, tabs, sections, manager components
- Page structure & layout: See references/structure.md
- Refactoring guide: See references/refactoring.md
- Component patterns: See references/components.md