Refactor EditTenantModal into EditTenant page with multi-step form for tenant details, contact information, and settings. Enhance validation schemas and integrate file upload functionality for branding assets. Update routing to navigate to the new EditTenant page instead of using a modal. Remove legacy modal handling from Tenants component.
This commit is contained in:
parent
2ced49373c
commit
c6ee8c7032
File diff suppressed because it is too large
Load Diff
1148
src/pages/EditTenant.tsx
Normal file
1148
src/pages/EditTenant.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ import {
|
|||||||
ActionDropdown,
|
ActionDropdown,
|
||||||
// NewTenantModal, // Commented out - using wizard instead
|
// NewTenantModal, // Commented out - using wizard instead
|
||||||
// ViewTenantModal, // Commented out - using details page instead
|
// ViewTenantModal, // Commented out - using details page instead
|
||||||
EditTenantModal,
|
// EditTenantModal, // Commented out - using edit page instead
|
||||||
DeleteConfirmationModal,
|
DeleteConfirmationModal,
|
||||||
DataTable,
|
DataTable,
|
||||||
Pagination,
|
Pagination,
|
||||||
@ -18,7 +18,6 @@ import { Plus, Download, ArrowUpDown } from 'lucide-react';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { tenantService } from '@/services/tenant-service';
|
import { tenantService } from '@/services/tenant-service';
|
||||||
import type { Tenant } from '@/types/tenant';
|
import type { Tenant } from '@/types/tenant';
|
||||||
import { showToast } from '@/utils/toast';
|
|
||||||
|
|
||||||
// Helper function to get tenant initials
|
// Helper function to get tenant initials
|
||||||
const getTenantInitials = (name: string): string => {
|
const getTenantInitials = (name: string): string => {
|
||||||
@ -86,11 +85,10 @@ const Tenants = (): ReactElement => {
|
|||||||
|
|
||||||
// View, Edit, Delete modals
|
// View, Edit, Delete modals
|
||||||
// const [viewModalOpen, setViewModalOpen] = useState<boolean>(false); // Commented out - using details page instead
|
// const [viewModalOpen, setViewModalOpen] = useState<boolean>(false); // Commented out - using details page instead
|
||||||
const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
|
// const [editModalOpen, setEditModalOpen] = useState<boolean>(false); // Commented out - using edit page instead
|
||||||
const [deleteModalOpen, setDeleteModalOpen] = useState<boolean>(false);
|
const [deleteModalOpen, setDeleteModalOpen] = useState<boolean>(false);
|
||||||
const [selectedTenantId, setSelectedTenantId] = useState<string | null>(null);
|
const [selectedTenantId, setSelectedTenantId] = useState<string | null>(null);
|
||||||
const [selectedTenantName, setSelectedTenantName] = useState<string>('');
|
const [selectedTenantName, setSelectedTenantName] = useState<string>('');
|
||||||
const [isUpdating, setIsUpdating] = useState<boolean>(false);
|
|
||||||
const [isDeleting, setIsDeleting] = useState<boolean>(false);
|
const [isDeleting, setIsDeleting] = useState<boolean>(false);
|
||||||
|
|
||||||
const fetchTenants = async (
|
const fetchTenants = async (
|
||||||
@ -152,40 +150,11 @@ const Tenants = (): ReactElement => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Edit tenant handler
|
// Edit tenant handler
|
||||||
const handleEditTenant = (tenantId: string, tenantName: string): void => {
|
const handleEditTenant = (tenantId: string): void => {
|
||||||
setSelectedTenantId(tenantId);
|
navigate(`/tenants/${tenantId}/edit`);
|
||||||
setSelectedTenantName(tenantName);
|
|
||||||
setEditModalOpen(true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update tenant handler
|
// Update tenant handler - removed, now handled in EditTenant page
|
||||||
const handleUpdateTenant = async (
|
|
||||||
id: string,
|
|
||||||
data: {
|
|
||||||
name: string;
|
|
||||||
slug: string;
|
|
||||||
status: 'active' | 'suspended' | 'deleted';
|
|
||||||
settings?: Record<string, unknown> | null;
|
|
||||||
subscription_tier?: string | null;
|
|
||||||
max_users?: number | null;
|
|
||||||
max_modules?: number | null;
|
|
||||||
}
|
|
||||||
): Promise<void> => {
|
|
||||||
try {
|
|
||||||
setIsUpdating(true);
|
|
||||||
const response = await tenantService.update(id, data);
|
|
||||||
const message = response.message || `Tenant updated successfully`;
|
|
||||||
const description = response.message ? undefined : `${data.name} has been updated`;
|
|
||||||
showToast.success(message, description);
|
|
||||||
setEditModalOpen(false);
|
|
||||||
setSelectedTenantId(null);
|
|
||||||
await fetchTenants(currentPage, limit, statusFilter, orderBy);
|
|
||||||
} catch (err: any) {
|
|
||||||
throw err; // Let the modal handle the error display
|
|
||||||
} finally {
|
|
||||||
setIsUpdating(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Delete tenant handler
|
// Delete tenant handler
|
||||||
const handleDeleteTenant = (tenantId: string, tenantName: string): void => {
|
const handleDeleteTenant = (tenantId: string, tenantName: string): void => {
|
||||||
@ -212,12 +181,6 @@ const Tenants = (): ReactElement => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load tenant for view/edit
|
|
||||||
const loadTenant = async (id: string): Promise<Tenant> => {
|
|
||||||
const response = await tenantService.getById(id);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Define table columns
|
// Define table columns
|
||||||
const columns: Column<Tenant>[] = [
|
const columns: Column<Tenant>[] = [
|
||||||
{
|
{
|
||||||
@ -291,7 +254,7 @@ const Tenants = (): ReactElement => {
|
|||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<ActionDropdown
|
<ActionDropdown
|
||||||
onView={() => handleViewTenant(tenant.id)}
|
onView={() => handleViewTenant(tenant.id)}
|
||||||
onEdit={() => handleEditTenant(tenant.id, tenant.name)}
|
onEdit={() => handleEditTenant(tenant.id)}
|
||||||
onDelete={() => handleDeleteTenant(tenant.id, tenant.name)}
|
onDelete={() => handleDeleteTenant(tenant.id, tenant.name)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -320,7 +283,7 @@ const Tenants = (): ReactElement => {
|
|||||||
</div>
|
</div>
|
||||||
<ActionDropdown
|
<ActionDropdown
|
||||||
onView={() => handleViewTenant(tenant.id)}
|
onView={() => handleViewTenant(tenant.id)}
|
||||||
onEdit={() => handleEditTenant(tenant.id, tenant.name)}
|
onEdit={() => handleEditTenant(tenant.id)}
|
||||||
onDelete={() => handleDeleteTenant(tenant.id, tenant.name)}
|
onDelete={() => handleDeleteTenant(tenant.id, tenant.name)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -489,19 +452,7 @@ const Tenants = (): ReactElement => {
|
|||||||
onLoadTenant={loadTenant}
|
onLoadTenant={loadTenant}
|
||||||
/> */}
|
/> */}
|
||||||
|
|
||||||
{/* Edit Tenant Modal */}
|
{/* Edit Tenant Modal - Removed, using edit page instead */}
|
||||||
<EditTenantModal
|
|
||||||
isOpen={editModalOpen}
|
|
||||||
onClose={() => {
|
|
||||||
setEditModalOpen(false);
|
|
||||||
setSelectedTenantId(null);
|
|
||||||
setSelectedTenantName('');
|
|
||||||
}}
|
|
||||||
tenantId={selectedTenantId}
|
|
||||||
onLoadTenant={loadTenant}
|
|
||||||
onSubmit={handleUpdateTenant}
|
|
||||||
isLoading={isUpdating}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Delete Confirmation Modal */}
|
{/* Delete Confirmation Modal */}
|
||||||
<DeleteConfirmationModal
|
<DeleteConfirmationModal
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import Dashboard from '@/pages/Dashboard';
|
import Dashboard from '@/pages/Dashboard';
|
||||||
import Tenants from '@/pages/Tenants';
|
import Tenants from '@/pages/Tenants';
|
||||||
import CreateTenantWizard from '@/pages/CreateTenantWizard';
|
import CreateTenantWizard from '@/pages/CreateTenantWizard';
|
||||||
|
import EditTenant from '@/pages/EditTenant';
|
||||||
import TenantDetails from '@/pages/TenantDetails';
|
import TenantDetails from '@/pages/TenantDetails';
|
||||||
import Users from '@/pages/Users';
|
import Users from '@/pages/Users';
|
||||||
import Roles from '@/pages/Roles';
|
import Roles from '@/pages/Roles';
|
||||||
@ -27,6 +28,10 @@ export const superAdminRoutes: RouteConfig[] = [
|
|||||||
path: '/tenants/create-wizard',
|
path: '/tenants/create-wizard',
|
||||||
element: <CreateTenantWizard />,
|
element: <CreateTenantWizard />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/tenants/:id/edit',
|
||||||
|
element: <EditTenant />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/tenants/:id',
|
path: '/tenants/:id',
|
||||||
element: <TenantDetails />,
|
element: <TenantDetails />,
|
||||||
|
|||||||
@ -42,10 +42,12 @@ export interface UpdateTenantRequest {
|
|||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
status: 'active' | 'suspended' | 'deleted';
|
status: 'active' | 'suspended' | 'deleted';
|
||||||
|
domain?: string | null;
|
||||||
settings?: Record<string, unknown> | null;
|
settings?: Record<string, unknown> | null;
|
||||||
subscription_tier?: string | null;
|
subscription_tier?: string | null;
|
||||||
max_users?: number | null;
|
max_users?: number | null;
|
||||||
max_modules?: number | null;
|
max_modules?: number | null;
|
||||||
|
module_ids?: string[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateTenantResponse {
|
export interface UpdateTenantResponse {
|
||||||
|
|||||||
@ -19,6 +19,28 @@ export interface TenantUser {
|
|||||||
status: string;
|
status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TenantAdmin {
|
||||||
|
id: string;
|
||||||
|
email: string;
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
contact_phone?: string | null;
|
||||||
|
address_line1?: string | null;
|
||||||
|
address_line2?: string | null;
|
||||||
|
city?: string | null;
|
||||||
|
state?: string | null;
|
||||||
|
postal_code?: string | null;
|
||||||
|
country?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TenantBranding {
|
||||||
|
logo_file_path?: string | null;
|
||||||
|
favicon_file_path?: string | null;
|
||||||
|
primary_color?: string | null;
|
||||||
|
secondary_color?: string | null;
|
||||||
|
accent_color?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Tenant {
|
export interface Tenant {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@ -31,9 +53,15 @@ export interface Tenant {
|
|||||||
domain?: string | null;
|
domain?: string | null;
|
||||||
enable_sso?: boolean;
|
enable_sso?: boolean;
|
||||||
enable_2fa?: boolean;
|
enable_2fa?: boolean;
|
||||||
|
logo_file_path?: string | null;
|
||||||
|
favicon_file_path?: string | null;
|
||||||
|
primary_color?: string | null;
|
||||||
|
secondary_color?: string | null;
|
||||||
|
accent_color?: string | null;
|
||||||
modules?: string[]; // Array of module IDs (legacy, for backward compatibility)
|
modules?: string[]; // Array of module IDs (legacy, for backward compatibility)
|
||||||
assignedModules?: AssignedModule[]; // Array of assigned modules with full details
|
assignedModules?: AssignedModule[]; // Array of assigned modules with full details
|
||||||
users?: TenantUser[]; // Array of tenant users
|
users?: TenantUser[]; // Array of tenant users
|
||||||
|
tenant_admin?: TenantAdmin; // Tenant admin user details
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user