Enhance organization management by adding edit, view, and delete functionality.

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/d42a5cc3-4f02-4792-ab34-87a1ef6e61c1.jpg
This commit is contained in:
alphaeusmote
2025-04-10 00:53:44 +00:00
2 changed files with 112 additions and 3 deletions
+95 -2
View File
@@ -1,6 +1,6 @@
import { createContext, useContext, useState, useEffect, ReactNode } from "react";
import { useQuery, useMutation, UseMutationResult } from "@tanstack/react-query";
import { Organization, InsertOrganization } from "@shared/schema";
import { Organization, InsertOrganization, Domain } from "@shared/schema";
import { useAuth } from "@/hooks/use-auth";
import { apiRequest, queryClient } from "@/lib/queryClient";
import { useToast } from "@/hooks/use-toast";
@@ -11,6 +11,10 @@ type OrganizationContextType = {
setCurrentOrganization: (organization: Organization) => void;
isLoading: boolean;
createOrganizationMutation: UseMutationResult<Organization, Error, InsertOrganization>;
updateOrganizationMutation: UseMutationResult<Organization, Error, { id: string; data: Partial<InsertOrganization> }>;
deleteOrganizationMutation: UseMutationResult<boolean, Error, string>;
domainsLoading: boolean;
domainsByOrganization: Record<string, Domain[]>;
};
const OrganizationContext = createContext<OrganizationContextType | undefined>(undefined);
@@ -19,6 +23,7 @@ export function OrganizationProvider({ children }: { children: ReactNode }) {
const { user } = useAuth();
const { toast } = useToast();
const [currentOrganization, setCurrentOrganization] = useState<Organization | null>(null);
const [domainsByOrganization, setDomainsByOrganization] = useState<Record<string, Domain[]>>({});
const { data: organizations = [], isLoading } = useQuery<Organization[]>({
queryKey: ["/api/organizations"],
@@ -26,6 +31,32 @@ export function OrganizationProvider({ children }: { children: ReactNode }) {
enabled: !!user,
});
// Load domains for each organization
const { isLoading: domainsLoading } = useQuery<Domain[]>({
queryKey: ["/api/domains"],
enabled: !!currentOrganization
});
// Use the domains data to group by organization
const { data: domains = [] } = useQuery<Domain[]>({
queryKey: ["/api/domains"],
enabled: !!currentOrganization
});
// Group domains by organization when domains change
useEffect(() => {
if (domains.length > 0) {
const domainsByOrg: Record<string, Domain[]> = {};
domains.forEach(domain => {
if (!domainsByOrg[domain.organizationId]) {
domainsByOrg[domain.organizationId] = [];
}
domainsByOrg[domain.organizationId].push(domain);
});
setDomainsByOrganization(domainsByOrg);
}
}, [domains]);
const createOrganizationMutation = useMutation({
mutationFn: async (orgData: InsertOrganization) => {
const res = await apiRequest("POST", "/api/organizations", orgData);
@@ -47,6 +78,64 @@ export function OrganizationProvider({ children }: { children: ReactNode }) {
});
},
});
const updateOrganizationMutation = useMutation({
mutationFn: async ({ id, data }: { id: string; data: Partial<InsertOrganization> }) => {
const res = await apiRequest("PATCH", `/api/organizations/${id}`, data);
return await res.json();
},
onSuccess: (updatedOrg: Organization) => {
queryClient.invalidateQueries({ queryKey: ["/api/organizations"] });
toast({
title: "Organization updated",
description: `Organization '${updatedOrg.name}' has been updated successfully.`,
});
// If the current organization was updated, update it in the state
if (currentOrganization?.id === updatedOrg.id) {
setCurrentOrganization(updatedOrg);
}
},
onError: (error: Error) => {
toast({
title: "Failed to update organization",
description: error.message,
variant: "destructive",
});
},
});
const deleteOrganizationMutation = useMutation({
mutationFn: async (id: string) => {
const res = await apiRequest("DELETE", `/api/organizations/${id}`);
return res.ok;
},
onSuccess: (_, id) => {
queryClient.invalidateQueries({ queryKey: ["/api/organizations"] });
// If the current organization was deleted, set another one as current
if (currentOrganization?.id === id) {
const remainingOrgs = organizations.filter(org => org.id !== id);
if (remainingOrgs.length > 0) {
setCurrentOrganization(remainingOrgs[0]);
} else {
setCurrentOrganization(null);
}
}
toast({
title: "Organization deleted",
description: "Organization has been deleted successfully.",
});
},
onError: (error: Error) => {
toast({
title: "Failed to delete organization",
description: error.message,
variant: "destructive",
});
},
});
// Set default organization when organizations are loaded
useEffect(() => {
@@ -72,7 +161,11 @@ export function OrganizationProvider({ children }: { children: ReactNode }) {
currentOrganization,
setCurrentOrganization,
isLoading,
createOrganizationMutation
domainsLoading,
domainsByOrganization,
createOrganizationMutation,
updateOrganizationMutation,
deleteOrganizationMutation
}}
>
{children}
+17 -1
View File
@@ -11,9 +11,19 @@ import { Organization } from '@shared/schema';
import { useOrganization } from '@/context/organization-context';
import { useToast } from '@/hooks/use-toast';
import { useAuth } from '@/hooks/use-auth';
import { Users, Plus, Edit, Trash2, Building } from 'lucide-react';
import { Users, Plus, Edit, Trash2, Building, Calendar, Clock, Info, AlertCircle } from 'lucide-react';
import { apiRequest, queryClient } from '@/lib/queryClient';
import { cn } from '@/lib/utils';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle
} from '@/components/ui/alert-dialog';
export default function OrganizationsPage() {
const { user } = useAuth();
@@ -22,6 +32,12 @@ export default function OrganizationsPage() {
const [newOrgName, setNewOrgName] = useState('');
const [newOrgActive, setNewOrgActive] = useState(true);
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
const [isViewDialogOpen, setIsViewDialogOpen] = useState(false);
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const [selectedOrg, setSelectedOrg] = useState<Organization | null>(null);
const [editOrgName, setEditOrgName] = useState('');
const [editOrgActive, setEditOrgActive] = useState(true);
const isAdmin = user?.role === 'admin';