From d032c95c178d27e40cac1f0fb0c0a3e82554545a Mon Sep 17 00:00:00 2001 From: alphaeusmote <41258468-alphaeusmote@users.noreply.replit.com> Date: Thu, 10 Apr 2025 00:00:05 +0000 Subject: [PATCH] Add organization management to the dashboard and authentication Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9111ef36-26c8-4085-84ca-a35dc1fec1b5 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7083d608-d6d3-4a6a-9a27-6286c5109627/e253bb9d-e465-4b95-aa04-9c7925837b19.jpg --- .../organization/organization-list-card.tsx | 88 +++++++++++++++++++ client/src/pages/auth-page.tsx | 4 + client/src/pages/dashboard.tsx | 10 ++- 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 client/src/components/organization/organization-list-card.tsx diff --git a/client/src/components/organization/organization-list-card.tsx b/client/src/components/organization/organization-list-card.tsx new file mode 100644 index 0000000..a6fe3a7 --- /dev/null +++ b/client/src/components/organization/organization-list-card.tsx @@ -0,0 +1,88 @@ +import { Organization } from "@shared/schema"; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Building, Users, Calendar } from "lucide-react"; +import { format } from "date-fns"; +import { useOrganization } from "@/context/organization-context"; + +interface OrganizationListCardProps { + organizations: Organization[]; +} + +export function OrganizationListCard({ organizations }: OrganizationListCardProps) { + const { currentOrganization, setCurrentOrganization } = useOrganization(); + + if (!organizations || organizations.length === 0) { + return ( + + + Organizations + + You don't have any organizations yet. + + + +
+

+ Create an organization in the settings page. +

+
+
+
+ ); + } + + return ( + + + + + Organizations + + + Select an organization to manage its resources + + + +
+ {organizations.map((org) => ( +
setCurrentOrganization(org)} + > +
+
+
{org.name}
+ {!org.isActive && ( + + Inactive + + )} +
+
+ {currentOrganization?.id === org.id && ( + Current + )} +
+
+
+
+ + 3 Members +
+
+ + Created {format(new Date(org.createdAt), 'MMM d, yyyy')} +
+
+
+ ))} +
+
+
+ ); +} \ No newline at end of file diff --git a/client/src/pages/auth-page.tsx b/client/src/pages/auth-page.tsx index b56f348..4f04d26 100644 --- a/client/src/pages/auth-page.tsx +++ b/client/src/pages/auth-page.tsx @@ -2,6 +2,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { useAuth } from "@/hooks/use-auth"; +import { useOrganization } from "@/context/organization-context"; import { Redirect } from "wouter"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; @@ -11,6 +12,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ThemeToggle } from "@/components/shared/theme-toggle"; import { useTheme } from "@/hooks/use-theme"; import { Loader2 } from "lucide-react"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; const loginSchema = z.object({ username: z.string().min(3, "Username must be at least 3 characters"), @@ -22,6 +24,7 @@ const registerSchema = z.object({ email: z.string().email("Please enter a valid email"), password: z.string().min(8, "Password must be at least 8 characters"), fullName: z.string().optional(), + organizationId: z.number().optional(), }); export default function AuthPage() { @@ -43,6 +46,7 @@ export default function AuthPage() { email: "", password: "", fullName: "", + organizationId: undefined, }, }); diff --git a/client/src/pages/dashboard.tsx b/client/src/pages/dashboard.tsx index 3e2ef44..3e68cf6 100644 --- a/client/src/pages/dashboard.tsx +++ b/client/src/pages/dashboard.tsx @@ -1,5 +1,5 @@ import { useQuery } from "@tanstack/react-query"; -import { Domain, DnsRecord, Provider } from "@shared/schema"; +import { Domain, DnsRecord, Provider, Organization } from "@shared/schema"; import { MainLayout } from "@/components/layouts/main-layout"; import { DomainStatusCard } from "@/components/domain/domain-status-card"; import { DomainTable } from "@/components/domain/domain-table"; @@ -7,13 +7,14 @@ import { RecentActivity } from "@/components/activity/recent-activity"; import { DnsUpdateChart } from "@/components/charts/dns-update-chart"; import { ProviderDistributionChart } from "@/components/charts/provider-distribution-chart"; import { RecordTypeChart } from "@/components/charts/record-type-chart"; +import { OrganizationListCard } from "@/components/organization/organization-list-card"; import { Button } from "@/components/ui/button"; import { useOrganization } from "@/context/organization-context"; import { Home, CheckCircle, AlertTriangle, AlertCircle, Plus, Wrench, FileText } from "lucide-react"; import { Link } from "wouter"; export default function DashboardPage() { - const { currentOrganization } = useOrganization(); + const { currentOrganization, organizations } = useOrganization(); // Fetch domains, DNS records, and providers const { data: domains = [] } = useQuery({ @@ -86,6 +87,11 @@ export default function DashboardPage() { + {/* Organizations List */} +
+ +
+ {/* Domain Status Table */}