mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-24 23:41:10 +02:00
This commit implements a comprehensive database-driven site configuration system that allows administrators to control the visibility and behavior of homepage elements, navigation links, footer sections, and route availability without code changes. Backend Changes: - Added SiteConfiguration model with singleton pattern (id=1) - Created migration 38_add_site_configuration_table.py - Implemented site_configuration_routes.py with public + admin endpoints - Added Pydantic schemas for validation (Base, Update, Read, Public) - Registered routes in main app Frontend Changes: - Created SiteConfigContext.tsx for global state management - Updated app/layout.tsx to wrap app in SiteConfigProvider - Implemented RouteGuard component for disabled routes - Updated navbar with conditional rendering (pricing, docs, github, signin) - Updated hero-section with conditional buttons (get started, talk to us) - Updated footer with conditional sections and custom copyright - Applied route guards to pricing, contact, terms, privacy pages Admin Panel: - Created /dashboard/site-settings page with full UI - Visual toggle switches for all configuration options - Real-time updates via API with toast notifications - Organized by section (Header, Homepage, Footer, Routes, Text) - Dark mode support and responsive design Configuration Options: Header: show_pricing_link, show_docs_link, show_github_link, show_sign_in Homepage: show_get_started_button, show_talk_to_us_button Footer: show_pages_section, show_legal_section, show_register_section Routes: disable_pricing/docs/contact/terms/privacy_route Custom: custom_copyright text (max 200 chars) Security: - Superuser-only admin endpoints with JWT validation - Public read-only endpoint for frontend consumption - Input validation via Pydantic schemas - Singleton pattern with database constraints - Client-side route guards for disabled routes Documentation: - Added comprehensive section to claude.md - Includes API docs, migration guide, testing checklist - Example code snippets and configuration tables - Security considerations and future enhancements All configuration defaults to minimal/privacy-focused state (most features disabled by default). Administrators can enable features as needed via the admin panel. Files Changed: 16 files (6 backend, 10 frontend, 1 documentation)
111 lines
2.7 KiB
TypeScript
111 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import React, { createContext, useContext, useEffect, useState } from "react";
|
|
|
|
export interface SiteConfig {
|
|
// Header/Navbar toggles
|
|
show_pricing_link: boolean;
|
|
show_docs_link: boolean;
|
|
show_github_link: boolean;
|
|
show_sign_in: boolean;
|
|
|
|
// Homepage toggles
|
|
show_get_started_button: boolean;
|
|
show_talk_to_us_button: boolean;
|
|
|
|
// Footer toggles
|
|
show_pages_section: boolean;
|
|
show_legal_section: boolean;
|
|
show_register_section: boolean;
|
|
|
|
// Route disabling
|
|
disable_pricing_route: boolean;
|
|
disable_docs_route: boolean;
|
|
disable_contact_route: boolean;
|
|
disable_terms_route: boolean;
|
|
disable_privacy_route: boolean;
|
|
|
|
// Custom text
|
|
custom_copyright: string | null;
|
|
}
|
|
|
|
const defaultConfig: SiteConfig = {
|
|
show_pricing_link: false,
|
|
show_docs_link: false,
|
|
show_github_link: false,
|
|
show_sign_in: true,
|
|
show_get_started_button: false,
|
|
show_talk_to_us_button: false,
|
|
show_pages_section: false,
|
|
show_legal_section: false,
|
|
show_register_section: false,
|
|
disable_pricing_route: true,
|
|
disable_docs_route: true,
|
|
disable_contact_route: true,
|
|
disable_terms_route: true,
|
|
disable_privacy_route: true,
|
|
custom_copyright: "SurfSense 2025",
|
|
};
|
|
|
|
interface SiteConfigContextType {
|
|
config: SiteConfig;
|
|
loading: boolean;
|
|
error: string | null;
|
|
refetch: () => Promise<void>;
|
|
}
|
|
|
|
const SiteConfigContext = createContext<SiteConfigContextType>({
|
|
config: defaultConfig,
|
|
loading: true,
|
|
error: null,
|
|
refetch: async () => {},
|
|
});
|
|
|
|
export function SiteConfigProvider({ children }: { children: React.ReactNode }) {
|
|
const [config, setConfig] = useState<SiteConfig>(defaultConfig);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const fetchConfig = async () => {
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
const backendUrl =
|
|
process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL || "http://localhost:8000";
|
|
const response = await fetch(`${backendUrl}/api/v1/site-config/public`);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch site configuration: ${response.statusText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
setConfig(data);
|
|
} catch (err) {
|
|
const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
|
|
setError(errorMessage);
|
|
console.error("Error fetching site configuration:", err);
|
|
// Keep default config on error
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchConfig();
|
|
}, []);
|
|
|
|
return (
|
|
<SiteConfigContext.Provider value={{ config, loading, error, refetch: fetchConfig }}>
|
|
{children}
|
|
</SiteConfigContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useSiteConfig() {
|
|
const context = useContext(SiteConfigContext);
|
|
if (!context) {
|
|
throw new Error("useSiteConfig must be used within a SiteConfigProvider");
|
|
}
|
|
return context;
|
|
}
|