diff --git a/.replit b/.replit index c806144..10e1957 100644 --- a/.replit +++ b/.replit @@ -40,3 +40,4 @@ args = "npm run dev" waitForPort = 5000 [agent] +integrations = ["javascript_database==1.0.0", "javascript_log_in_with_replit==1.0.0", "javascript_object_storage==1.0.0"] diff --git a/client/src/App.tsx b/client/src/App.tsx index 747e541..ef9e63a 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -8,6 +8,7 @@ import VideoPage from "@/pages/VideoPage"; import FolxStadlPage from "@/pages/FolxStadlPage"; import GeschichteLiedPage from "@/pages/GeschichteLiedPage"; import GipfelstammtischPage from "@/pages/GipfelstammtischPage"; +import AdminPage from "@/pages/admin"; import NotFound from "@/pages/not-found"; function Router() { @@ -18,6 +19,7 @@ function Router() { + ); diff --git a/client/src/components/loading-spinner.tsx b/client/src/components/loading-spinner.tsx index b41497d..d0a5138 100644 --- a/client/src/components/loading-spinner.tsx +++ b/client/src/components/loading-spinner.tsx @@ -4,7 +4,7 @@ interface LoadingSpinnerProps { className?: string; } -export default function LoadingSpinner({ size = 'md', text = 'Loading...', className = '' }: LoadingSpinnerProps) { +export function LoadingSpinner({ size = 'md', text = 'Loading...', className = '' }: LoadingSpinnerProps) { const sizeClasses = { sm: 'w-6 h-6', md: 'w-10 h-10', @@ -25,4 +25,6 @@ export default function LoadingSpinner({ size = 'md', text = 'Loading...', class
{text}
); -} \ No newline at end of file +} + +export default LoadingSpinner; \ No newline at end of file diff --git a/client/src/hooks/useAuth.ts b/client/src/hooks/useAuth.ts new file mode 100644 index 0000000..d87fe27 --- /dev/null +++ b/client/src/hooks/useAuth.ts @@ -0,0 +1,16 @@ +import { useQuery } from "@tanstack/react-query"; + +export function useAuth() { + const { data: user, isLoading } = useQuery({ + queryKey: ["/api/auth/user"], + retry: false, + }); + + return { + user, + isLoading, + isAuthenticated: !!user, + isAdmin: user?.isAdmin || false, + isSuperAdmin: user?.isSuperAdmin || false, + }; +} \ No newline at end of file diff --git a/client/src/pages/admin.tsx b/client/src/pages/admin.tsx new file mode 100644 index 0000000..2c26030 --- /dev/null +++ b/client/src/pages/admin.tsx @@ -0,0 +1,354 @@ +import { useState } from "react"; +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { useAuth } from "@/hooks/useAuth"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; +import { Badge } from "@/components/ui/badge"; +import { useToast } from "@/hooks/use-toast"; +import { LoadingSpinner } from "@/components/loading-spinner"; +import { apiRequest } from "@/lib/queryClient"; +import type { Video } from "@shared/schema"; +import { Shield, Edit, Upload, Search, Filter, Save, X } from "lucide-react"; + +export default function AdminPage() { + const { user, isLoading: authLoading, isAuthenticated, isAdmin } = useAuth(); + const { toast } = useToast(); + const queryClient = useQueryClient(); + + const [search, setSearch] = useState(""); + const [selectedVideo, setSelectedVideo] = useState