2026-01-24 03:33:48 +05:30
|
|
|
'use client';
|
|
|
|
|
|
|
|
|
|
import { useEffect, useState } from 'react';
|
|
|
|
|
import { useRouter } from 'next/navigation';
|
|
|
|
|
import Link from 'next/link';
|
|
|
|
|
import {
|
|
|
|
|
profileSectionsService,
|
|
|
|
|
ProfileSection,
|
|
|
|
|
CreateSectionDto,
|
|
|
|
|
UpdateSectionDto,
|
|
|
|
|
getErrorMessage,
|
|
|
|
|
} from '@/services';
|
|
|
|
|
|
|
|
|
|
type ModalType = 'create' | 'edit' | 'delete' | null;
|
|
|
|
|
|
|
|
|
|
export default function ProfileSectionsPage() {
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
const [sections, setSections] = useState<ProfileSection[]>([]);
|
|
|
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
|
const [error, setError] = useState('');
|
|
|
|
|
const [showInactive, setShowInactive] = useState(true);
|
|
|
|
|
|
|
|
|
|
// Modal state
|
|
|
|
|
const [modalType, setModalType] = useState<ModalType>(null);
|
|
|
|
|
const [selectedSection, setSelectedSection] = useState<ProfileSection | null>(null);
|
|
|
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
|
|
|
const [modalError, setModalError] = useState('');
|
|
|
|
|
|
|
|
|
|
// Form state
|
|
|
|
|
const [formData, setFormData] = useState<CreateSectionDto>({
|
|
|
|
|
name: '',
|
|
|
|
|
description: '',
|
|
|
|
|
icon: '',
|
|
|
|
|
isActive: true,
|
|
|
|
|
isGlobal: false,
|
|
|
|
|
sortOrder: 0,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
fetchSections();
|
|
|
|
|
}, [showInactive]);
|
|
|
|
|
|
|
|
|
|
const fetchSections = async () => {
|
|
|
|
|
setIsLoading(true);
|
|
|
|
|
setError('');
|
|
|
|
|
try {
|
|
|
|
|
const data = await profileSectionsService.getAll(showInactive);
|
|
|
|
|
setSections(data);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const errorMessage = getErrorMessage(err);
|
|
|
|
|
setError(errorMessage);
|
|
|
|
|
if (errorMessage.includes('Unauthorized')) {
|
|
|
|
|
router.push('/login');
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
setIsLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const openCreateModal = () => {
|
|
|
|
|
setFormData({
|
|
|
|
|
name: '',
|
|
|
|
|
description: '',
|
|
|
|
|
icon: '',
|
|
|
|
|
isActive: true,
|
|
|
|
|
isGlobal: false,
|
|
|
|
|
sortOrder: 0,
|
|
|
|
|
});
|
|
|
|
|
setModalError('');
|
|
|
|
|
setModalType('create');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const openEditModal = (section: ProfileSection) => {
|
|
|
|
|
setSelectedSection(section);
|
|
|
|
|
setFormData({
|
|
|
|
|
name: section.name,
|
|
|
|
|
description: section.description || '',
|
|
|
|
|
icon: section.icon || '',
|
|
|
|
|
isActive: section.isActive,
|
|
|
|
|
isGlobal: section.isGlobal,
|
|
|
|
|
sortOrder: section.sortOrder,
|
|
|
|
|
});
|
|
|
|
|
setModalError('');
|
|
|
|
|
setModalType('edit');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const openDeleteModal = (section: ProfileSection) => {
|
|
|
|
|
setSelectedSection(section);
|
|
|
|
|
setModalError('');
|
|
|
|
|
setModalType('delete');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const closeModal = () => {
|
|
|
|
|
setModalType(null);
|
|
|
|
|
setSelectedSection(null);
|
|
|
|
|
setModalError('');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleCreate = async (e: React.FormEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
setIsSubmitting(true);
|
|
|
|
|
setModalError('');
|
|
|
|
|
try {
|
|
|
|
|
await profileSectionsService.create(formData);
|
|
|
|
|
closeModal();
|
|
|
|
|
fetchSections();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
setModalError(getErrorMessage(err));
|
|
|
|
|
} finally {
|
|
|
|
|
setIsSubmitting(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleUpdate = async (e: React.FormEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
if (!selectedSection) return;
|
|
|
|
|
setIsSubmitting(true);
|
|
|
|
|
setModalError('');
|
|
|
|
|
try {
|
|
|
|
|
await profileSectionsService.update(selectedSection.id, formData as UpdateSectionDto);
|
|
|
|
|
closeModal();
|
|
|
|
|
fetchSections();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
setModalError(getErrorMessage(err));
|
|
|
|
|
} finally {
|
|
|
|
|
setIsSubmitting(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleDelete = async () => {
|
|
|
|
|
if (!selectedSection) return;
|
|
|
|
|
setIsSubmitting(true);
|
|
|
|
|
setModalError('');
|
|
|
|
|
try {
|
|
|
|
|
await profileSectionsService.delete(selectedSection.id);
|
|
|
|
|
closeModal();
|
|
|
|
|
fetchSections();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
setModalError(getErrorMessage(err));
|
|
|
|
|
} finally {
|
|
|
|
|
setIsSubmitting(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const toggleStatus = async (section: ProfileSection) => {
|
|
|
|
|
try {
|
|
|
|
|
await profileSectionsService.update(section.id, { isActive: !section.isActive });
|
|
|
|
|
fetchSections();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
setError(getErrorMessage(err));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div>
|
|
|
|
|
{/* Page Title */}
|
|
|
|
|
<div className="mb-6">
|
|
|
|
|
<h1 className="text-2xl font-bold text-gray-900">Profile Sections</h1>
|
|
|
|
|
<p className="text-gray-500">Manage profile sections and their fields for agent types</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Sections Table */}
|
|
|
|
|
<div className="bg-white rounded-lg shadow">
|
|
|
|
|
<div className="px-6 py-4 border-b border-gray-200">
|
|
|
|
|
<div className="flex justify-between items-center">
|
|
|
|
|
<div className="flex items-center space-x-4">
|
|
|
|
|
<label className="flex items-center space-x-2 text-sm text-gray-600">
|
|
|
|
|
<input
|
|
|
|
|
type="checkbox"
|
|
|
|
|
checked={showInactive}
|
|
|
|
|
onChange={(e) => setShowInactive(e.target.checked)}
|
|
|
|
|
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
|
|
|
/>
|
|
|
|
|
<span>Show Inactive</span>
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex space-x-3">
|
|
|
|
|
<button
|
|
|
|
|
onClick={fetchSections}
|
|
|
|
|
className="px-4 py-2 border border-gray-300 hover:bg-gray-50 text-gray-700 text-sm font-medium rounded-lg transition-colors flex items-center"
|
|
|
|
|
>
|
|
|
|
|
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
|
|
|
</svg>
|
|
|
|
|
Refresh
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
onClick={openCreateModal}
|
|
|
|
|
className="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors flex items-center"
|
|
|
|
|
>
|
|
|
|
|
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
|
|
|
|
|
</svg>
|
|
|
|
|
Add Section
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{error && (
|
|
|
|
|
<div className="px-6 py-4 bg-red-50 border-b border-red-200">
|
|
|
|
|
<p className="text-red-700 text-sm">{error}</p>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<div className="overflow-x-auto">
|
|
|
|
|
{isLoading ? (
|
|
|
|
|
<div className="flex items-center justify-center py-12">
|
|
|
|
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
|
|
|
|
</div>
|
|
|
|
|
) : sections.length === 0 ? (
|
|
|
|
|
<div className="text-center py-12">
|
|
|
|
|
<svg className="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 10h16M4 14h16M4 18h16" />
|
|
|
|
|
</svg>
|
|
|
|
|
<p className="mt-2 text-gray-500">No profile sections found</p>
|
|
|
|
|
<button
|
|
|
|
|
onClick={openCreateModal}
|
|
|
|
|
className="mt-4 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors"
|
|
|
|
|
>
|
|
|
|
|
Create First Section
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<table className="min-w-full divide-y divide-gray-200">
|
|
|
|
|
<thead className="bg-gray-50">
|
|
|
|
|
<tr>
|
|
|
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
|
|
|
Section
|
|
|
|
|
</th>
|
|
|
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
|
|
|
Description
|
|
|
|
|
</th>
|
|
|
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
|
|
|
Fields
|
|
|
|
|
</th>
|
|
|
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
|
|
|
Agent Types
|
|
|
|
|
</th>
|
|
|
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
|
|
|
Global
|
|
|
|
|
</th>
|
|
|
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
|
|
|
Status
|
|
|
|
|
</th>
|
|
|
|
|
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
|
|
|
Actions
|
|
|
|
|
</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody className="bg-white divide-y divide-gray-200">
|
|
|
|
|
{sections.map((section) => (
|
|
|
|
|
<tr key={section.id} className="hover:bg-gray-50">
|
|
|
|
|
<td className="px-6 py-4 whitespace-nowrap">
|
|
|
|
|
<div className="flex items-center">
|
|
|
|
|
{section.icon && (
|
|
|
|
|
<span className="mr-2 text-lg">{section.icon}</span>
|
|
|
|
|
)}
|
|
|
|
|
<div>
|
|
|
|
|
<div className="text-sm font-medium text-gray-900">{section.name}</div>
|
|
|
|
|
<div className="text-xs text-gray-500">{section.slug}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td className="px-6 py-4">
|
|
|
|
|
<div className="text-sm text-gray-500 max-w-xs truncate">
|
|
|
|
|
{section.description || '-'}
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td className="px-6 py-4 whitespace-nowrap">
|
|
|
|
|
<Link
|
|
|
|
|
href={`/dashboard/profile-sections/${section.id}`}
|
|
|
|
|
className="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800 hover:bg-blue-200"
|
|
|
|
|
>
|
|
|
|
|
{section._count?.fields || 0} fields
|
|
|
|
|
<svg className="ml-1 w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
|
|
|
|
</svg>
|
|
|
|
|
</Link>
|
|
|
|
|
</td>
|
|
|
|
|
<td className="px-6 py-4 whitespace-nowrap">
|
|
|
|
|
<div className="text-sm text-gray-500">
|
|
|
|
|
{section._count?.agentTypeSections || 0} assigned
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td className="px-6 py-4 whitespace-nowrap">
|
2026-01-24 12:49:34 +05:30
|
|
|
<div className="flex items-center space-x-2">
|
|
|
|
|
{section.isSystem && (
|
|
|
|
|
<span className="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-amber-100 text-amber-800">
|
|
|
|
|
System
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
<span
|
|
|
|
|
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
|
|
|
|
|
section.isGlobal
|
|
|
|
|
? 'bg-purple-100 text-purple-800'
|
|
|
|
|
: 'bg-gray-100 text-gray-600'
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
{section.isGlobal ? 'Global' : 'Specific'}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
2026-01-24 03:33:48 +05:30
|
|
|
</td>
|
|
|
|
|
<td className="px-6 py-4 whitespace-nowrap">
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => toggleStatus(section)}
|
|
|
|
|
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full cursor-pointer transition-colors ${
|
|
|
|
|
section.isActive
|
|
|
|
|
? 'bg-green-100 text-green-800 hover:bg-green-200'
|
|
|
|
|
: 'bg-gray-100 text-gray-800 hover:bg-gray-200'
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
{section.isActive ? 'Active' : 'Inactive'}
|
|
|
|
|
</button>
|
|
|
|
|
</td>
|
|
|
|
|
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
|
|
|
|
<Link
|
|
|
|
|
href={`/dashboard/profile-sections/${section.id}`}
|
|
|
|
|
className="text-blue-600 hover:text-blue-900 mr-4"
|
|
|
|
|
>
|
|
|
|
|
Manage
|
|
|
|
|
</Link>
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => openEditModal(section)}
|
|
|
|
|
className="text-gray-600 hover:text-gray-900 mr-4"
|
|
|
|
|
>
|
|
|
|
|
Edit
|
|
|
|
|
</button>
|
2026-01-24 12:49:34 +05:30
|
|
|
{section.isSystem ? (
|
|
|
|
|
<span
|
|
|
|
|
className="text-gray-400 cursor-not-allowed"
|
|
|
|
|
title="System sections cannot be deleted"
|
|
|
|
|
>
|
|
|
|
|
Delete
|
|
|
|
|
</span>
|
|
|
|
|
) : (
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => openDeleteModal(section)}
|
|
|
|
|
className="text-red-600 hover:text-red-900"
|
|
|
|
|
>
|
|
|
|
|
Delete
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
2026-01-24 03:33:48 +05:30
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
))}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Create/Edit Modal */}
|
|
|
|
|
{(modalType === 'create' || modalType === 'edit') && (
|
|
|
|
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
|
|
|
|
<div className="bg-white rounded-lg shadow-xl max-w-md w-full mx-4">
|
|
|
|
|
<div className="px-6 py-4 border-b border-gray-200">
|
|
|
|
|
<h3 className="text-lg font-semibold text-gray-900">
|
|
|
|
|
{modalType === 'create' ? 'Create Profile Section' : 'Edit Profile Section'}
|
|
|
|
|
</h3>
|
|
|
|
|
</div>
|
|
|
|
|
<form onSubmit={modalType === 'create' ? handleCreate : handleUpdate}>
|
|
|
|
|
<div className="px-6 py-4 space-y-4">
|
|
|
|
|
{modalError && (
|
|
|
|
|
<div className="p-3 bg-red-50 border border-red-200 rounded-lg">
|
|
|
|
|
<p className="text-red-700 text-sm">{modalError}</p>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
|
|
|
Name <span className="text-red-500">*</span>
|
|
|
|
|
</label>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={formData.name}
|
|
|
|
|
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
|
|
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-900 bg-white placeholder:text-gray-500"
|
|
|
|
|
placeholder="e.g., Location, Experience, Education"
|
|
|
|
|
required
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
|
|
|
Description
|
|
|
|
|
</label>
|
|
|
|
|
<textarea
|
|
|
|
|
value={formData.description}
|
|
|
|
|
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
|
|
|
|
rows={3}
|
|
|
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-900 bg-white placeholder:text-gray-500"
|
|
|
|
|
placeholder="Brief description of this section"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
|
|
|
Icon (emoji)
|
|
|
|
|
</label>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={formData.icon}
|
|
|
|
|
onChange={(e) => setFormData({ ...formData, icon: e.target.value })}
|
|
|
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-900 bg-white placeholder:text-gray-500"
|
|
|
|
|
placeholder="e.g., location_on"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
|
|
|
Sort Order
|
|
|
|
|
</label>
|
|
|
|
|
<input
|
|
|
|
|
type="number"
|
|
|
|
|
value={formData.sortOrder}
|
|
|
|
|
onChange={(e) => setFormData({ ...formData, sortOrder: parseInt(e.target.value) || 0 })}
|
|
|
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-900 bg-white"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center space-x-6">
|
|
|
|
|
<div className="flex items-center">
|
|
|
|
|
<input
|
|
|
|
|
type="checkbox"
|
|
|
|
|
id="isActive"
|
|
|
|
|
checked={formData.isActive}
|
|
|
|
|
onChange={(e) => setFormData({ ...formData, isActive: e.target.checked })}
|
|
|
|
|
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
|
|
|
/>
|
|
|
|
|
<label htmlFor="isActive" className="ml-2 text-sm text-gray-700">
|
|
|
|
|
Active
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center">
|
|
|
|
|
<input
|
|
|
|
|
type="checkbox"
|
|
|
|
|
id="isGlobal"
|
|
|
|
|
checked={formData.isGlobal}
|
|
|
|
|
onChange={(e) => setFormData({ ...formData, isGlobal: e.target.checked })}
|
|
|
|
|
className="rounded border-gray-300 text-purple-600 focus:ring-purple-500"
|
|
|
|
|
/>
|
|
|
|
|
<label htmlFor="isGlobal" className="ml-2 text-sm text-gray-700">
|
|
|
|
|
Global (all agent types)
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={closeModal}
|
|
|
|
|
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
Cancel
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
type="submit"
|
|
|
|
|
disabled={isSubmitting}
|
|
|
|
|
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50"
|
|
|
|
|
>
|
|
|
|
|
{isSubmitting ? 'Saving...' : modalType === 'create' ? 'Create' : 'Save Changes'}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Delete Confirmation Modal */}
|
|
|
|
|
{modalType === 'delete' && selectedSection && (
|
|
|
|
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
|
|
|
|
<div className="bg-white rounded-lg shadow-xl max-w-md w-full mx-4">
|
|
|
|
|
<div className="px-6 py-4 border-b border-gray-200">
|
|
|
|
|
<h3 className="text-lg font-semibold text-gray-900">Delete Profile Section</h3>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="px-6 py-4">
|
|
|
|
|
{modalError && (
|
|
|
|
|
<div className="mb-4 p-3 bg-red-50 border border-red-200 rounded-lg">
|
|
|
|
|
<p className="text-red-700 text-sm">{modalError}</p>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
<p className="text-gray-600">
|
|
|
|
|
Are you sure you want to delete <span className="font-semibold">{selectedSection.name}</span>?
|
|
|
|
|
</p>
|
|
|
|
|
{(selectedSection._count?.fields && selectedSection._count.fields > 0) && (
|
|
|
|
|
<p className="mt-2 text-amber-600 text-sm">
|
|
|
|
|
Warning: This section has {selectedSection._count.fields} field(s). They will also be deleted.
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
|
|
|
|
|
<button
|
|
|
|
|
onClick={closeModal}
|
|
|
|
|
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
Cancel
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
onClick={handleDelete}
|
|
|
|
|
disabled={isSubmitting}
|
|
|
|
|
className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors disabled:opacity-50"
|
|
|
|
|
>
|
|
|
|
|
{isSubmitting ? 'Deleting...' : 'Delete'}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|