feat: Add Source Serif 4 and Fractul font families and integrate them across the admin UI.
This commit is contained in:
1 parent
4bdb9fe1f7
commit
3dd98d137e
99 files changed
+829
-454
No files matched your search
@@ -141,7 +141,7 @@ export default function AgentTypeSectionsPage() {
|
|||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center min-h-[400px]">
|
<div className="flex items-center justify-center min-h-[400px]">
|
||||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-[#f5a623]"></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -150,34 +150,34 @@ export default function AgentTypeSectionsPage() {
|
|||||||
<div>
|
<div>
|
||||||
{/* Breadcrumb */}
|
{/* Breadcrumb */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<nav className="flex items-center space-x-2 text-sm text-gray-500">
|
<nav className="flex items-center space-x-2 text-sm text-[#666666]">
|
||||||
<Link href="/dashboard/agent-types" className="hover:text-blue-600">
|
<Link href="/dashboard/agent-types" className="hover:text-[#f5a623]">
|
||||||
Agent Types
|
Agent Types
|
||||||
</Link>
|
</Link>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span className="text-gray-900 font-medium">{data?.agentType.name || 'Loading...'}</span>
|
<span className="text-[#00293d] font-medium">{data?.agentType.name || 'Loading...'}</span>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span className="text-gray-900">Sections</span>
|
<span className="text-[#00293d]">Sections</span>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Page Title */}
|
{/* Page Title */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h1 className="text-2xl font-bold text-gray-900">
|
<h1 className="text-2xl font-bold text-[#00293d] font-fractul">
|
||||||
Manage Sections for {data?.agentType.name}
|
Manage Sections for {data?.agentType.name}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-gray-500">
|
<p className="text-[#666666] font-serif">
|
||||||
Customize the order and requirements of profile sections for this agent type.
|
Customize the order and requirements of profile sections for this agent type.
|
||||||
Drag to reorder or use the arrow buttons.
|
Drag to reorder or use the arrow buttons.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Sections List */}
|
{/* Sections List */}
|
||||||
<div className="bg-white rounded-lg shadow">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb]">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
<span className="text-sm text-gray-600">
|
<span className="text-sm text-[#666666]">
|
||||||
{sections.length} section{sections.length !== 1 ? 's' : ''}
|
{sections.length} section{sections.length !== 1 ? 's' : ''}
|
||||||
</span>
|
</span>
|
||||||
{hasChanges && (
|
{hasChanges && (
|
||||||
@@ -192,14 +192,14 @@ export default function AgentTypeSectionsPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={handleReset}
|
onClick={handleReset}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors disabled:opacity-50"
|
className="px-4 py-2 border border-[#e5e7eb] text-[#00293d] rounded-xl hover:bg-[#f5f9f8] transition-colors disabled:opacity-50"
|
||||||
>
|
>
|
||||||
Reset
|
Reset
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50 flex items-center"
|
className="px-4 py-2 bg-[#f5a623] text-white rounded-xl hover:bg-[#e09620] transition-colors disabled:opacity-50 flex items-center"
|
||||||
>
|
>
|
||||||
{isSaving ? (
|
{isSaving ? (
|
||||||
<>
|
<>
|
||||||
@@ -227,13 +227,13 @@ export default function AgentTypeSectionsPage() {
|
|||||||
|
|
||||||
{sections.length === 0 ? (
|
{sections.length === 0 ? (
|
||||||
<div className="text-center py-12">
|
<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">
|
<svg className="mx-auto h-12 w-12 text-[#9ca3af]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
||||||
</svg>
|
</svg>
|
||||||
<p className="mt-2 text-gray-500">No sections assigned to this agent type</p>
|
<p className="mt-2 text-[#666666] font-serif">No sections assigned to this agent type</p>
|
||||||
<Link
|
<Link
|
||||||
href="/dashboard/profile-sections"
|
href="/dashboard/profile-sections"
|
||||||
className="mt-4 inline-block px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors"
|
className="mt-4 inline-block px-4 py-2 bg-[#f5a623] hover:bg-[#e09620] text-white text-sm font-medium rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
Go to Profile Sections
|
Go to Profile Sections
|
||||||
</Link>
|
</Link>
|
||||||
@@ -247,34 +247,34 @@ export default function AgentTypeSectionsPage() {
|
|||||||
onDragStart={() => handleDragStart(index)}
|
onDragStart={() => handleDragStart(index)}
|
||||||
onDragOver={(e) => handleDragOver(e, index)}
|
onDragOver={(e) => handleDragOver(e, index)}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
className={`bg-white rounded-lg shadow p-4 flex items-center justify-between hover:shadow-md cursor-move transition-all ${
|
className={`bg-white rounded-xl shadow-sm border border-[#e5e7eb] p-4 flex items-center justify-between hover:shadow-md cursor-move transition-all ${
|
||||||
draggedIndex === index ? 'ring-2 ring-blue-300 ring-offset-2 shadow-lg' : ''
|
draggedIndex === index ? 'ring-2 ring-[#f5a623]/30 ring-offset-2 shadow-lg' : ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
{/* Drag Handle */}
|
{/* Drag Handle */}
|
||||||
<div className="text-gray-400 cursor-grab">
|
<div className="text-[#9ca3af] cursor-grab">
|
||||||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||||
<path d="M8 6a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm0 6a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm0 6a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm8-12a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm0 6a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm0 6a2 2 0 1 1-4 0 2 2 0 0 1 4 0z" />
|
<path d="M8 6a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm0 6a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm0 6a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm8-12a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm0 6a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm0 6a2 2 0 1 1-4 0 2 2 0 0 1 4 0z" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Order Number */}
|
{/* Order Number */}
|
||||||
<div className="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100 text-gray-600 text-sm font-medium">
|
<div className="w-8 h-8 flex items-center justify-center rounded-full bg-[#e8f0ee] text-[#666666] text-sm font-medium">
|
||||||
{index + 1}
|
{index + 1}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Section Info */}
|
{/* Section Info */}
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<span className="font-medium text-gray-900">{section.name}</span>
|
<span className="font-medium text-[#00293d]">{section.name}</span>
|
||||||
{section.isGlobal && (
|
{section.isGlobal && (
|
||||||
<span className="px-2 py-0.5 text-xs font-semibold rounded-full bg-purple-100 text-purple-800">
|
<span className="px-2 py-0.5 text-xs font-semibold rounded-full bg-[#fff7ed] text-[#f5a623]">
|
||||||
Global
|
Global
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{section.isSystem && (
|
{section.isSystem && (
|
||||||
<span className="px-2 py-0.5 text-xs font-semibold rounded-full bg-blue-100 text-blue-800">
|
<span className="px-2 py-0.5 text-xs font-semibold rounded-full bg-[#e8f0ee] text-[#5ba4a4]">
|
||||||
System
|
System
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -284,7 +284,7 @@ export default function AgentTypeSectionsPage() {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-gray-500">
|
<div className="text-sm text-[#666666]">
|
||||||
{section.description || 'No description'}
|
{section.description || 'No description'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -297,9 +297,9 @@ export default function AgentTypeSectionsPage() {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={section.isRequired}
|
checked={section.isRequired}
|
||||||
onChange={() => toggleRequired(index)}
|
onChange={() => toggleRequired(index)}
|
||||||
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
className="rounded border-[#e5e7eb] text-[#f5a623] focus:ring-[#f5a623]"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm text-gray-600">Required</span>
|
<span className="text-sm text-[#666666]">Required</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* Move Buttons */}
|
{/* Move Buttons */}
|
||||||
@@ -307,7 +307,7 @@ export default function AgentTypeSectionsPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => moveSection(index, 'up')}
|
onClick={() => moveSection(index, 'up')}
|
||||||
disabled={index === 0}
|
disabled={index === 0}
|
||||||
className="p-1.5 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded disabled:opacity-30 disabled:cursor-not-allowed"
|
className="p-1.5 text-[#9ca3af] hover:text-[#666666] hover:bg-[#e8f0ee] rounded disabled:opacity-30 disabled:cursor-not-allowed"
|
||||||
title="Move up"
|
title="Move up"
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -317,7 +317,7 @@ export default function AgentTypeSectionsPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => moveSection(index, 'down')}
|
onClick={() => moveSection(index, 'down')}
|
||||||
disabled={index === sections.length - 1}
|
disabled={index === sections.length - 1}
|
||||||
className="p-1.5 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded disabled:opacity-30 disabled:cursor-not-allowed"
|
className="p-1.5 text-[#9ca3af] hover:text-[#666666] hover:bg-[#e8f0ee] rounded disabled:opacity-30 disabled:cursor-not-allowed"
|
||||||
title="Move down"
|
title="Move down"
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -333,9 +333,9 @@ export default function AgentTypeSectionsPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Info Box */}
|
{/* Info Box */}
|
||||||
<div className="mt-6 p-4 bg-blue-50 rounded-lg border border-blue-200">
|
<div className="mt-6 p-4 bg-[#f5f9f8] rounded-xl border border-[#e5e7eb]">
|
||||||
<h3 className="text-sm font-semibold text-blue-800 mb-2">How Section Ordering Works</h3>
|
<h3 className="text-sm font-semibold text-[#00293d] mb-2 font-fractul">How Section Ordering Works</h3>
|
||||||
<ul className="text-sm text-blue-700 space-y-1">
|
<ul className="text-sm text-[#666666] space-y-1 font-serif">
|
||||||
<li><strong>Global sections</strong> (purple badge) are automatically included for all agent types.</li>
|
<li><strong>Global sections</strong> (purple badge) are automatically included for all agent types.</li>
|
||||||
<li><strong>System sections</strong> (blue badge) cannot be deleted, only hidden.</li>
|
<li><strong>System sections</strong> (blue badge) cannot be deleted, only hidden.</li>
|
||||||
<li><strong>Custom Order</strong> (yellow badge) indicates this agent type has a custom order for that section.</li>
|
<li><strong>Custom Order</strong> (yellow badge) indicates this agent type has a custom order for that section.</li>
|
||||||
|
|||||||
@@ -145,21 +145,21 @@ export default function AgentTypesPage() {
|
|||||||
<div>
|
<div>
|
||||||
{/* Page Title */}
|
{/* Page Title */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h1 className="text-2xl font-bold text-gray-900">Agent Types</h1>
|
<h1 className="text-2xl font-bold text-[#00293d] font-fractul">Agent Types</h1>
|
||||||
<p className="text-gray-500">Manage agent categories and types</p>
|
<p className="text-[#666666] font-serif">Manage agent categories and types</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Agent Types Table */}
|
{/* Agent Types Table */}
|
||||||
<div className="bg-white rounded-lg shadow">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb]">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
<label className="flex items-center space-x-2 text-sm text-gray-600">
|
<label className="flex items-center space-x-2 text-sm text-[#666666] font-serif">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={showInactive}
|
checked={showInactive}
|
||||||
onChange={(e) => setShowInactive(e.target.checked)}
|
onChange={(e) => setShowInactive(e.target.checked)}
|
||||||
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
className="rounded border-[#e5e7eb] text-[#f5a623] focus:ring-[#f5a623]"
|
||||||
/>
|
/>
|
||||||
<span>Show Inactive</span>
|
<span>Show Inactive</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -167,7 +167,7 @@ export default function AgentTypesPage() {
|
|||||||
<div className="flex space-x-3">
|
<div className="flex space-x-3">
|
||||||
<button
|
<button
|
||||||
onClick={fetchAgentTypes}
|
onClick={fetchAgentTypes}
|
||||||
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"
|
className="px-4 py-2 border border-[#e5e7eb] hover:bg-[#f5f9f8] text-[#00293d] 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">
|
<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" />
|
<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" />
|
||||||
@@ -176,7 +176,7 @@ export default function AgentTypesPage() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={openCreateModal}
|
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"
|
className="px-4 py-2 bg-[#f5a623] hover:bg-[#e09620] 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">
|
<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" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
|
||||||
@@ -196,64 +196,64 @@ export default function AgentTypesPage() {
|
|||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="flex items-center justify-center py-12">
|
<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 className="animate-spin rounded-full h-8 w-8 border-b-2 border-[#f5a623]"></div>
|
||||||
</div>
|
</div>
|
||||||
) : agentTypes.length === 0 ? (
|
) : agentTypes.length === 0 ? (
|
||||||
<div className="text-center py-12">
|
<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">
|
<svg className="mx-auto h-12 w-12 text-[#9ca3af]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
||||||
</svg>
|
</svg>
|
||||||
<p className="mt-2 text-gray-500">No agent types found</p>
|
<p className="mt-2 text-[#666666]">No agent types found</p>
|
||||||
<button
|
<button
|
||||||
onClick={openCreateModal}
|
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"
|
className="mt-4 px-4 py-2 bg-[#f5a623] hover:bg-[#e09620] text-white text-sm font-medium rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
Create First Agent Type
|
Create First Agent Type
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<table className="min-w-full divide-y divide-gray-200">
|
<table className="min-w-full divide-y divide-[#e5e7eb]">
|
||||||
<thead className="bg-gray-50">
|
<thead className="bg-[#f5f9f8]">
|
||||||
<tr>
|
<tr>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Name
|
Name
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Description
|
Description
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Icon
|
Icon
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Sort Order
|
Sort Order
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Status
|
Status
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Agents
|
Agents
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-right text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Actions
|
Actions
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="bg-white divide-y divide-gray-200">
|
<tbody className="bg-white divide-y divide-[#e5e7eb]">
|
||||||
{agentTypes.map((agentType) => (
|
{agentTypes.map((agentType) => (
|
||||||
<tr key={agentType.id} className="hover:bg-gray-50">
|
<tr key={agentType.id} className="hover:bg-[#f5f9f8]">
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<div className="text-sm font-medium text-gray-900">{agentType.name}</div>
|
<div className="text-sm font-medium text-[#00293d]">{agentType.name}</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4">
|
<td className="px-6 py-4">
|
||||||
<div className="text-sm text-gray-500 max-w-xs truncate">
|
<div className="text-sm text-[#666666] max-w-xs truncate">
|
||||||
{agentType.description || '-'}
|
{agentType.description || '-'}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<div className="text-sm text-gray-500">{agentType.icon || '-'}</div>
|
<div className="text-sm text-[#666666]">{agentType.icon || '-'}</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<div className="text-sm text-gray-500">{agentType.sortOrder}</div>
|
<div className="text-sm text-[#666666]">{agentType.sortOrder}</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<button
|
<button
|
||||||
@@ -268,18 +268,18 @@ export default function AgentTypesPage() {
|
|||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<div className="text-sm text-gray-500">{agentType._count?.agents || 0}</div>
|
<div className="text-sm text-[#666666]">{agentType._count?.agents || 0}</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||||
<button
|
<button
|
||||||
onClick={() => router.push(`/dashboard/agent-types/${agentType.id}/sections`)}
|
onClick={() => router.push(`/dashboard/agent-types/${agentType.id}/sections`)}
|
||||||
className="text-purple-600 hover:text-purple-900 mr-4"
|
className="text-[#5ba4a4] hover:text-[#5ba4a4]/80 mr-4"
|
||||||
>
|
>
|
||||||
Sections
|
Sections
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => openEditModal(agentType)}
|
onClick={() => openEditModal(agentType)}
|
||||||
className="text-blue-600 hover:text-blue-900 mr-4"
|
className="text-[#f5a623] hover:text-[#e09620] mr-4"
|
||||||
>
|
>
|
||||||
Edit
|
Edit
|
||||||
</button>
|
</button>
|
||||||
@@ -300,10 +300,10 @@ export default function AgentTypesPage() {
|
|||||||
|
|
||||||
{/* Create/Edit Modal */}
|
{/* Create/Edit Modal */}
|
||||||
{(modalType === 'create' || modalType === 'edit') && (
|
{(modalType === 'create' || modalType === 'edit') && (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
<div className="fixed inset-0 bg-black/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="bg-white rounded-xl shadow-xl max-w-md w-full mx-4">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<h3 className="text-lg font-semibold text-gray-900">
|
<h3 className="text-lg font-semibold text-[#00293d]">
|
||||||
{modalType === 'create' ? 'Create Agent Type' : 'Edit Agent Type'}
|
{modalType === 'create' ? 'Create Agent Type' : 'Edit Agent Type'}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -315,42 +315,42 @@ export default function AgentTypesPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Name <span className="text-red-500">*</span>
|
Name <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={formData.name}
|
value={formData.name}
|
||||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Description
|
Description
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
value={formData.description}
|
value={formData.description}
|
||||||
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
||||||
rows={3}
|
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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Icon (emoji or icon name)
|
Icon (emoji or icon name)
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={formData.icon}
|
value={formData.icon}
|
||||||
onChange={(e) => setFormData({ ...formData, icon: e.target.value })}
|
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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
placeholder="e.g. house, building, key"
|
placeholder="e.g. house, building, key"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Sort Order
|
Sort Order
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -360,7 +360,7 @@ export default function AgentTypesPage() {
|
|||||||
onFocus={(e) => e.target.select()}
|
onFocus={(e) => e.target.select()}
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
min={0}
|
min={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 placeholder:text-gray-500"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
@@ -369,25 +369,25 @@ export default function AgentTypesPage() {
|
|||||||
id="isActive"
|
id="isActive"
|
||||||
checked={formData.isActive}
|
checked={formData.isActive}
|
||||||
onChange={(e) => setFormData({ ...formData, isActive: e.target.checked })}
|
onChange={(e) => setFormData({ ...formData, isActive: e.target.checked })}
|
||||||
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
className="rounded border-[#e5e7eb] text-[#f5a623] focus:ring-[#f5a623]"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="isActive" className="ml-2 text-sm text-gray-700">
|
<label htmlFor="isActive" className="ml-2 text-sm text-[#00293d] font-serif">
|
||||||
Active
|
Active
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
|
<div className="px-6 py-4 border-t border-[#e5e7eb] flex justify-end space-x-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={closeModal}
|
onClick={closeModal}
|
||||||
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
className="px-4 py-2 border border-[#e5e7eb] text-[#00293d] rounded-xl hover:bg-[#f5f9f8] transition-colors"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50"
|
className="px-4 py-2 bg-[#f5a623] text-white rounded-xl hover:bg-[#e09620] transition-colors disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isSubmitting ? 'Saving...' : modalType === 'create' ? 'Create' : 'Save Changes'}
|
{isSubmitting ? 'Saving...' : modalType === 'create' ? 'Create' : 'Save Changes'}
|
||||||
</button>
|
</button>
|
||||||
@@ -399,10 +399,10 @@ export default function AgentTypesPage() {
|
|||||||
|
|
||||||
{/* Delete Confirmation Modal */}
|
{/* Delete Confirmation Modal */}
|
||||||
{modalType === 'delete' && selectedType && (
|
{modalType === 'delete' && selectedType && (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
<div className="fixed inset-0 bg-black/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="bg-white rounded-xl shadow-xl max-w-md w-full mx-4">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<h3 className="text-lg font-semibold text-gray-900">Delete Agent Type</h3>
|
<h3 className="text-lg font-semibold text-[#00293d]">Delete Agent Type</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 py-4">
|
<div className="px-6 py-4">
|
||||||
{modalError && (
|
{modalError && (
|
||||||
@@ -410,7 +410,7 @@ export default function AgentTypesPage() {
|
|||||||
<p className="text-red-700 text-sm">{modalError}</p>
|
<p className="text-red-700 text-sm">{modalError}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<p className="text-gray-600">
|
<p className="text-[#666666] font-serif">
|
||||||
Are you sure you want to delete <span className="font-semibold">{selectedType.name}</span>?
|
Are you sure you want to delete <span className="font-semibold">{selectedType.name}</span>?
|
||||||
{selectedType._count?.agents && selectedType._count.agents > 0 && (
|
{selectedType._count?.agents && selectedType._count.agents > 0 && (
|
||||||
<span className="block mt-2 text-red-600 text-sm">
|
<span className="block mt-2 text-red-600 text-sm">
|
||||||
@@ -419,10 +419,10 @@ export default function AgentTypesPage() {
|
|||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
|
<div className="px-6 py-4 border-t border-[#e5e7eb] flex justify-end space-x-3">
|
||||||
<button
|
<button
|
||||||
onClick={closeModal}
|
onClick={closeModal}
|
||||||
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
className="px-4 py-2 border border-[#e5e7eb] text-[#00293d] rounded-xl hover:bg-[#f5f9f8] transition-colors"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ export default function DashboardLayout({
|
|||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex items-center justify-center bg-gray-100">
|
<div className="min-h-screen flex items-center justify-center bg-[#f5f9f8]">
|
||||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#f5a623]"></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -49,35 +49,35 @@ export default function DashboardLayout({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50">
|
<div className="min-h-screen bg-[#f5f9f8]">
|
||||||
{/* Sidebar */}
|
{/* Sidebar */}
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
|
|
||||||
{/* Main Content */}
|
{/* Main Content */}
|
||||||
<div className="ml-64">
|
<div className="ml-64">
|
||||||
{/* Top Header */}
|
{/* Top Header */}
|
||||||
<header className="bg-white border-b border-gray-200 sticky top-0 z-40">
|
<header className="bg-white border-b border-[#e5e7eb] sticky top-0 z-40">
|
||||||
<div className="px-8 py-3">
|
<div className="px-8 py-3">
|
||||||
<div className="flex justify-end items-center">
|
<div className="flex justify-end items-center">
|
||||||
{/* User Dropdown */}
|
{/* User Dropdown */}
|
||||||
<div className="relative" ref={dropdownRef}>
|
<div className="relative" ref={dropdownRef}>
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
|
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
|
||||||
className="flex items-center gap-3 py-2 px-3 rounded-xl hover:bg-gray-50 transition-all duration-200"
|
className="flex items-center gap-3 py-2 px-3 rounded-xl hover:bg-[#f5f9f8] transition-all duration-200"
|
||||||
>
|
>
|
||||||
<div className="w-9 h-9 bg-gradient-to-br from-blue-500 to-blue-600 rounded-full flex items-center justify-center shadow-sm">
|
<div className="w-9 h-9 bg-[#00293d] rounded-full flex items-center justify-center shadow-sm">
|
||||||
<span className="text-white font-semibold text-sm">
|
<span className="text-white font-semibold text-sm font-fractul">
|
||||||
{user?.firstName?.[0] || user?.email?.[0]?.toUpperCase() || 'A'}
|
{user?.firstName?.[0] || user?.email?.[0]?.toUpperCase() || 'A'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-left hidden sm:block">
|
<div className="text-left hidden sm:block">
|
||||||
<p className="text-sm font-semibold text-gray-800">
|
<p className="text-sm font-semibold text-[#00293d] font-fractul">
|
||||||
{user?.firstName || 'Admin'} {user?.lastName || ''}
|
{user?.firstName || 'Admin'} {user?.lastName || ''}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-gray-500">{user?.email}</p>
|
<p className="text-xs text-[#666666] font-serif">{user?.email}</p>
|
||||||
</div>
|
</div>
|
||||||
<svg
|
<svg
|
||||||
className={`w-4 h-4 text-gray-400 transition-transform duration-200 ${isDropdownOpen ? 'rotate-180' : ''}`}
|
className={`w-4 h-4 text-[#9ca3af] transition-transform duration-200 ${isDropdownOpen ? 'rotate-180' : ''}`}
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -88,19 +88,19 @@ export default function DashboardLayout({
|
|||||||
|
|
||||||
{/* Dropdown Menu */}
|
{/* Dropdown Menu */}
|
||||||
{isDropdownOpen && (
|
{isDropdownOpen && (
|
||||||
<div className="absolute right-0 mt-2 w-56 bg-white rounded-xl shadow-lg border border-gray-100 overflow-hidden z-50">
|
<div className="absolute right-0 mt-2 w-56 bg-white rounded-xl shadow-lg border border-[#e5e7eb] overflow-hidden z-50">
|
||||||
<div className="px-4 py-4 bg-gradient-to-br from-gray-50 to-white border-b border-gray-100">
|
<div className="px-4 py-4 bg-[#f5f9f8] border-b border-[#e5e7eb]">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="w-10 h-10 bg-gradient-to-br from-blue-500 to-blue-600 rounded-full flex items-center justify-center shadow-sm">
|
<div className="w-10 h-10 bg-[#00293d] rounded-full flex items-center justify-center shadow-sm">
|
||||||
<span className="text-white font-semibold">
|
<span className="text-white font-semibold font-fractul">
|
||||||
{user?.firstName?.[0] || user?.email?.[0]?.toUpperCase() || 'A'}
|
{user?.firstName?.[0] || user?.email?.[0]?.toUpperCase() || 'A'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-semibold text-gray-800">
|
<p className="text-sm font-semibold text-[#00293d] font-fractul">
|
||||||
{user?.firstName || 'Admin'} {user?.lastName || ''}
|
{user?.firstName || 'Admin'} {user?.lastName || ''}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-gray-500 truncate">{user?.email}</p>
|
<p className="text-xs text-[#666666] truncate font-serif">{user?.email}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+42
-42
@@ -57,7 +57,7 @@ export default function DashboardPage() {
|
|||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center py-12">
|
<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 className="animate-spin rounded-full h-8 w-8 border-b-2 border-[#f5a623]"></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -66,17 +66,17 @@ export default function DashboardPage() {
|
|||||||
<div>
|
<div>
|
||||||
{/* Page Title */}
|
{/* Page Title */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h1 className="text-2xl font-bold text-gray-900">Dashboard</h1>
|
<h1 className="text-2xl font-bold text-[#00293d] font-fractul">Dashboard</h1>
|
||||||
<p className="text-gray-500">Welcome to Re-Quest Admin Panel</p>
|
<p className="text-[#666666] font-serif">Welcome to Re-Quest Admin Panel</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Stats Cards */}
|
{/* Stats Cards */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
||||||
<div className="bg-white rounded-lg shadow p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb] p-6 card-hover">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="p-3 bg-blue-100 rounded-lg">
|
<div className="p-3 bg-[#e8f0ee] rounded-xl">
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6 text-blue-600"
|
className="w-6 h-6 text-[#5ba4a4]"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -90,14 +90,14 @@ export default function DashboardPage() {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-4">
|
<div className="ml-4">
|
||||||
<p className="text-sm font-medium text-gray-500">Total Users</p>
|
<p className="text-sm font-medium text-[#666666] font-serif">Total Users</p>
|
||||||
<p className="text-2xl font-bold text-gray-900">{stats.totalUsers}</p>
|
<p className="text-2xl font-bold text-[#00293d] font-fractul">{stats.totalUsers}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white rounded-lg shadow p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb] p-6 card-hover">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="p-3 bg-green-100 rounded-lg">
|
<div className="p-3 bg-green-50 rounded-xl">
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6 text-green-600"
|
className="w-6 h-6 text-green-600"
|
||||||
fill="none"
|
fill="none"
|
||||||
@@ -113,16 +113,16 @@ export default function DashboardPage() {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-4">
|
<div className="ml-4">
|
||||||
<p className="text-sm font-medium text-gray-500">Active</p>
|
<p className="text-sm font-medium text-[#666666] font-serif">Active</p>
|
||||||
<p className="text-2xl font-bold text-gray-900">{stats.activeUsers}</p>
|
<p className="text-2xl font-bold text-[#00293d] font-fractul">{stats.activeUsers}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white rounded-lg shadow p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb] p-6 card-hover">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="p-3 bg-purple-100 rounded-lg">
|
<div className="p-3 bg-[#fff7ed] rounded-xl">
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6 text-purple-600"
|
className="w-6 h-6 text-[#f5a623]"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -136,14 +136,14 @@ export default function DashboardPage() {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-4">
|
<div className="ml-4">
|
||||||
<p className="text-sm font-medium text-gray-500">Agents</p>
|
<p className="text-sm font-medium text-[#666666] font-serif">Agents</p>
|
||||||
<p className="text-2xl font-bold text-gray-900">{stats.agents}</p>
|
<p className="text-2xl font-bold text-[#00293d] font-fractul">{stats.agents}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white rounded-lg shadow p-6">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb] p-6 card-hover">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="p-3 bg-yellow-100 rounded-lg">
|
<div className="p-3 bg-yellow-50 rounded-xl">
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6 text-yellow-600"
|
className="w-6 h-6 text-yellow-600"
|
||||||
fill="none"
|
fill="none"
|
||||||
@@ -159,21 +159,21 @@ export default function DashboardPage() {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-4">
|
<div className="ml-4">
|
||||||
<p className="text-sm font-medium text-gray-500">Pending</p>
|
<p className="text-sm font-medium text-[#666666] font-serif">Pending</p>
|
||||||
<p className="text-2xl font-bold text-gray-900">{stats.pendingUsers}</p>
|
<p className="text-2xl font-bold text-[#00293d] font-fractul">{stats.pendingUsers}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Recent Users */}
|
{/* Recent Users */}
|
||||||
<div className="bg-white rounded-lg shadow">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb]">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<h2 className="text-lg font-semibold text-gray-900">Recent Users</h2>
|
<h2 className="text-lg font-semibold text-[#00293d] font-fractul">Recent Users</h2>
|
||||||
<Link
|
<Link
|
||||||
href="/dashboard/users"
|
href="/dashboard/users"
|
||||||
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
|
className="text-[#f5a623] hover:text-[#e09620] text-sm font-medium font-serif transition-colors"
|
||||||
>
|
>
|
||||||
View All →
|
View All →
|
||||||
</Link>
|
</Link>
|
||||||
@@ -183,7 +183,7 @@ export default function DashboardPage() {
|
|||||||
{recentUsers.length === 0 ? (
|
{recentUsers.length === 0 ? (
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<svg
|
<svg
|
||||||
className="mx-auto h-12 w-12 text-gray-400"
|
className="mx-auto h-12 w-12 text-[#9ca3af]"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -195,29 +195,29 @@ export default function DashboardPage() {
|
|||||||
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"
|
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p className="mt-2 text-gray-500">No users found</p>
|
<p className="mt-2 text-[#666666] font-serif">No users found</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<table className="min-w-full divide-y divide-gray-200">
|
<table className="min-w-full divide-y divide-[#e5e7eb]">
|
||||||
<thead className="bg-gray-50">
|
<thead className="bg-[#f5f9f8]">
|
||||||
<tr>
|
<tr>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider font-serif">
|
||||||
User
|
User
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider font-serif">
|
||||||
Role
|
Role
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider font-serif">
|
||||||
Status
|
Status
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider font-serif">
|
||||||
Joined
|
Joined
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="bg-white divide-y divide-gray-200">
|
<tbody className="bg-white divide-y divide-[#e5e7eb]">
|
||||||
{recentUsers.map((user) => (
|
{recentUsers.map((user) => (
|
||||||
<tr key={user.id} className="hover:bg-gray-50">
|
<tr key={user.id} className="hover:bg-[#f5f9f8] transition-colors">
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="flex-shrink-0 h-10 w-10">
|
<div className="flex-shrink-0 h-10 w-10">
|
||||||
@@ -228,18 +228,18 @@ export default function DashboardPage() {
|
|||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="h-10 w-10 rounded-full bg-gray-200 flex items-center justify-center">
|
<div className="h-10 w-10 rounded-full bg-[#e8f0ee] flex items-center justify-center">
|
||||||
<span className="text-gray-500 font-medium text-sm">
|
<span className="text-[#00293d] font-medium text-sm font-fractul">
|
||||||
{user.profile?.firstName?.[0] || user.email[0].toUpperCase()}
|
{user.profile?.firstName?.[0] || user.email[0].toUpperCase()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-4">
|
<div className="ml-4">
|
||||||
<div className="text-sm font-medium text-gray-900">
|
<div className="text-sm font-medium text-[#00293d] font-serif">
|
||||||
{user.profile?.firstName} {user.profile?.lastName}
|
{user.profile?.firstName} {user.profile?.lastName}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-gray-500">{user.email}</div>
|
<div className="text-sm text-[#666666]">{user.email}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -249,8 +249,8 @@ export default function DashboardPage() {
|
|||||||
user.role === 'ADMIN'
|
user.role === 'ADMIN'
|
||||||
? 'bg-red-100 text-red-800'
|
? 'bg-red-100 text-red-800'
|
||||||
: user.role === 'AGENT'
|
: user.role === 'AGENT'
|
||||||
? 'bg-purple-100 text-purple-800'
|
? 'bg-[#fff7ed] text-[#f5a623]'
|
||||||
: 'bg-blue-100 text-blue-800'
|
: 'bg-[#e8f0ee] text-[#5ba4a4]'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{user.role}
|
{user.role}
|
||||||
@@ -271,7 +271,7 @@ export default function DashboardPage() {
|
|||||||
{user.status === 'PENDING_VERIFICATION' ? 'PENDING' : user.status}
|
{user.status === 'PENDING_VERIFICATION' ? 'PENDING' : user.status}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-[#666666] font-serif">
|
||||||
{new Date(user.createdAt).toLocaleDateString()}
|
{new Date(user.createdAt).toLocaleDateString()}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ export default function SectionDetailPage() {
|
|||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center py-12">
|
<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 className="animate-spin rounded-full h-8 w-8 border-b-2 border-[#f5a623]"></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -307,8 +307,8 @@ export default function SectionDetailPage() {
|
|||||||
if (!section) {
|
if (!section) {
|
||||||
return (
|
return (
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<p className="text-gray-500">Section not found</p>
|
<p className="text-[#666666] font-serif">Section not found</p>
|
||||||
<Link href="/dashboard/profile-sections" className="mt-4 text-blue-600 hover:underline">
|
<Link href="/dashboard/profile-sections" className="mt-4 text-[#f5a623] hover:underline">
|
||||||
Back to sections
|
Back to sections
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -323,7 +323,7 @@ export default function SectionDetailPage() {
|
|||||||
<div>
|
<div>
|
||||||
{/* Breadcrumb */}
|
{/* Breadcrumb */}
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<Link href="/dashboard/profile-sections" className="text-blue-600 hover:underline text-sm">
|
<Link href="/dashboard/profile-sections" className="text-[#f5a623] hover:underline text-sm">
|
||||||
← Back to Profile Sections
|
← Back to Profile Sections
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -333,24 +333,24 @@ export default function SectionDetailPage() {
|
|||||||
<div>
|
<div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
{section.icon && <span className="text-2xl mr-2">{section.icon}</span>}
|
{section.icon && <span className="text-2xl mr-2">{section.icon}</span>}
|
||||||
<h1 className="text-2xl font-bold text-gray-900">{section.name}</h1>
|
<h1 className="text-2xl font-bold text-[#00293d] font-fractul">{section.name}</h1>
|
||||||
{section.isSystem && (
|
{section.isSystem && (
|
||||||
<span className="ml-3 px-2 py-1 text-xs font-semibold rounded-full bg-amber-100 text-amber-800">
|
<span className="ml-3 px-2 py-1 text-xs font-semibold rounded-full bg-amber-100 text-amber-800">
|
||||||
System
|
System
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{section.isGlobal && (
|
{section.isGlobal && (
|
||||||
<span className="ml-3 px-2 py-1 text-xs font-semibold rounded-full bg-purple-100 text-purple-800">
|
<span className="ml-3 px-2 py-1 text-xs font-semibold rounded-full bg-[#fff7ed] text-[#f5a623]">
|
||||||
Global
|
Global
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-gray-500 mt-1">{section.description || 'No description'}</p>
|
<p className="text-[#666666] font-serif mt-1">{section.description || 'No description'}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex space-x-3">
|
<div className="flex space-x-3">
|
||||||
<button
|
<button
|
||||||
onClick={fetchData}
|
onClick={fetchData}
|
||||||
className="px-4 py-2 border border-gray-300 hover:bg-gray-50 text-gray-700 text-sm font-medium rounded-lg transition-colors"
|
className="px-4 py-2 border border-[#e5e7eb] hover:bg-[#f5f9f8] text-[#00293d] text-sm font-medium rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
Refresh
|
Refresh
|
||||||
</button>
|
</button>
|
||||||
@@ -366,12 +366,12 @@ export default function SectionDetailPage() {
|
|||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||||
{/* Fields Section */}
|
{/* Fields Section */}
|
||||||
<div className="lg:col-span-2">
|
<div className="lg:col-span-2">
|
||||||
<div className="bg-white rounded-lg shadow">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb]">
|
||||||
<div className="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
|
<div className="px-6 py-4 border-b border-[#e5e7eb] flex justify-between items-center">
|
||||||
<h2 className="text-lg font-semibold text-gray-900">Fields ({fields.length})</h2>
|
<h2 className="text-lg font-semibold text-[#00293d] font-fractul">Fields ({fields.length})</h2>
|
||||||
<button
|
<button
|
||||||
onClick={openCreateFieldModal}
|
onClick={openCreateFieldModal}
|
||||||
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"
|
className="px-4 py-2 bg-[#f5a623] hover:bg-[#e09620] 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">
|
<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" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
|
||||||
@@ -380,28 +380,28 @@ export default function SectionDetailPage() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="divide-y divide-gray-200">
|
<div className="divide-y divide-[#e5e7eb]">
|
||||||
{fields.length === 0 ? (
|
{fields.length === 0 ? (
|
||||||
<div className="text-center py-12">
|
<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">
|
<svg className="mx-auto h-12 w-12 text-[#9ca3af]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||||
</svg>
|
</svg>
|
||||||
<p className="mt-2 text-gray-500">No fields defined yet</p>
|
<p className="mt-2 text-[#666666] font-serif">No fields defined yet</p>
|
||||||
<button
|
<button
|
||||||
onClick={openCreateFieldModal}
|
onClick={openCreateFieldModal}
|
||||||
className="mt-4 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors"
|
className="mt-4 px-4 py-2 bg-[#f5a623] hover:bg-[#e09620] text-white text-sm font-medium rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
Add First Field
|
Add First Field
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
fields.map((field, index) => (
|
fields.map((field, index) => (
|
||||||
<div key={field.id} className="px-6 py-4 hover:bg-gray-50">
|
<div key={field.id} className="px-6 py-4 hover:bg-[#f5f9f8]">
|
||||||
<div className="flex justify-between items-start">
|
<div className="flex justify-between items-start">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="flex items-center flex-wrap gap-2">
|
<div className="flex items-center flex-wrap gap-2">
|
||||||
<span className="text-gray-400 mr-1 text-sm">#{index + 1}</span>
|
<span className="text-[#9ca3af] mr-1 text-sm">#{index + 1}</span>
|
||||||
<span className="font-medium text-gray-900">{field.name}</span>
|
<span className="font-medium text-[#00293d]">{field.name}</span>
|
||||||
{field.isRequired && (
|
{field.isRequired && (
|
||||||
<span className="text-red-500 text-xs">*required</span>
|
<span className="text-red-500 text-xs">*required</span>
|
||||||
)}
|
)}
|
||||||
@@ -412,12 +412,12 @@ export default function SectionDetailPage() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 flex items-center space-x-3 text-sm">
|
<div className="mt-1 flex items-center space-x-3 text-sm">
|
||||||
<span className="px-2 py-0.5 bg-gray-100 text-gray-600 rounded">
|
<span className="px-2 py-0.5 bg-[#e8f0ee] text-[#666666] rounded">
|
||||||
{getFieldTypeLabel(field.fieldType)}
|
{getFieldTypeLabel(field.fieldType)}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-gray-400">{field.slug}</span>
|
<span className="text-[#9ca3af]">{field.slug}</span>
|
||||||
{field.placeholder && (
|
{field.placeholder && (
|
||||||
<span className="text-gray-400 truncate max-w-xs">
|
<span className="text-[#9ca3af] truncate max-w-xs">
|
||||||
placeholder: {field.placeholder}
|
placeholder: {field.placeholder}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -425,12 +425,12 @@ export default function SectionDetailPage() {
|
|||||||
{field.options && field.options.length > 0 && (
|
{field.options && field.options.length > 0 && (
|
||||||
<div className="mt-2 flex flex-wrap gap-1">
|
<div className="mt-2 flex flex-wrap gap-1">
|
||||||
{(field.options as FieldOption[]).slice(0, 5).map((opt, i) => (
|
{(field.options as FieldOption[]).slice(0, 5).map((opt, i) => (
|
||||||
<span key={i} className="px-2 py-0.5 bg-blue-50 text-blue-700 text-xs rounded">
|
<span key={i} className="px-2 py-0.5 bg-[#e8f0ee] text-[#5ba4a4] text-xs rounded">
|
||||||
{opt.label}
|
{opt.label}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
{field.options.length > 5 && (
|
{field.options.length > 5 && (
|
||||||
<span className="px-2 py-0.5 bg-gray-100 text-gray-500 text-xs rounded">
|
<span className="px-2 py-0.5 bg-[#e8f0ee] text-[#666666] text-xs rounded">
|
||||||
+{field.options.length - 5} more
|
+{field.options.length - 5} more
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -450,7 +450,7 @@ export default function SectionDetailPage() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => openEditFieldModal(field)}
|
onClick={() => openEditFieldModal(field)}
|
||||||
className="p-1 text-gray-400 hover:text-blue-600"
|
className="p-1 text-[#9ca3af] hover:text-[#f5a623]"
|
||||||
>
|
>
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||||
@@ -458,7 +458,7 @@ export default function SectionDetailPage() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => openDeleteFieldModal(field)}
|
onClick={() => openDeleteFieldModal(field)}
|
||||||
className="p-1 text-gray-400 hover:text-red-600"
|
className="p-1 text-[#9ca3af] hover:text-red-600"
|
||||||
>
|
>
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||||
@@ -475,13 +475,13 @@ export default function SectionDetailPage() {
|
|||||||
|
|
||||||
{/* Agent Type Assignments */}
|
{/* Agent Type Assignments */}
|
||||||
<div className="lg:col-span-1">
|
<div className="lg:col-span-1">
|
||||||
<div className="bg-white rounded-lg shadow">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb]">
|
||||||
<div className="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
|
<div className="px-6 py-4 border-b border-[#e5e7eb] flex justify-between items-center">
|
||||||
<h2 className="text-lg font-semibold text-gray-900">Agent Types</h2>
|
<h2 className="text-lg font-semibold text-[#00293d] font-fractul">Agent Types</h2>
|
||||||
{availableAgentTypes.length > 0 && (
|
{availableAgentTypes.length > 0 && (
|
||||||
<button
|
<button
|
||||||
onClick={openAssignModal}
|
onClick={openAssignModal}
|
||||||
className="px-3 py-1.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors"
|
className="px-3 py-1.5 bg-[#f5a623] hover:bg-[#e09620] text-white text-sm font-medium rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
Assign
|
Assign
|
||||||
</button>
|
</button>
|
||||||
@@ -489,10 +489,10 @@ export default function SectionDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
{/* Global toggle */}
|
{/* Global toggle */}
|
||||||
<div className="flex items-center justify-between p-3 bg-gray-50 rounded-lg mb-4">
|
<div className="flex items-center justify-between p-3 bg-[#f5f9f8] rounded-xl mb-4">
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium text-gray-900">Available to all agent types</p>
|
<p className="font-medium text-[#00293d]">Available to all agent types</p>
|
||||||
<p className="text-xs text-gray-500">
|
<p className="text-xs text-[#666666]">
|
||||||
{section.isGlobal
|
{section.isGlobal
|
||||||
? 'This section appears for all agent types by default'
|
? 'This section appears for all agent types by default'
|
||||||
: 'Only assigned agent types will see this section'}
|
: 'Only assigned agent types will see this section'}
|
||||||
@@ -500,8 +500,8 @@ export default function SectionDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleToggleGlobal(!section.isGlobal)}
|
onClick={() => handleToggleGlobal(!section.isGlobal)}
|
||||||
className={`relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 ${
|
className={`relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-[#5ba4a4] focus:ring-offset-2 ${
|
||||||
section.isGlobal ? 'bg-purple-600' : 'bg-gray-200'
|
section.isGlobal ? 'bg-[#5ba4a4]' : 'bg-[#e8f0ee]'
|
||||||
}`}
|
}`}
|
||||||
role="switch"
|
role="switch"
|
||||||
aria-checked={section.isGlobal}
|
aria-checked={section.isGlobal}
|
||||||
@@ -517,7 +517,7 @@ export default function SectionDetailPage() {
|
|||||||
{/* Specific agent type assignments */}
|
{/* Specific agent type assignments */}
|
||||||
{section.agentTypeSections && section.agentTypeSections.length > 0 ? (
|
{section.agentTypeSections && section.agentTypeSections.length > 0 ? (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<p className="text-xs text-gray-500 font-medium uppercase tracking-wide mb-2">
|
<p className="text-xs text-[#666666] font-medium uppercase tracking-wide mb-2">
|
||||||
Specific Assignments
|
Specific Assignments
|
||||||
</p>
|
</p>
|
||||||
{section.agentTypeSections.map((ats) => {
|
{section.agentTypeSections.map((ats) => {
|
||||||
@@ -525,17 +525,17 @@ export default function SectionDetailPage() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={ats.id}
|
key={ats.id}
|
||||||
className="flex items-center justify-between p-3 bg-gray-50 rounded-lg"
|
className="flex items-center justify-between p-3 bg-[#f5f9f8] rounded-xl"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium text-gray-900">{agentType?.name || 'Unknown'}</p>
|
<p className="font-medium text-[#00293d]">{agentType?.name || 'Unknown'}</p>
|
||||||
<p className="text-xs text-gray-500">
|
<p className="text-xs text-[#666666]">
|
||||||
{ats.isRequired ? 'Required' : 'Optional'} • Order: {ats.sortOrder}
|
{ats.isRequired ? 'Required' : 'Optional'} • Order: {ats.sortOrder}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleRemoveAssignment(ats.agentTypeId)}
|
onClick={() => handleRemoveAssignment(ats.agentTypeId)}
|
||||||
className="p-1 text-gray-400 hover:text-red-600"
|
className="p-1 text-[#9ca3af] hover:text-red-600"
|
||||||
title="Remove assignment"
|
title="Remove assignment"
|
||||||
>
|
>
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -548,7 +548,7 @@ export default function SectionDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-center py-4">
|
<div className="text-center py-4">
|
||||||
<p className="text-gray-500 text-sm">
|
<p className="text-[#666666] text-sm font-serif">
|
||||||
{section.isGlobal
|
{section.isGlobal
|
||||||
? 'No specific agent type configurations yet'
|
? 'No specific agent type configurations yet'
|
||||||
: 'Not assigned to any agent type'}
|
: 'Not assigned to any agent type'}
|
||||||
@@ -556,7 +556,7 @@ export default function SectionDetailPage() {
|
|||||||
{availableAgentTypes.length > 0 && (
|
{availableAgentTypes.length > 0 && (
|
||||||
<button
|
<button
|
||||||
onClick={openAssignModal}
|
onClick={openAssignModal}
|
||||||
className="mt-3 text-blue-600 hover:underline text-sm"
|
className="mt-3 text-[#f5a623] hover:underline text-sm"
|
||||||
>
|
>
|
||||||
{section.isGlobal ? 'Add specific configuration' : 'Assign to agent type'}
|
{section.isGlobal ? 'Add specific configuration' : 'Assign to agent type'}
|
||||||
</button>
|
</button>
|
||||||
@@ -571,9 +571,9 @@ export default function SectionDetailPage() {
|
|||||||
{/* Field Create/Edit Modal */}
|
{/* Field Create/Edit Modal */}
|
||||||
{(fieldModalType === 'create' || fieldModalType === 'edit') && (
|
{(fieldModalType === 'create' || fieldModalType === 'edit') && (
|
||||||
<div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50 overflow-y-auto">
|
<div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50 overflow-y-auto">
|
||||||
<div className="bg-white rounded-lg shadow-xl max-w-2xl w-full mx-4 my-8">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb]-xl max-w-2xl w-full mx-4 my-8">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<h3 className="text-lg font-semibold text-gray-900">
|
<h3 className="text-lg font-semibold text-[#00293d] font-fractul">
|
||||||
{fieldModalType === 'create' ? 'Create Field' : 'Edit Field'}
|
{fieldModalType === 'create' ? 'Create Field' : 'Edit Field'}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -587,25 +587,25 @@ export default function SectionDetailPage() {
|
|||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Name <span className="text-red-500">*</span>
|
Name <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={fieldForm.name}
|
value={fieldForm.name}
|
||||||
onChange={(e) => setFieldForm({ ...fieldForm, name: e.target.value })}
|
onChange={(e) => setFieldForm({ ...fieldForm, 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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Field Type <span className="text-red-500">*</span>
|
Field Type <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
value={fieldForm.fieldType}
|
value={fieldForm.fieldType}
|
||||||
onChange={(e) => setFieldForm({ ...fieldForm, fieldType: e.target.value as FieldType })}
|
onChange={(e) => setFieldForm({ ...fieldForm, fieldType: e.target.value as FieldType })}
|
||||||
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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white"
|
||||||
>
|
>
|
||||||
{FIELD_TYPES.map((ft) => (
|
{FIELD_TYPES.map((ft) => (
|
||||||
<option key={ft.value} value={ft.value}>
|
<option key={ft.value} value={ft.value}>
|
||||||
@@ -617,46 +617,46 @@ export default function SectionDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Description
|
Description
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={fieldForm.description}
|
value={fieldForm.description}
|
||||||
onChange={(e) => setFieldForm({ ...fieldForm, description: e.target.value })}
|
onChange={(e) => setFieldForm({ ...fieldForm, description: 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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
placeholder="Help text for this field"
|
placeholder="Help text for this field"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Placeholder
|
Placeholder
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={fieldForm.placeholder}
|
value={fieldForm.placeholder}
|
||||||
onChange={(e) => setFieldForm({ ...fieldForm, placeholder: e.target.value })}
|
onChange={(e) => setFieldForm({ ...fieldForm, placeholder: 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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Default Value
|
Default Value
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={fieldForm.defaultValue}
|
value={fieldForm.defaultValue}
|
||||||
onChange={(e) => setFieldForm({ ...fieldForm, defaultValue: e.target.value })}
|
onChange={(e) => setFieldForm({ ...fieldForm, defaultValue: 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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Sort Order
|
Sort Order
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -666,7 +666,7 @@ export default function SectionDetailPage() {
|
|||||||
onFocus={(e) => e.target.select()}
|
onFocus={(e) => e.target.select()}
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
min={0}
|
min={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 placeholder:text-gray-500"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-6 pt-6">
|
<div className="flex items-center space-x-6 pt-6">
|
||||||
@@ -676,9 +676,9 @@ export default function SectionDetailPage() {
|
|||||||
id="fieldIsActive"
|
id="fieldIsActive"
|
||||||
checked={fieldForm.isActive}
|
checked={fieldForm.isActive}
|
||||||
onChange={(e) => setFieldForm({ ...fieldForm, isActive: e.target.checked })}
|
onChange={(e) => setFieldForm({ ...fieldForm, isActive: e.target.checked })}
|
||||||
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
className="rounded border-[#e5e7eb] text-[#f5a623] focus:ring-[#f5a623]"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="fieldIsActive" className="ml-2 text-sm text-gray-700">
|
<label htmlFor="fieldIsActive" className="ml-2 text-sm text-[#00293d] font-serif">
|
||||||
Active
|
Active
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -688,9 +688,9 @@ export default function SectionDetailPage() {
|
|||||||
id="fieldIsRequired"
|
id="fieldIsRequired"
|
||||||
checked={fieldForm.isRequired}
|
checked={fieldForm.isRequired}
|
||||||
onChange={(e) => setFieldForm({ ...fieldForm, isRequired: e.target.checked })}
|
onChange={(e) => setFieldForm({ ...fieldForm, isRequired: e.target.checked })}
|
||||||
className="rounded border-gray-300 text-red-600 focus:ring-red-500"
|
className="rounded border-[#e5e7eb] text-red-600 focus:ring-red-500"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="fieldIsRequired" className="ml-2 text-sm text-gray-700">
|
<label htmlFor="fieldIsRequired" className="ml-2 text-sm text-[#00293d] font-serif">
|
||||||
Required
|
Required
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -701,10 +701,10 @@ export default function SectionDetailPage() {
|
|||||||
<div className="border border-amber-200 rounded-lg p-4 bg-amber-50">
|
<div className="border border-amber-200 rounded-lg p-4 bg-amber-50">
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<label htmlFor="fieldIsSearchableOnly" className="text-sm font-medium text-gray-700">
|
<label htmlFor="fieldIsSearchableOnly" className="text-sm font-medium text-[#00293d]">
|
||||||
Search Only (Hidden from Public Profile)
|
Search Only (Hidden from Public Profile)
|
||||||
</label>
|
</label>
|
||||||
<p className="text-xs text-gray-500 mt-1">
|
<p className="text-xs text-[#666666] font-serif mt-1">
|
||||||
This field will be shown in the agent edit form and used for search filtering,
|
This field will be shown in the agent edit form and used for search filtering,
|
||||||
but will NOT be visible on the public agent profile page.
|
but will NOT be visible on the public agent profile page.
|
||||||
</p>
|
</p>
|
||||||
@@ -714,15 +714,15 @@ export default function SectionDetailPage() {
|
|||||||
id="fieldIsSearchableOnly"
|
id="fieldIsSearchableOnly"
|
||||||
checked={fieldForm.isSearchableOnly}
|
checked={fieldForm.isSearchableOnly}
|
||||||
onChange={(e) => setFieldForm({ ...fieldForm, isSearchableOnly: e.target.checked })}
|
onChange={(e) => setFieldForm({ ...fieldForm, isSearchableOnly: e.target.checked })}
|
||||||
className="mt-1 rounded border-gray-300 text-amber-600 focus:ring-amber-500"
|
className="mt-1 rounded border-[#e5e7eb] text-amber-600 focus:ring-amber-500"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Options Editor for SELECT, RADIO, MULTI_SELECT, CHECKBOX_GROUP */}
|
{/* Options Editor for SELECT, RADIO, MULTI_SELECT, CHECKBOX_GROUP */}
|
||||||
{REQUIRES_OPTIONS.includes(fieldForm.fieldType) && (
|
{REQUIRES_OPTIONS.includes(fieldForm.fieldType) && (
|
||||||
<div className="border border-gray-200 rounded-lg p-4">
|
<div className="border border-[#e5e7eb] rounded-xl p-4">
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-3">
|
<label className="block text-sm font-medium text-[#00293d] mb-3">
|
||||||
Options
|
Options
|
||||||
</label>
|
</label>
|
||||||
<div className="flex space-x-2 mb-3">
|
<div className="flex space-x-2 mb-3">
|
||||||
@@ -731,19 +731,19 @@ export default function SectionDetailPage() {
|
|||||||
value={optionInput.value}
|
value={optionInput.value}
|
||||||
onChange={(e) => setOptionInput({ ...optionInput, value: e.target.value })}
|
onChange={(e) => setOptionInput({ ...optionInput, value: e.target.value })}
|
||||||
placeholder="Value"
|
placeholder="Value"
|
||||||
className="flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm text-gray-900 bg-white placeholder:text-gray-500"
|
className="flex-1 px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-sm text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={optionInput.label}
|
value={optionInput.label}
|
||||||
onChange={(e) => setOptionInput({ ...optionInput, label: e.target.value })}
|
onChange={(e) => setOptionInput({ ...optionInput, label: e.target.value })}
|
||||||
placeholder="Label"
|
placeholder="Label"
|
||||||
className="flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm text-gray-900 bg-white placeholder:text-gray-500"
|
className="flex-1 px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-sm text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={addOption}
|
onClick={addOption}
|
||||||
className="px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 text-sm font-medium rounded-lg transition-colors"
|
className="px-4 py-2 bg-[#e8f0ee] hover:bg-[#d5e5e1] text-[#00293d] text-sm font-medium rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
Add
|
Add
|
||||||
</button>
|
</button>
|
||||||
@@ -753,11 +753,11 @@ export default function SectionDetailPage() {
|
|||||||
{fieldForm.options.map((opt, index) => (
|
{fieldForm.options.map((opt, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="flex items-center justify-between px-3 py-2 bg-gray-50 rounded"
|
className="flex items-center justify-between px-3 py-2 bg-[#f5f9f8] rounded"
|
||||||
>
|
>
|
||||||
<span className="text-sm">
|
<span className="text-sm">
|
||||||
<span className="font-medium text-gray-900">{opt.label}</span>
|
<span className="font-medium text-[#00293d]">{opt.label}</span>
|
||||||
<span className="text-xs text-gray-400 ml-2">({opt.value})</span>
|
<span className="text-xs text-[#9ca3af] ml-2">({opt.value})</span>
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -777,68 +777,68 @@ export default function SectionDetailPage() {
|
|||||||
|
|
||||||
{/* Range Config for RANGE type */}
|
{/* Range Config for RANGE type */}
|
||||||
{fieldForm.fieldType === 'RANGE' && (
|
{fieldForm.fieldType === 'RANGE' && (
|
||||||
<div className="border border-gray-200 rounded-lg p-4">
|
<div className="border border-[#e5e7eb] rounded-xl p-4">
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-3">
|
<label className="block text-sm font-medium text-[#00293d] mb-3">
|
||||||
Range Configuration
|
Range Configuration
|
||||||
</label>
|
</label>
|
||||||
<div className="grid grid-cols-4 gap-3">
|
<div className="grid grid-cols-4 gap-3">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-xs text-gray-500 mb-1">Min</label>
|
<label className="block text-xs text-[#666666] mb-1">Min</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
value={fieldForm.rangeConfig?.min || 0}
|
value={fieldForm.rangeConfig?.min || 0}
|
||||||
onChange={(e) => updateRangeConfig('min', e.target.value)}
|
onChange={(e) => updateRangeConfig('min', e.target.value)}
|
||||||
onFocus={(e) => e.target.select()}
|
onFocus={(e) => e.target.select()}
|
||||||
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-sm text-gray-900 bg-white"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-sm text-[#00293d] bg-white"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-xs text-gray-500 mb-1">Max</label>
|
<label className="block text-xs text-[#666666] mb-1">Max</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
value={fieldForm.rangeConfig?.max || 100}
|
value={fieldForm.rangeConfig?.max || 100}
|
||||||
onChange={(e) => updateRangeConfig('max', e.target.value)}
|
onChange={(e) => updateRangeConfig('max', e.target.value)}
|
||||||
onFocus={(e) => e.target.select()}
|
onFocus={(e) => e.target.select()}
|
||||||
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-sm text-gray-900 bg-white"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-sm text-[#00293d] bg-white"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-xs text-gray-500 mb-1">Step</label>
|
<label className="block text-xs text-[#666666] mb-1">Step</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
value={fieldForm.rangeConfig?.step || 1}
|
value={fieldForm.rangeConfig?.step || 1}
|
||||||
onChange={(e) => updateRangeConfig('step', e.target.value)}
|
onChange={(e) => updateRangeConfig('step', e.target.value)}
|
||||||
onFocus={(e) => e.target.select()}
|
onFocus={(e) => e.target.select()}
|
||||||
min={1}
|
min={1}
|
||||||
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-sm text-gray-900 bg-white"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-sm text-[#00293d] bg-white"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-xs text-gray-500 mb-1">Unit</label>
|
<label className="block text-xs text-[#666666] mb-1">Unit</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={fieldForm.rangeConfig?.unit || ''}
|
value={fieldForm.rangeConfig?.unit || ''}
|
||||||
onChange={(e) => updateRangeConfig('unit', e.target.value)}
|
onChange={(e) => updateRangeConfig('unit', e.target.value)}
|
||||||
placeholder="e.g., years"
|
placeholder="e.g., years"
|
||||||
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-sm text-gray-900 bg-white placeholder:text-gray-500"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-sm text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
|
<div className="px-6 py-4 border-t border-[#e5e7eb] flex justify-end space-x-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={closeFieldModal}
|
onClick={closeFieldModal}
|
||||||
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
className="px-4 py-2 border border-[#e5e7eb] text-[#00293d] rounded-xl hover:bg-[#f5f9f8] transition-colors"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50"
|
className="px-4 py-2 bg-[#f5a623] text-white rounded-xl hover:bg-[#e09620] transition-colors disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isSubmitting ? 'Saving...' : fieldModalType === 'create' ? 'Create Field' : 'Save Changes'}
|
{isSubmitting ? 'Saving...' : fieldModalType === 'create' ? 'Create Field' : 'Save Changes'}
|
||||||
</button>
|
</button>
|
||||||
@@ -851,9 +851,9 @@ export default function SectionDetailPage() {
|
|||||||
{/* Field Delete Modal */}
|
{/* Field Delete Modal */}
|
||||||
{fieldModalType === 'delete' && selectedField && (
|
{fieldModalType === 'delete' && selectedField && (
|
||||||
<div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50">
|
<div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50">
|
||||||
<div className="bg-white rounded-lg shadow-xl max-w-md w-full mx-4">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb]-xl max-w-md w-full mx-4">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<h3 className="text-lg font-semibold text-gray-900">Delete Field</h3>
|
<h3 className="text-lg font-semibold text-[#00293d] font-fractul">Delete Field</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 py-4">
|
<div className="px-6 py-4">
|
||||||
{modalError && (
|
{modalError && (
|
||||||
@@ -861,14 +861,14 @@ export default function SectionDetailPage() {
|
|||||||
<p className="text-red-700 text-sm">{modalError}</p>
|
<p className="text-red-700 text-sm">{modalError}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<p className="text-gray-600">
|
<p className="text-[#666666] font-serif">
|
||||||
Are you sure you want to delete the field <span className="font-semibold">{selectedField.name}</span>?
|
Are you sure you want to delete the field <span className="font-semibold">{selectedField.name}</span>?
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
|
<div className="px-6 py-4 border-t border-[#e5e7eb] flex justify-end space-x-3">
|
||||||
<button
|
<button
|
||||||
onClick={closeFieldModal}
|
onClick={closeFieldModal}
|
||||||
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
className="px-4 py-2 border border-[#e5e7eb] text-[#00293d] rounded-xl hover:bg-[#f5f9f8] transition-colors"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
@@ -887,9 +887,9 @@ export default function SectionDetailPage() {
|
|||||||
{/* Assign to Agent Type Modal */}
|
{/* Assign to Agent Type Modal */}
|
||||||
{assignModalType === 'assign' && (
|
{assignModalType === 'assign' && (
|
||||||
<div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50">
|
<div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50">
|
||||||
<div className="bg-white rounded-lg shadow-xl max-w-md w-full mx-4">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb]-xl max-w-md w-full mx-4">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<h3 className="text-lg font-semibold text-gray-900">Assign to Agent Type</h3>
|
<h3 className="text-lg font-semibold text-[#00293d] font-fractul">Assign to Agent Type</h3>
|
||||||
</div>
|
</div>
|
||||||
<form onSubmit={handleAssign}>
|
<form onSubmit={handleAssign}>
|
||||||
<div className="px-6 py-4 space-y-4">
|
<div className="px-6 py-4 space-y-4">
|
||||||
@@ -899,13 +899,13 @@ export default function SectionDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Agent Type <span className="text-red-500">*</span>
|
Agent Type <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
value={assignForm.agentTypeId}
|
value={assignForm.agentTypeId}
|
||||||
onChange={(e) => setAssignForm({ ...assignForm, agentTypeId: e.target.value })}
|
onChange={(e) => setAssignForm({ ...assignForm, agentTypeId: 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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white"
|
||||||
required
|
required
|
||||||
>
|
>
|
||||||
<option value="">Select agent type...</option>
|
<option value="">Select agent type...</option>
|
||||||
@@ -917,7 +917,7 @@ export default function SectionDetailPage() {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Sort Order
|
Sort Order
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -927,7 +927,7 @@ export default function SectionDetailPage() {
|
|||||||
onFocus={(e) => e.target.select()}
|
onFocus={(e) => e.target.select()}
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
min={0}
|
min={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 placeholder:text-gray-500"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
@@ -936,25 +936,25 @@ export default function SectionDetailPage() {
|
|||||||
id="assignIsRequired"
|
id="assignIsRequired"
|
||||||
checked={assignForm.isRequired}
|
checked={assignForm.isRequired}
|
||||||
onChange={(e) => setAssignForm({ ...assignForm, isRequired: e.target.checked })}
|
onChange={(e) => setAssignForm({ ...assignForm, isRequired: e.target.checked })}
|
||||||
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
className="rounded border-[#e5e7eb] text-[#f5a623] focus:ring-[#f5a623]"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="assignIsRequired" className="ml-2 text-sm text-gray-700">
|
<label htmlFor="assignIsRequired" className="ml-2 text-sm text-[#00293d] font-serif">
|
||||||
Required section for this agent type
|
Required section for this agent type
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
|
<div className="px-6 py-4 border-t border-[#e5e7eb] flex justify-end space-x-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={closeAssignModal}
|
onClick={closeAssignModal}
|
||||||
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
className="px-4 py-2 border border-[#e5e7eb] text-[#00293d] rounded-xl hover:bg-[#f5f9f8] transition-colors"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isSubmitting || !assignForm.agentTypeId}
|
disabled={isSubmitting || !assignForm.agentTypeId}
|
||||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50"
|
className="px-4 py-2 bg-[#f5a623] text-white rounded-xl hover:bg-[#e09620] transition-colors disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isSubmitting ? 'Assigning...' : 'Assign'}
|
{isSubmitting ? 'Assigning...' : 'Assign'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -159,21 +159,21 @@ export default function ProfileSectionsPage() {
|
|||||||
<div>
|
<div>
|
||||||
{/* Page Title */}
|
{/* Page Title */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h1 className="text-2xl font-bold text-gray-900">Profile Sections</h1>
|
<h1 className="text-2xl font-bold text-[#00293d] font-fractul">Profile Sections</h1>
|
||||||
<p className="text-gray-500">Manage profile sections and their fields for agent types</p>
|
<p className="text-[#666666] font-serif">Manage profile sections and their fields for agent types</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Sections Table */}
|
{/* Sections Table */}
|
||||||
<div className="bg-white rounded-lg shadow">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb]">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
<label className="flex items-center space-x-2 text-sm text-gray-600">
|
<label className="flex items-center space-x-2 text-sm text-[#666666] font-serif">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={showInactive}
|
checked={showInactive}
|
||||||
onChange={(e) => setShowInactive(e.target.checked)}
|
onChange={(e) => setShowInactive(e.target.checked)}
|
||||||
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
className="rounded border-[#e5e7eb] text-[#f5a623] focus:ring-[#f5a623]"
|
||||||
/>
|
/>
|
||||||
<span>Show Inactive</span>
|
<span>Show Inactive</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -181,7 +181,7 @@ export default function ProfileSectionsPage() {
|
|||||||
<div className="flex space-x-3">
|
<div className="flex space-x-3">
|
||||||
<button
|
<button
|
||||||
onClick={fetchSections}
|
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"
|
className="px-4 py-2 border border-[#e5e7eb] hover:bg-[#f5f9f8] text-[#00293d] 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">
|
<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" />
|
<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" />
|
||||||
@@ -190,7 +190,7 @@ export default function ProfileSectionsPage() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={openCreateModal}
|
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"
|
className="px-4 py-2 bg-[#f5a623] hover:bg-[#e09620] 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">
|
<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" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
|
||||||
@@ -210,73 +210,73 @@ export default function ProfileSectionsPage() {
|
|||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="flex items-center justify-center py-12">
|
<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 className="animate-spin rounded-full h-8 w-8 border-b-2 border-[#f5a623]"></div>
|
||||||
</div>
|
</div>
|
||||||
) : sections.length === 0 ? (
|
) : sections.length === 0 ? (
|
||||||
<div className="text-center py-12">
|
<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">
|
<svg className="mx-auto h-12 w-12 text-[#9ca3af]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 10h16M4 14h16M4 18h16" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 10h16M4 14h16M4 18h16" />
|
||||||
</svg>
|
</svg>
|
||||||
<p className="mt-2 text-gray-500">No profile sections found</p>
|
<p className="mt-2 text-[#666666] font-serif">No profile sections found</p>
|
||||||
<button
|
<button
|
||||||
onClick={openCreateModal}
|
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"
|
className="mt-4 px-4 py-2 bg-[#f5a623] hover:bg-[#e09620] text-white text-sm font-medium rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
Create First Section
|
Create First Section
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<table className="min-w-full divide-y divide-gray-200">
|
<table className="min-w-full divide-y divide-[#e5e7eb]">
|
||||||
<thead className="bg-gray-50">
|
<thead className="bg-[#f5f9f8]">
|
||||||
<tr>
|
<tr>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Section
|
Section
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Description
|
Description
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Fields
|
Fields
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Agent Types
|
Agent Types
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Global
|
Global
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Status
|
Status
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-right text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Actions
|
Actions
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="bg-white divide-y divide-gray-200">
|
<tbody className="bg-white divide-y divide-[#e5e7eb]">
|
||||||
{sections.map((section) => (
|
{sections.map((section) => (
|
||||||
<tr key={section.id} className="hover:bg-gray-50">
|
<tr key={section.id} className="hover:bg-[#f5f9f8]">
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
{section.icon && (
|
{section.icon && (
|
||||||
<span className="mr-3 text-gray-500">
|
<span className="mr-3 text-[#666666]">
|
||||||
<SectionIcon name={section.icon} className="w-5 h-5" />
|
<SectionIcon name={section.icon} className="w-5 h-5" />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm font-medium text-gray-900">{section.name}</div>
|
<div className="text-sm font-medium text-[#00293d]">{section.name}</div>
|
||||||
<div className="text-xs text-gray-500">{section.slug}</div>
|
<div className="text-xs text-[#666666]">{section.slug}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4">
|
<td className="px-6 py-4">
|
||||||
<div className="text-sm text-gray-500 max-w-xs truncate">
|
<div className="text-sm text-[#666666] max-w-xs truncate">
|
||||||
{section.description || '-'}
|
{section.description || '-'}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<Link
|
<Link
|
||||||
href={`/dashboard/profile-sections/${section.id}`}
|
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"
|
className="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-[#e8f0ee] text-[#5ba4a4] hover:bg-[#d5e5e1]"
|
||||||
>
|
>
|
||||||
{section._count?.fields || 0} fields
|
{section._count?.fields || 0} fields
|
||||||
<svg className="ml-1 w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="ml-1 w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -285,9 +285,9 @@ export default function ProfileSectionsPage() {
|
|||||||
</Link>
|
</Link>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<div className="text-sm text-gray-500">
|
<div className="text-sm text-[#666666]">
|
||||||
{section.isGlobal ? (
|
{section.isGlobal ? (
|
||||||
<span className="text-purple-600 font-medium">All (Global)</span>
|
<span className="text-[#5ba4a4] font-medium">All (Global)</span>
|
||||||
) : (
|
) : (
|
||||||
`${section._count?.agentTypeSections || 0} assigned`
|
`${section._count?.agentTypeSections || 0} assigned`
|
||||||
)}
|
)}
|
||||||
@@ -296,15 +296,15 @@ export default function ProfileSectionsPage() {
|
|||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
{section.isSystem && (
|
{section.isSystem && (
|
||||||
<span className="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-amber-100 text-amber-800">
|
<span className="inline-flex px-2 py-1 text-xs font-semibold rounded-full bg-[#fff7ed] text-[#f5a623]">
|
||||||
System
|
System
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span
|
<span
|
||||||
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
|
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
|
||||||
section.isGlobal
|
section.isGlobal
|
||||||
? 'bg-purple-100 text-purple-800'
|
? 'bg-[#fff7ed] text-[#f5a623]'
|
||||||
: 'bg-gray-100 text-gray-600'
|
: 'bg-[#e8f0ee] text-[#666666]'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{section.isGlobal ? 'Global' : 'Specific'}
|
{section.isGlobal ? 'Global' : 'Specific'}
|
||||||
@@ -331,19 +331,19 @@ export default function ProfileSectionsPage() {
|
|||||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||||
<Link
|
<Link
|
||||||
href={`/dashboard/profile-sections/${section.id}`}
|
href={`/dashboard/profile-sections/${section.id}`}
|
||||||
className="text-blue-600 hover:text-blue-900 mr-4"
|
className="text-[#f5a623] hover:text-[#e09620] mr-4"
|
||||||
>
|
>
|
||||||
Manage
|
Manage
|
||||||
</Link>
|
</Link>
|
||||||
<button
|
<button
|
||||||
onClick={() => openEditModal(section)}
|
onClick={() => openEditModal(section)}
|
||||||
className="text-gray-600 hover:text-gray-900 mr-4"
|
className="text-[#5ba4a4] hover:text-[#5ba4a4]/80 mr-4"
|
||||||
>
|
>
|
||||||
Edit
|
Edit
|
||||||
</button>
|
</button>
|
||||||
{section.isSystem ? (
|
{section.isSystem ? (
|
||||||
<span
|
<span
|
||||||
className="text-gray-400 cursor-not-allowed"
|
className="text-[#9ca3af] cursor-not-allowed"
|
||||||
title="System sections cannot be deleted"
|
title="System sections cannot be deleted"
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
@@ -367,10 +367,10 @@ export default function ProfileSectionsPage() {
|
|||||||
|
|
||||||
{/* Create/Edit Modal */}
|
{/* Create/Edit Modal */}
|
||||||
{(modalType === 'create' || modalType === 'edit') && (
|
{(modalType === 'create' || modalType === 'edit') && (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
<div className="fixed inset-0 bg-black/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="bg-white rounded-xl shadow-xl max-w-md w-full mx-4">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<h3 className="text-lg font-semibold text-gray-900">
|
<h3 className="text-lg font-semibold text-[#00293d] font-fractul">
|
||||||
{modalType === 'create' ? 'Create Profile Section' : 'Edit Profile Section'}
|
{modalType === 'create' ? 'Create Profile Section' : 'Edit Profile Section'}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -382,44 +382,44 @@ export default function ProfileSectionsPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Name <span className="text-red-500">*</span>
|
Name <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={formData.name}
|
value={formData.name}
|
||||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
placeholder="e.g., Location, Experience, Education"
|
placeholder="e.g., Location, Experience, Education"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Description
|
Description
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
value={formData.description}
|
value={formData.description}
|
||||||
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
||||||
rows={3}
|
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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
placeholder="Brief description of this section"
|
placeholder="Brief description of this section"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Icon (emoji)
|
Icon (emoji)
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={formData.icon}
|
value={formData.icon}
|
||||||
onChange={(e) => setFormData({ ...formData, icon: e.target.value })}
|
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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
placeholder="e.g., location_on"
|
placeholder="e.g., location_on"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-[#00293d] mb-1">
|
||||||
Sort Order
|
Sort Order
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -429,7 +429,7 @@ export default function ProfileSectionsPage() {
|
|||||||
onFocus={(e) => e.target.select()}
|
onFocus={(e) => e.target.select()}
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
min={0}
|
min={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 placeholder:text-gray-500"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-6">
|
<div className="flex items-center space-x-6">
|
||||||
@@ -439,9 +439,9 @@ export default function ProfileSectionsPage() {
|
|||||||
id="isActive"
|
id="isActive"
|
||||||
checked={formData.isActive}
|
checked={formData.isActive}
|
||||||
onChange={(e) => setFormData({ ...formData, isActive: e.target.checked })}
|
onChange={(e) => setFormData({ ...formData, isActive: e.target.checked })}
|
||||||
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
className="rounded border-[#e5e7eb] text-[#f5a623] focus:ring-[#f5a623]"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="isActive" className="ml-2 text-sm text-gray-700">
|
<label htmlFor="isActive" className="ml-2 text-sm text-[#00293d] font-serif">
|
||||||
Active
|
Active
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -451,9 +451,9 @@ export default function ProfileSectionsPage() {
|
|||||||
id="isGlobal"
|
id="isGlobal"
|
||||||
checked={formData.isGlobal}
|
checked={formData.isGlobal}
|
||||||
onChange={(e) => setFormData({ ...formData, isGlobal: e.target.checked })}
|
onChange={(e) => setFormData({ ...formData, isGlobal: e.target.checked })}
|
||||||
className="rounded border-gray-300 text-purple-600 focus:ring-purple-500"
|
className="rounded border-[#e5e7eb] text-[#5ba4a4] focus:ring-[#5ba4a4]"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="isGlobal" className="ml-2 text-sm text-gray-700">
|
<label htmlFor="isGlobal" className="ml-2 text-sm text-[#00293d] font-serif">
|
||||||
Global (all agent types)
|
Global (all agent types)
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -464,25 +464,25 @@ export default function ProfileSectionsPage() {
|
|||||||
id="isRepeatable"
|
id="isRepeatable"
|
||||||
checked={formData.isRepeatable}
|
checked={formData.isRepeatable}
|
||||||
onChange={(e) => setFormData({ ...formData, isRepeatable: e.target.checked })}
|
onChange={(e) => setFormData({ ...formData, isRepeatable: e.target.checked })}
|
||||||
className="rounded border-gray-300 text-orange-600 focus:ring-orange-500"
|
className="rounded border-[#e5e7eb] text-[#f5a623] focus:ring-[#f5a623]"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="isRepeatable" className="ml-2 text-sm text-gray-700">
|
<label htmlFor="isRepeatable" className="ml-2 text-sm text-[#00293d] font-serif">
|
||||||
Allow Multiple Entries (e.g., certifications, education)
|
Allow Multiple Entries (e.g., certifications, education)
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
|
<div className="px-6 py-4 border-t border-[#e5e7eb] flex justify-end space-x-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={closeModal}
|
onClick={closeModal}
|
||||||
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
className="px-4 py-2 border border-[#e5e7eb] text-[#00293d] rounded-xl hover:bg-[#f5f9f8] transition-colors"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50"
|
className="px-4 py-2 bg-[#f5a623] text-white rounded-xl hover:bg-[#e09620] transition-colors disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isSubmitting ? 'Saving...' : modalType === 'create' ? 'Create' : 'Save Changes'}
|
{isSubmitting ? 'Saving...' : modalType === 'create' ? 'Create' : 'Save Changes'}
|
||||||
</button>
|
</button>
|
||||||
@@ -494,10 +494,10 @@ export default function ProfileSectionsPage() {
|
|||||||
|
|
||||||
{/* Delete Confirmation Modal */}
|
{/* Delete Confirmation Modal */}
|
||||||
{modalType === 'delete' && selectedSection && (
|
{modalType === 'delete' && selectedSection && (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
<div className="fixed inset-0 bg-black/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="bg-white rounded-xl shadow-xl max-w-md w-full mx-4">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<h3 className="text-lg font-semibold text-gray-900">Delete Profile Section</h3>
|
<h3 className="text-lg font-semibold text-[#00293d] font-fractul">Delete Profile Section</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 py-4">
|
<div className="px-6 py-4">
|
||||||
{modalError && (
|
{modalError && (
|
||||||
@@ -505,7 +505,7 @@ export default function ProfileSectionsPage() {
|
|||||||
<p className="text-red-700 text-sm">{modalError}</p>
|
<p className="text-red-700 text-sm">{modalError}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<p className="text-gray-600">
|
<p className="text-[#666666] font-serif">
|
||||||
Are you sure you want to delete <span className="font-semibold">{selectedSection.name}</span>?
|
Are you sure you want to delete <span className="font-semibold">{selectedSection.name}</span>?
|
||||||
</p>
|
</p>
|
||||||
{(selectedSection._count?.fields && selectedSection._count.fields > 0) && (
|
{(selectedSection._count?.fields && selectedSection._count.fields > 0) && (
|
||||||
@@ -514,10 +514,10 @@ export default function ProfileSectionsPage() {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
|
<div className="px-6 py-4 border-t border-[#e5e7eb] flex justify-end space-x-3">
|
||||||
<button
|
<button
|
||||||
onClick={closeModal}
|
onClick={closeModal}
|
||||||
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
className="px-4 py-2 border border-[#e5e7eb] text-[#00293d] rounded-xl hover:bg-[#f5f9f8] transition-colors"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ export default function UserDetailPage() {
|
|||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center py-12">
|
<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 className="animate-spin rounded-full h-8 w-8 border-b-2 border-[#f5a623]"></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -247,7 +247,7 @@ export default function UserDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => router.push('/dashboard/users')}
|
onClick={() => router.push('/dashboard/users')}
|
||||||
className="mt-4 px-4 py-2 text-blue-600 hover:text-blue-800"
|
className="mt-4 px-4 py-2 text-[#f5a623] hover:text-[#e09620]"
|
||||||
>
|
>
|
||||||
← Back to Users
|
← Back to Users
|
||||||
</button>
|
</button>
|
||||||
@@ -258,10 +258,10 @@ export default function UserDetailPage() {
|
|||||||
if (!user) {
|
if (!user) {
|
||||||
return (
|
return (
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
<p className="text-gray-500">User not found</p>
|
<p className="text-[#666666] font-serif">User not found</p>
|
||||||
<button
|
<button
|
||||||
onClick={() => router.push('/dashboard/users')}
|
onClick={() => router.push('/dashboard/users')}
|
||||||
className="mt-4 px-4 py-2 text-blue-600 hover:text-blue-800"
|
className="mt-4 px-4 py-2 text-[#f5a623] hover:text-[#e09620]"
|
||||||
>
|
>
|
||||||
← Back to Users
|
← Back to Users
|
||||||
</button>
|
</button>
|
||||||
@@ -274,7 +274,7 @@ export default function UserDetailPage() {
|
|||||||
{/* Back Button */}
|
{/* Back Button */}
|
||||||
<button
|
<button
|
||||||
onClick={() => router.push('/dashboard/users')}
|
onClick={() => router.push('/dashboard/users')}
|
||||||
className="mb-6 flex items-center text-gray-600 hover:text-gray-900"
|
className="mb-6 flex items-center text-[#666666] hover:text-[#00293d]"
|
||||||
>
|
>
|
||||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||||
@@ -295,7 +295,7 @@ export default function UserDetailPage() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* User Header */}
|
{/* User Header */}
|
||||||
<div className="bg-white rounded-lg shadow mb-6">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb] mb-6">
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
{/* Avatar */}
|
{/* Avatar */}
|
||||||
@@ -303,8 +303,8 @@ export default function UserDetailPage() {
|
|||||||
{avatarUrl ? (
|
{avatarUrl ? (
|
||||||
<img className="h-20 w-20 rounded-full object-cover" src={avatarUrl} alt="" />
|
<img className="h-20 w-20 rounded-full object-cover" src={avatarUrl} alt="" />
|
||||||
) : (
|
) : (
|
||||||
<div className="h-20 w-20 rounded-full bg-gray-200 flex items-center justify-center">
|
<div className="h-20 w-20 rounded-full bg-[#e8f0ee] flex items-center justify-center">
|
||||||
<span className="text-gray-500 font-medium text-2xl">
|
<span className="text-[#666666] font-medium text-2xl">
|
||||||
{user.profile?.firstName?.[0] || user.email[0].toUpperCase()}
|
{user.profile?.firstName?.[0] || user.email[0].toUpperCase()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -313,10 +313,10 @@ export default function UserDetailPage() {
|
|||||||
|
|
||||||
{/* Name & Email */}
|
{/* Name & Email */}
|
||||||
<div className="ml-6 flex-1">
|
<div className="ml-6 flex-1">
|
||||||
<h1 className="text-2xl font-bold text-gray-900">
|
<h1 className="text-2xl font-bold text-[#00293d] font-fractul">
|
||||||
{user.profile?.firstName} {user.profile?.lastName}
|
{user.profile?.firstName} {user.profile?.lastName}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-gray-500">{user.email}</p>
|
<p className="text-[#666666] font-serif">{user.email}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Role & Status Badges */}
|
{/* Role & Status Badges */}
|
||||||
@@ -326,8 +326,8 @@ export default function UserDetailPage() {
|
|||||||
user.role === 'ADMIN'
|
user.role === 'ADMIN'
|
||||||
? 'bg-red-100 text-red-800'
|
? 'bg-red-100 text-red-800'
|
||||||
: user.role === 'AGENT'
|
: user.role === 'AGENT'
|
||||||
? 'bg-purple-100 text-purple-800'
|
? 'bg-[#fff7ed] text-[#f5a623]'
|
||||||
: 'bg-blue-100 text-blue-800'
|
: 'bg-[#e8f0ee] text-[#5ba4a4]'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{user.role}
|
{user.role}
|
||||||
@@ -349,20 +349,20 @@ export default function UserDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Basic Information */}
|
{/* Basic Information */}
|
||||||
<div className="bg-white rounded-lg shadow mb-6">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb] mb-6">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<h2 className="text-lg font-semibold text-gray-900">Basic Information</h2>
|
<h2 className="text-lg font-semibold text-[#00293d] font-fractul">Basic Information</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">Provider</p>
|
<p className="text-sm text-[#666666]">Provider</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.authProvider === 'LOCAL' ? 'Email' : user.authProvider}
|
{user.authProvider === 'LOCAL' ? 'Email' : user.authProvider}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">Email Verified</p>
|
<p className="text-sm text-[#666666]">Email Verified</p>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
{user.emailVerified ? (
|
{user.emailVerified ? (
|
||||||
<>
|
<>
|
||||||
@@ -377,25 +377,25 @@ export default function UserDetailPage() {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<svg className="w-5 h-5 text-gray-400 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
<svg className="w-5 h-5 text-[#9ca3af] mr-1" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path
|
<path
|
||||||
fillRule="evenodd"
|
fillRule="evenodd"
|
||||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
|
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
|
||||||
clipRule="evenodd"
|
clipRule="evenodd"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span className="text-sm font-medium text-gray-500">Not Verified</span>
|
<span className="text-sm font-medium text-[#666666]">Not Verified</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">Joined</p>
|
<p className="text-sm text-[#666666]">Joined</p>
|
||||||
<p className="text-sm font-medium text-gray-900">{formatDate(user.createdAt)}</p>
|
<p className="text-sm font-medium text-[#00293d]">{formatDate(user.createdAt)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">Last Login</p>
|
<p className="text-sm text-[#666666]">Last Login</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.lastLoginAt ? formatDate(user.lastLoginAt) : 'Never'}
|
{user.lastLoginAt ? formatDate(user.lastLoginAt) : 'Never'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -404,33 +404,33 @@ export default function UserDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Contact Information */}
|
{/* Contact Information */}
|
||||||
<div className="bg-white rounded-lg shadow mb-6">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb] mb-6">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<h2 className="text-lg font-semibold text-gray-900">Contact Information</h2>
|
<h2 className="text-lg font-semibold text-[#00293d] font-fractul">Contact Information</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">Phone</p>
|
<p className="text-sm text-[#666666]">Phone</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.profile?.phone || 'Not provided'}
|
{user.profile?.phone || 'Not provided'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">City</p>
|
<p className="text-sm text-[#666666]">City</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.profile?.city || 'Not provided'}
|
{user.profile?.city || 'Not provided'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">State</p>
|
<p className="text-sm text-[#666666]">State</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.profile?.state || 'Not provided'}
|
{user.profile?.state || 'Not provided'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">Country</p>
|
<p className="text-sm text-[#666666]">Country</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.profile?.country || 'Not provided'}
|
{user.profile?.country || 'Not provided'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -440,21 +440,21 @@ export default function UserDetailPage() {
|
|||||||
|
|
||||||
{/* Agent Details (only for AGENT role) */}
|
{/* Agent Details (only for AGENT role) */}
|
||||||
{user.role === 'AGENT' && user.agentProfile && (
|
{user.role === 'AGENT' && user.agentProfile && (
|
||||||
<div className="bg-white rounded-lg shadow mb-6">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb] mb-6">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<h2 className="text-lg font-semibold text-gray-900">Agent Details</h2>
|
<h2 className="text-lg font-semibold text-[#00293d] font-fractul">Agent Details</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
{/* Agent Details Grid */}
|
{/* Agent Details Grid */}
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||||
{/* Agent Type - Editable */}
|
{/* Agent Type - Editable */}
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500 mb-1">Agent Type</p>
|
<p className="text-sm text-[#666666] mb-1">Agent Type</p>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<select
|
<select
|
||||||
value={selectedAgentTypeId}
|
value={selectedAgentTypeId}
|
||||||
onChange={(e) => setSelectedAgentTypeId(e.target.value)}
|
onChange={(e) => setSelectedAgentTypeId(e.target.value)}
|
||||||
className="w-full max-w-[160px] px-2 py-1 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-gray-900 bg-white"
|
className="w-full max-w-[160px] px-2 py-1 text-sm border border-[#e5e7eb] rounded-lg focus:ring-1 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white"
|
||||||
>
|
>
|
||||||
<option value="">Select...</option>
|
<option value="">Select...</option>
|
||||||
{agentTypes.map((type) => (
|
{agentTypes.map((type) => (
|
||||||
@@ -467,7 +467,7 @@ export default function UserDetailPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={handleUpdateAgentType}
|
onClick={handleUpdateAgentType}
|
||||||
disabled={isUpdatingAgentType}
|
disabled={isUpdatingAgentType}
|
||||||
className="px-2 py-1 bg-blue-600 hover:bg-blue-700 text-white text-xs font-medium rounded transition-colors disabled:opacity-50"
|
className="px-2 py-1 bg-[#f5a623] hover:bg-[#e09620] text-white text-xs font-medium rounded transition-colors disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isUpdatingAgentType ? '...' : 'Save'}
|
{isUpdatingAgentType ? '...' : 'Save'}
|
||||||
</button>
|
</button>
|
||||||
@@ -475,32 +475,32 @@ export default function UserDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">Slug</p>
|
<p className="text-sm text-[#666666]">Slug</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.agentProfile.slug || 'Not set'}
|
{user.agentProfile.slug || 'Not set'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">Company</p>
|
<p className="text-sm text-[#666666]">Company</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.agentProfile.companyName || 'Not provided'}
|
{user.agentProfile.companyName || 'Not provided'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">License Number</p>
|
<p className="text-sm text-[#666666]">License Number</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.agentProfile.licenseNumber || 'Not provided'}
|
{user.agentProfile.licenseNumber || 'Not provided'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">Years of Experience</p>
|
<p className="text-sm text-[#666666]">Years of Experience</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.agentProfile.yearsOfExperience ?? 'Not provided'}
|
{user.agentProfile.yearsOfExperience ?? 'Not provided'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">Profile Status</p>
|
<p className="text-sm text-[#666666]">Profile Status</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.agentProfile.profileCompleteness}%{' '}
|
{user.agentProfile.profileCompleteness}%{' '}
|
||||||
<span
|
<span
|
||||||
className={`ml-1 inline-flex px-2 py-0.5 text-xs font-semibold rounded-full ${
|
className={`ml-1 inline-flex px-2 py-0.5 text-xs font-semibold rounded-full ${
|
||||||
@@ -517,19 +517,19 @@ export default function UserDetailPage() {
|
|||||||
|
|
||||||
{/* Headline & Bio */}
|
{/* Headline & Bio */}
|
||||||
{(user.agentProfile.headline || user.agentProfile.bio) && (
|
{(user.agentProfile.headline || user.agentProfile.bio) && (
|
||||||
<div className="mt-6 pt-6 border-t border-gray-200">
|
<div className="mt-6 pt-6 border-t border-[#e5e7eb]">
|
||||||
{user.agentProfile.headline && (
|
{user.agentProfile.headline && (
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<p className="text-sm text-gray-500 mb-1">Headline</p>
|
<p className="text-sm text-[#666666] mb-1">Headline</p>
|
||||||
<p className="text-sm font-medium text-gray-900">
|
<p className="text-sm font-medium text-[#00293d]">
|
||||||
{user.agentProfile.headline}
|
{user.agentProfile.headline}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{user.agentProfile.bio && (
|
{user.agentProfile.bio && (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500 mb-1">Bio</p>
|
<p className="text-sm text-[#666666] mb-1">Bio</p>
|
||||||
<p className="text-sm text-gray-700 whitespace-pre-wrap">
|
<p className="text-sm text-[#666666] whitespace-pre-wrap">
|
||||||
{user.agentProfile.bio}
|
{user.agentProfile.bio}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -542,10 +542,10 @@ export default function UserDetailPage() {
|
|||||||
|
|
||||||
{/* Verification Section (only for AGENT role) */}
|
{/* Verification Section (only for AGENT role) */}
|
||||||
{user.role === 'AGENT' && user.agentProfile && (
|
{user.role === 'AGENT' && user.agentProfile && (
|
||||||
<div className="bg-white rounded-lg shadow mb-6">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb] mb-6">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-lg font-semibold text-gray-900">Verification Status</h2>
|
<h2 className="text-lg font-semibold text-[#00293d] font-fractul">Verification Status</h2>
|
||||||
{getVerificationStatusBadge(user.agentProfile.verificationStatus as VerificationStatus)}
|
{getVerificationStatusBadge(user.agentProfile.verificationStatus as VerificationStatus)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -568,21 +568,21 @@ export default function UserDetailPage() {
|
|||||||
|
|
||||||
{/* Uploaded Documents */}
|
{/* Uploaded Documents */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h3 className="text-sm font-medium text-gray-900 mb-3">Uploaded Documents</h3>
|
<h3 className="text-sm font-medium text-[#00293d] mb-3">Uploaded Documents</h3>
|
||||||
{isLoadingDocuments ? (
|
{isLoadingDocuments ? (
|
||||||
<div className="flex items-center justify-center py-4">
|
<div className="flex items-center justify-center py-4">
|
||||||
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-blue-600"></div>
|
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-[#f5a623]"></div>
|
||||||
</div>
|
</div>
|
||||||
) : verificationDocuments.length > 0 ? (
|
) : verificationDocuments.length > 0 ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{verificationDocuments.map((doc, index) => (
|
{verificationDocuments.map((doc, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="flex items-center justify-between p-3 bg-gray-50 border border-gray-200 rounded-lg"
|
className="flex items-center justify-between p-3 bg-[#f5f9f8] border border-[#e5e7eb] rounded-xl"
|
||||||
>
|
>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<svg
|
<svg
|
||||||
className="w-8 h-8 text-gray-400 mr-3"
|
className="w-8 h-8 text-[#9ca3af] mr-3"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -595,8 +595,8 @@ export default function UserDetailPage() {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-gray-900">{doc.name}</p>
|
<p className="text-sm font-medium text-[#00293d]">{doc.name}</p>
|
||||||
<p className="text-xs text-gray-500">{formatFileSize(doc.size)}</p>
|
<p className="text-xs text-[#666666]">{formatFileSize(doc.size)}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{doc.url && (
|
{doc.url && (
|
||||||
@@ -604,7 +604,7 @@ export default function UserDetailPage() {
|
|||||||
href={doc.url}
|
href={doc.url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="px-3 py-1 text-sm text-blue-600 hover:text-blue-800 hover:bg-blue-50 rounded transition-colors"
|
className="px-3 py-1 text-sm text-[#f5a623] hover:text-[#e09620] hover:bg-[#fff7ed] rounded transition-colors"
|
||||||
>
|
>
|
||||||
Download
|
Download
|
||||||
</a>
|
</a>
|
||||||
@@ -613,7 +613,7 @@ export default function UserDetailPage() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-sm text-gray-500 py-4 text-center">
|
<p className="text-sm text-[#666666] py-4 text-center">
|
||||||
No documents uploaded yet
|
No documents uploaded yet
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -621,19 +621,19 @@ export default function UserDetailPage() {
|
|||||||
|
|
||||||
{/* Admin Actions */}
|
{/* Admin Actions */}
|
||||||
{user.agentProfile.verificationStatus !== 'APPROVED' && (
|
{user.agentProfile.verificationStatus !== 'APPROVED' && (
|
||||||
<div className="border-t border-gray-200 pt-6">
|
<div className="border-t border-[#e5e7eb] pt-6">
|
||||||
<h3 className="text-sm font-medium text-gray-900 mb-3">Admin Actions</h3>
|
<h3 className="text-sm font-medium text-[#00293d] mb-3">Admin Actions</h3>
|
||||||
|
|
||||||
{/* Note Input */}
|
{/* Note Input */}
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label className="block text-sm text-gray-500 mb-1">
|
<label className="block text-sm text-[#666666] mb-1">
|
||||||
Note (optional, required for rejection)
|
Note (optional, required for rejection)
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
value={verificationNote}
|
value={verificationNote}
|
||||||
onChange={(e) => setVerificationNote(e.target.value)}
|
onChange={(e) => setVerificationNote(e.target.value)}
|
||||||
rows={2}
|
rows={2}
|
||||||
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"
|
className="w-full px-3 py-2 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] text-[#00293d] bg-white placeholder:text-[#666666]"
|
||||||
placeholder="Enter a note for the agent (e.g., rejection reason)"
|
placeholder="Enter a note for the agent (e.g., rejection reason)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -736,7 +736,7 @@ export default function UserDetailPage() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{!verificationNote.trim() && (
|
{!verificationNote.trim() && (
|
||||||
<p className="mt-2 text-xs text-gray-500">
|
<p className="mt-2 text-xs text-[#666666]">
|
||||||
* A note is required to reject verification
|
* A note is required to reject verification
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -750,7 +750,7 @@ export default function UserDetailPage() {
|
|||||||
|
|
||||||
{/* Already Approved Message */}
|
{/* Already Approved Message */}
|
||||||
{user.agentProfile.verificationStatus === 'APPROVED' && (
|
{user.agentProfile.verificationStatus === 'APPROVED' && (
|
||||||
<div className="border-t border-gray-200 pt-6">
|
<div className="border-t border-[#e5e7eb] pt-6">
|
||||||
<div className="flex items-center text-green-600">
|
<div className="flex items-center text-green-600">
|
||||||
<svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
<svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path
|
<path
|
||||||
|
|||||||
@@ -96,24 +96,24 @@ export default function UsersPage() {
|
|||||||
<div>
|
<div>
|
||||||
{/* Page Title */}
|
{/* Page Title */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h1 className="text-2xl font-bold text-gray-900">Users</h1>
|
<h1 className="text-2xl font-bold text-[#00293d] font-fractul">Users</h1>
|
||||||
<p className="text-gray-500">Manage all registered users</p>
|
<p className="text-[#666666] font-serif">Manage all registered users</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Users Table */}
|
{/* Users Table */}
|
||||||
<div className="bg-white rounded-lg shadow">
|
<div className="bg-white rounded-xl shadow-sm border border-[#e5e7eb]">
|
||||||
<div className="px-6 py-4 border-b border-gray-200">
|
<div className="px-6 py-4 border-b border-[#e5e7eb]">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
{/* Filter Tabs */}
|
{/* Filter Tabs */}
|
||||||
<div className="flex space-x-1 bg-gray-100 rounded-lg p-1">
|
<div className="flex space-x-1 bg-[#f5f9f8] rounded-lg p-1">
|
||||||
{roleFilters.map((filter) => (
|
{roleFilters.map((filter) => (
|
||||||
<button
|
<button
|
||||||
key={filter.value}
|
key={filter.value}
|
||||||
onClick={() => handleFilterChange(filter.value)}
|
onClick={() => handleFilterChange(filter.value)}
|
||||||
className={`px-4 py-2 text-sm font-medium rounded-md transition-colors ${
|
className={`px-4 py-2 text-sm font-medium rounded-md transition-colors ${
|
||||||
activeFilter === filter.value
|
activeFilter === filter.value
|
||||||
? 'bg-white text-gray-900 shadow-sm'
|
? 'bg-white text-[#00293d] shadow-sm'
|
||||||
: 'text-gray-600 hover:text-gray-900'
|
: 'text-[#666666] hover:text-[#00293d]'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{filter.label}
|
{filter.label}
|
||||||
@@ -122,7 +122,7 @@ export default function UsersPage() {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={fetchUsers}
|
onClick={fetchUsers}
|
||||||
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"
|
className="px-4 py-2 bg-[#f5a623] hover:bg-[#e09620] text-white text-sm font-medium rounded-lg transition-colors flex items-center"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
className="w-4 h-4 mr-2"
|
className="w-4 h-4 mr-2"
|
||||||
@@ -151,12 +151,12 @@ export default function UsersPage() {
|
|||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="flex items-center justify-center py-12">
|
<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 className="animate-spin rounded-full h-8 w-8 border-b-2 border-[#f5a623]"></div>
|
||||||
</div>
|
</div>
|
||||||
) : users.length === 0 ? (
|
) : users.length === 0 ? (
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<svg
|
<svg
|
||||||
className="mx-auto h-12 w-12 text-gray-400"
|
className="mx-auto h-12 w-12 text-[#9ca3af]"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -168,40 +168,40 @@ export default function UsersPage() {
|
|||||||
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"
|
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p className="mt-2 text-gray-500">No users found</p>
|
<p className="mt-2 text-[#666666]">No users found</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<table className="min-w-full divide-y divide-gray-200">
|
<table className="min-w-full divide-y divide-[#e5e7eb]">
|
||||||
<thead className="bg-gray-50">
|
<thead className="bg-[#f5f9f8]">
|
||||||
<tr>
|
<tr>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
User
|
User
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Role
|
Role
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Status
|
Status
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Provider
|
Provider
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Verified
|
Verified
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Joined
|
Joined
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th className="px-6 py-3 text-left text-xs font-medium text-[#666666] uppercase tracking-wider">
|
||||||
Last Login
|
Last Login
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="bg-white divide-y divide-gray-200">
|
<tbody className="bg-white divide-y divide-[#e5e7eb]">
|
||||||
{users.map((user) => (
|
{users.map((user) => (
|
||||||
<tr
|
<tr
|
||||||
key={user.id}
|
key={user.id}
|
||||||
className="hover:bg-gray-50 cursor-pointer"
|
className="hover:bg-[#f5f9f8] cursor-pointer"
|
||||||
onClick={() => router.push(`/dashboard/users/${user.id}`)}
|
onClick={() => router.push(`/dashboard/users/${user.id}`)}
|
||||||
>
|
>
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
@@ -214,18 +214,18 @@ export default function UsersPage() {
|
|||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="h-10 w-10 rounded-full bg-gray-200 flex items-center justify-center">
|
<div className="h-10 w-10 rounded-full bg-[#e8f0ee] flex items-center justify-center">
|
||||||
<span className="text-gray-500 font-medium text-sm">
|
<span className="text-[#666666] font-medium text-sm">
|
||||||
{user.profile?.firstName?.[0] || user.email[0].toUpperCase()}
|
{user.profile?.firstName?.[0] || user.email[0].toUpperCase()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-4">
|
<div className="ml-4">
|
||||||
<div className="text-sm font-medium text-gray-900">
|
<div className="text-sm font-medium text-[#00293d]">
|
||||||
{user.profile?.firstName} {user.profile?.lastName}
|
{user.profile?.firstName} {user.profile?.lastName}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-gray-500">{user.email}</div>
|
<div className="text-sm text-[#666666]">{user.email}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -235,8 +235,8 @@ export default function UsersPage() {
|
|||||||
user.role === 'ADMIN'
|
user.role === 'ADMIN'
|
||||||
? 'bg-red-100 text-red-800'
|
? 'bg-red-100 text-red-800'
|
||||||
: user.role === 'AGENT'
|
: user.role === 'AGENT'
|
||||||
? 'bg-purple-100 text-purple-800'
|
? 'bg-[#fff7ed] text-[#f5a623]'
|
||||||
: 'bg-blue-100 text-blue-800'
|
: 'bg-[#e8f0ee] text-[#5ba4a4]'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{user.role}
|
{user.role}
|
||||||
@@ -257,7 +257,7 @@ export default function UsersPage() {
|
|||||||
{user.status === 'PENDING_VERIFICATION' ? 'PENDING' : user.status}
|
{user.status === 'PENDING_VERIFICATION' ? 'PENDING' : user.status}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-[#666666]">
|
||||||
{user.authProvider === 'LOCAL' ? 'Email' : user.authProvider}
|
{user.authProvider === 'LOCAL' ? 'Email' : user.authProvider}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<td className="px-6 py-4 whitespace-nowrap">
|
||||||
@@ -275,7 +275,7 @@ export default function UsersPage() {
|
|||||||
</svg>
|
</svg>
|
||||||
) : (
|
) : (
|
||||||
<svg
|
<svg
|
||||||
className="w-5 h-5 text-gray-400"
|
className="w-5 h-5 text-[#9ca3af]"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
viewBox="0 0 20 20"
|
viewBox="0 0 20 20"
|
||||||
>
|
>
|
||||||
@@ -287,10 +287,10 @@ export default function UsersPage() {
|
|||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-[#666666]">
|
||||||
{new Date(user.createdAt).toLocaleDateString()}
|
{new Date(user.createdAt).toLocaleDateString()}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-[#666666]">
|
||||||
{user.lastLoginAt
|
{user.lastLoginAt
|
||||||
? new Date(user.lastLoginAt).toLocaleDateString()
|
? new Date(user.lastLoginAt).toLocaleDateString()
|
||||||
: 'Never'}
|
: 'Never'}
|
||||||
@@ -304,8 +304,8 @@ export default function UsersPage() {
|
|||||||
|
|
||||||
{/* Pagination */}
|
{/* Pagination */}
|
||||||
{totalPages > 1 && (
|
{totalPages > 1 && (
|
||||||
<div className="px-6 py-4 border-t border-gray-200 flex items-center justify-between">
|
<div className="px-6 py-4 border-t border-[#e5e7eb] flex items-center justify-between">
|
||||||
<p className="text-sm text-gray-500">
|
<p className="text-sm text-[#666666]">
|
||||||
Showing {(currentPage - 1) * limit + 1} to{' '}
|
Showing {(currentPage - 1) * limit + 1} to{' '}
|
||||||
{Math.min(currentPage * limit, totalUsers)} of {totalUsers} users
|
{Math.min(currentPage * limit, totalUsers)} of {totalUsers} users
|
||||||
</p>
|
</p>
|
||||||
@@ -313,14 +313,14 @@ export default function UsersPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
|
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
|
||||||
disabled={currentPage === 1}
|
disabled={currentPage === 1}
|
||||||
className="px-3 py-1 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"
|
className="px-3 py-1 border border-[#e5e7eb] rounded-md text-sm font-medium text-[#00293d] hover:bg-[#f5f9f8] disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
Previous
|
Previous
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
|
onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
|
||||||
disabled={currentPage === totalPages}
|
disabled={currentPage === totalPages}
|
||||||
className="px-3 py-1 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"
|
className="px-3 py-1 border border-[#e5e7eb] rounded-md text-sm font-medium text-[#00293d] hover:bg-[#f5f9f8] disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
+58
-7
@@ -1,19 +1,70 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--background: #ffffff;
|
/* RE-Quest Admin Design Tokens (matching web app) */
|
||||||
--foreground: #171717;
|
--color-primary-dark: #00293d;
|
||||||
|
--color-primary-light: #c4d9d4;
|
||||||
|
--color-accent-orange: #f5a623;
|
||||||
|
--color-accent-orange-hover: #e09620;
|
||||||
|
--color-accent-teal: #5ba4a4;
|
||||||
|
--color-background: #ffffff;
|
||||||
|
--color-background-alt: #f5f9f8;
|
||||||
|
--color-foreground: #171717;
|
||||||
|
--color-text-gray: #666666;
|
||||||
|
--color-text-muted: #9ca3af;
|
||||||
|
--color-border: #e5e7eb;
|
||||||
|
|
||||||
|
/* Spacing */
|
||||||
|
--spacing-section: 6rem;
|
||||||
|
--spacing-section-sm: 4rem;
|
||||||
|
|
||||||
|
/* Border Radius */
|
||||||
|
--radius-sm: 0.375rem;
|
||||||
|
--radius-md: 0.5rem;
|
||||||
|
--radius-lg: 1rem;
|
||||||
|
--radius-xl: 1.5rem;
|
||||||
|
--radius-2xl: 2rem;
|
||||||
|
--radius-full: 9999px;
|
||||||
|
|
||||||
|
/* Shadows */
|
||||||
|
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||||
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--color-background: var(--background);
|
--color-background: #ffffff;
|
||||||
--color-foreground: var(--foreground);
|
--color-foreground: #171717;
|
||||||
--font-sans: var(--font-geist-sans);
|
--font-sans: var(--font-geist-sans);
|
||||||
--font-mono: var(--font-geist-mono);
|
--font-mono: var(--font-geist-mono);
|
||||||
|
--font-serif: var(--font-source-serif-4);
|
||||||
|
--font-fractul: var(--font-fractul);
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: var(--background);
|
background: var(--color-background);
|
||||||
color: var(--foreground);
|
color: var(--color-foreground);
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: var(--font-source-serif-4, Arial, Helvetica, sans-serif);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Selection styling to match web */
|
||||||
|
::selection {
|
||||||
|
background-color: var(--color-primary-light);
|
||||||
|
color: var(--color-primary-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Smooth scrolling */
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card hover effects */
|
||||||
|
.card-hover {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-hover:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
}
|
}
|
||||||
+106
-1
@@ -1,5 +1,6 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { Geist, Geist_Mono } from "next/font/google";
|
import { Geist, Geist_Mono } from "next/font/google";
|
||||||
|
import localFont from "next/font/local";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import { AuthProvider } from "@/context/AuthContext";
|
import { AuthProvider } from "@/context/AuthContext";
|
||||||
|
|
||||||
@@ -13,6 +14,110 @@ const geistMono = Geist_Mono({
|
|||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Local Fractul font (matching web app)
|
||||||
|
const fractul = localFont({
|
||||||
|
src: [
|
||||||
|
{
|
||||||
|
path: "../fonts/fractul/Fractul-Regular.ttf",
|
||||||
|
weight: "400",
|
||||||
|
style: "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/fractul/Fractul-Italic.ttf",
|
||||||
|
weight: "400",
|
||||||
|
style: "italic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/fractul/Fractul-Medium.ttf",
|
||||||
|
weight: "500",
|
||||||
|
style: "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/fractul/Fractul-MediumItalic.ttf",
|
||||||
|
weight: "500",
|
||||||
|
style: "italic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/fractul/Fractul-SemiBold.ttf",
|
||||||
|
weight: "600",
|
||||||
|
style: "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/fractul/Fractul-SemiBoldItalic.ttf",
|
||||||
|
weight: "600",
|
||||||
|
style: "italic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/fractul/Fractul-Bold.ttf",
|
||||||
|
weight: "700",
|
||||||
|
style: "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/fractul/Fractul-BoldItalic.ttf",
|
||||||
|
weight: "700",
|
||||||
|
style: "italic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/fractul/Fractul-ExtraBold.ttf",
|
||||||
|
weight: "800",
|
||||||
|
style: "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/fractul/Fractul-ExtraBoldItalic.ttf",
|
||||||
|
weight: "800",
|
||||||
|
style: "italic",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
variable: "--font-fractul",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Local Source Serif 4 font (matching web app)
|
||||||
|
const sourceSerif4 = localFont({
|
||||||
|
src: [
|
||||||
|
{
|
||||||
|
path: "../fonts/Source_Serif_4/static/SourceSerif4-Regular.ttf",
|
||||||
|
weight: "400",
|
||||||
|
style: "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/Source_Serif_4/static/SourceSerif4-Italic.ttf",
|
||||||
|
weight: "400",
|
||||||
|
style: "italic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/Source_Serif_4/static/SourceSerif4-Medium.ttf",
|
||||||
|
weight: "500",
|
||||||
|
style: "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/Source_Serif_4/static/SourceSerif4-MediumItalic.ttf",
|
||||||
|
weight: "500",
|
||||||
|
style: "italic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/Source_Serif_4/static/SourceSerif4-SemiBold.ttf",
|
||||||
|
weight: "600",
|
||||||
|
style: "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/Source_Serif_4/static/SourceSerif4-SemiBoldItalic.ttf",
|
||||||
|
weight: "600",
|
||||||
|
style: "italic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/Source_Serif_4/static/SourceSerif4-Bold.ttf",
|
||||||
|
weight: "700",
|
||||||
|
style: "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "../fonts/Source_Serif_4/static/SourceSerif4-BoldItalic.ttf",
|
||||||
|
weight: "700",
|
||||||
|
style: "italic",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
variable: "--font-source-serif-4",
|
||||||
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Re-Quest Admin",
|
title: "Re-Quest Admin",
|
||||||
description: "Admin dashboard for Re-Quest Platform",
|
description: "Admin dashboard for Re-Quest Platform",
|
||||||
@@ -26,7 +131,7 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body
|
<body
|
||||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
className={`${geistSans.variable} ${geistMono.variable} ${sourceSerif4.variable} ${fractul.variable} antialiased`}
|
||||||
>
|
>
|
||||||
<AuthProvider>{children}</AuthProvider>
|
<AuthProvider>{children}</AuthProvider>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+16
-16
@@ -35,21 +35,21 @@ export default function LoginPage() {
|
|||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex items-center justify-center bg-gray-100">
|
<div className="min-h-screen flex items-center justify-center bg-[#f5f9f8]">
|
||||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#f5a623]"></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex items-center justify-center bg-gray-100">
|
<div className="min-h-screen flex items-center justify-center bg-[#f5f9f8]">
|
||||||
<div className="max-w-md w-full mx-4">
|
<div className="max-w-md w-full mx-4">
|
||||||
<div className="bg-white rounded-lg shadow-lg p-8">
|
<div className="bg-white rounded-2xl shadow-lg p-8 border border-[#e5e7eb]">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="text-center mb-8">
|
<div className="text-center mb-8">
|
||||||
<div className="mx-auto w-16 h-16 bg-blue-600 rounded-full flex items-center justify-center mb-4">
|
<div className="mx-auto w-16 h-16 bg-[#00293d] rounded-2xl flex items-center justify-center mb-4 shadow-md">
|
||||||
<svg
|
<svg
|
||||||
className="w-8 h-8 text-white"
|
className="w-8 h-8 text-[#f5a623]"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -58,17 +58,17 @@ export default function LoginPage() {
|
|||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
|
d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-2xl font-bold text-gray-900">Re-Quest Admin</h1>
|
<h1 className="text-2xl font-bold text-[#00293d] font-fractul">Re-Quest Admin</h1>
|
||||||
<p className="text-gray-500 mt-2">Re-Quest Platform Administration</p>
|
<p className="text-[#666666] mt-2 font-serif">Platform Administration</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Error Alert */}
|
{/* Error Alert */}
|
||||||
{error && (
|
{error && (
|
||||||
<div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg">
|
<div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-xl">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<svg
|
<svg
|
||||||
className="w-5 h-5 text-red-500 mr-2"
|
className="w-5 h-5 text-red-500 mr-2"
|
||||||
@@ -91,7 +91,7 @@ export default function LoginPage() {
|
|||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor="email"
|
htmlFor="email"
|
||||||
className="block text-sm font-medium text-gray-700 mb-2"
|
className="block text-sm font-medium text-[#00293d] mb-2 font-serif"
|
||||||
>
|
>
|
||||||
Email Address
|
Email Address
|
||||||
</label>
|
</label>
|
||||||
@@ -101,7 +101,7 @@ export default function LoginPage() {
|
|||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
required
|
required
|
||||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors text-gray-900 placeholder:text-gray-400 bg-white"
|
className="w-full px-4 py-3 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] transition-colors text-gray-900 placeholder:text-gray-400 bg-white"
|
||||||
placeholder="admin@realestate.com"
|
placeholder="admin@realestate.com"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -109,7 +109,7 @@ export default function LoginPage() {
|
|||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor="password"
|
htmlFor="password"
|
||||||
className="block text-sm font-medium text-gray-700 mb-2"
|
className="block text-sm font-medium text-[#00293d] mb-2 font-serif"
|
||||||
>
|
>
|
||||||
Password
|
Password
|
||||||
</label>
|
</label>
|
||||||
@@ -119,7 +119,7 @@ export default function LoginPage() {
|
|||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
required
|
required
|
||||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors text-gray-900 placeholder:text-gray-400 bg-white"
|
className="w-full px-4 py-3 border border-[#e5e7eb] rounded-xl focus:ring-2 focus:ring-[#f5a623] focus:border-[#f5a623] transition-colors text-gray-900 placeholder:text-gray-400 bg-white"
|
||||||
placeholder="Enter your password"
|
placeholder="Enter your password"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -127,7 +127,7 @@ export default function LoginPage() {
|
|||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
className="w-full py-3 px-4 bg-blue-600 hover:bg-blue-700 disabled:bg-blue-400 text-white font-medium rounded-lg transition-colors flex items-center justify-center"
|
className="w-full py-3 px-4 bg-[#f5a623] hover:bg-[#e09620] disabled:bg-[#f5a623]/60 text-white font-semibold rounded-xl transition-all duration-200 flex items-center justify-center shadow-sm hover:shadow-md font-fractul"
|
||||||
>
|
>
|
||||||
{isSubmitting ? (
|
{isSubmitting ? (
|
||||||
<>
|
<>
|
||||||
@@ -160,7 +160,7 @@ export default function LoginPage() {
|
|||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<div className="mt-6 text-center">
|
<div className="mt-6 text-center">
|
||||||
<p className="text-xs text-gray-500">
|
<p className="text-xs text-[#9ca3af] font-serif">
|
||||||
Only administrators can access this portal
|
Only administrators can access this portal
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+2
-2
@@ -19,8 +19,8 @@ export default function Home() {
|
|||||||
}, [isAuthenticated, isLoading, router]);
|
}, [isAuthenticated, isLoading, router]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex items-center justify-center bg-gray-100">
|
<div className="min-h-screen flex items-center justify-center bg-[#f5f9f8]">
|
||||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#f5a623]"></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
+10
-10
@@ -66,11 +66,11 @@ export default function Sidebar() {
|
|||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="w-64 bg-gray-900 min-h-screen fixed left-0 top-0">
|
<aside className="w-64 bg-[#00293d] min-h-screen fixed left-0 top-0">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<div className="p-6 border-b border-gray-800">
|
<div className="p-6 border-b border-[#003a57]">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center mr-3">
|
<div className="w-10 h-10 bg-[#f5a623] rounded-lg flex items-center justify-center mr-3 shadow-sm">
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6 text-white"
|
className="w-6 h-6 text-white"
|
||||||
fill="none"
|
fill="none"
|
||||||
@@ -86,15 +86,15 @@ export default function Sidebar() {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-lg font-bold text-white">Re-Quest</h1>
|
<h1 className="text-lg font-bold text-white font-fractul">Re-Quest</h1>
|
||||||
<p className="text-xs text-gray-400">Admin Panel</p>
|
<p className="text-xs text-[#e8f0ee]">Admin Panel</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Navigation */}
|
{/* Navigation */}
|
||||||
<nav className="p-4">
|
<nav className="p-4">
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-1">
|
||||||
{menuItems.map((item) => {
|
{menuItems.map((item) => {
|
||||||
const isActive = pathname === item.href ||
|
const isActive = pathname === item.href ||
|
||||||
(item.href !== '/dashboard' && pathname.startsWith(item.href));
|
(item.href !== '/dashboard' && pathname.startsWith(item.href));
|
||||||
@@ -103,14 +103,14 @@ export default function Sidebar() {
|
|||||||
<li key={item.name}>
|
<li key={item.name}>
|
||||||
<Link
|
<Link
|
||||||
href={item.href}
|
href={item.href}
|
||||||
className={`flex items-center px-4 py-3 rounded-lg transition-colors ${
|
className={`flex items-center px-4 py-3 rounded-lg transition-all duration-200 ${
|
||||||
isActive
|
isActive
|
||||||
? 'bg-blue-600 text-white'
|
? 'bg-[#f5a623] text-white shadow-sm'
|
||||||
: 'text-gray-300 hover:bg-gray-800 hover:text-white'
|
: 'text-[#c4d9d4] hover:bg-[#003a57] hover:text-white'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{item.icon}
|
{item.icon}
|
||||||
<span className="ml-3 font-medium">{item.name}</span>
|
<span className="ml-3 font-medium font-serif text-sm">{item.name}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
Source Serif 4 Variable Font
|
||||||
|
============================
|
||||||
|
|
||||||
|
This download contains Source Serif 4 as both variable fonts and static fonts.
|
||||||
|
|
||||||
|
Source Serif 4 is a variable font with these axes:
|
||||||
|
opsz
|
||||||
|
wght
|
||||||
|
|
||||||
|
This means all the styles are contained in these files:
|
||||||
|
SourceSerif4-VariableFont_opsz,wght.ttf
|
||||||
|
SourceSerif4-Italic-VariableFont_opsz,wght.ttf
|
||||||
|
|
||||||
|
If your app fully supports variable fonts, you can now pick intermediate styles
|
||||||
|
that aren’t available as static fonts. Not all apps support variable fonts, and
|
||||||
|
in those cases you can use the static font files for Source Serif 4:
|
||||||
|
static/SourceSerif4-ExtraLight.ttf
|
||||||
|
static/SourceSerif4-Light.ttf
|
||||||
|
static/SourceSerif4-Regular.ttf
|
||||||
|
static/SourceSerif4-Medium.ttf
|
||||||
|
static/SourceSerif4-SemiBold.ttf
|
||||||
|
static/SourceSerif4-Bold.ttf
|
||||||
|
static/SourceSerif4-ExtraBold.ttf
|
||||||
|
static/SourceSerif4-Black.ttf
|
||||||
|
static/SourceSerif4_18pt-ExtraLight.ttf
|
||||||
|
static/SourceSerif4_18pt-Light.ttf
|
||||||
|
static/SourceSerif4_18pt-Regular.ttf
|
||||||
|
static/SourceSerif4_18pt-Medium.ttf
|
||||||
|
static/SourceSerif4_18pt-SemiBold.ttf
|
||||||
|
static/SourceSerif4_18pt-Bold.ttf
|
||||||
|
static/SourceSerif4_18pt-ExtraBold.ttf
|
||||||
|
static/SourceSerif4_18pt-Black.ttf
|
||||||
|
static/SourceSerif4_36pt-ExtraLight.ttf
|
||||||
|
static/SourceSerif4_36pt-Light.ttf
|
||||||
|
static/SourceSerif4_36pt-Regular.ttf
|
||||||
|
static/SourceSerif4_36pt-Medium.ttf
|
||||||
|
static/SourceSerif4_36pt-SemiBold.ttf
|
||||||
|
static/SourceSerif4_36pt-Bold.ttf
|
||||||
|
static/SourceSerif4_36pt-ExtraBold.ttf
|
||||||
|
static/SourceSerif4_36pt-Black.ttf
|
||||||
|
static/SourceSerif4_48pt-ExtraLight.ttf
|
||||||
|
static/SourceSerif4_48pt-Light.ttf
|
||||||
|
static/SourceSerif4_48pt-Regular.ttf
|
||||||
|
static/SourceSerif4_48pt-Medium.ttf
|
||||||
|
static/SourceSerif4_48pt-SemiBold.ttf
|
||||||
|
static/SourceSerif4_48pt-Bold.ttf
|
||||||
|
static/SourceSerif4_48pt-ExtraBold.ttf
|
||||||
|
static/SourceSerif4_48pt-Black.ttf
|
||||||
|
static/SourceSerif4-ExtraLightItalic.ttf
|
||||||
|
static/SourceSerif4-LightItalic.ttf
|
||||||
|
static/SourceSerif4-Italic.ttf
|
||||||
|
static/SourceSerif4-MediumItalic.ttf
|
||||||
|
static/SourceSerif4-SemiBoldItalic.ttf
|
||||||
|
static/SourceSerif4-BoldItalic.ttf
|
||||||
|
static/SourceSerif4-ExtraBoldItalic.ttf
|
||||||
|
static/SourceSerif4-BlackItalic.ttf
|
||||||
|
static/SourceSerif4_18pt-ExtraLightItalic.ttf
|
||||||
|
static/SourceSerif4_18pt-LightItalic.ttf
|
||||||
|
static/SourceSerif4_18pt-Italic.ttf
|
||||||
|
static/SourceSerif4_18pt-MediumItalic.ttf
|
||||||
|
static/SourceSerif4_18pt-SemiBoldItalic.ttf
|
||||||
|
static/SourceSerif4_18pt-BoldItalic.ttf
|
||||||
|
static/SourceSerif4_18pt-ExtraBoldItalic.ttf
|
||||||
|
static/SourceSerif4_18pt-BlackItalic.ttf
|
||||||
|
static/SourceSerif4_36pt-ExtraLightItalic.ttf
|
||||||
|
static/SourceSerif4_36pt-LightItalic.ttf
|
||||||
|
static/SourceSerif4_36pt-Italic.ttf
|
||||||
|
static/SourceSerif4_36pt-MediumItalic.ttf
|
||||||
|
static/SourceSerif4_36pt-SemiBoldItalic.ttf
|
||||||
|
static/SourceSerif4_36pt-BoldItalic.ttf
|
||||||
|
static/SourceSerif4_36pt-ExtraBoldItalic.ttf
|
||||||
|
static/SourceSerif4_36pt-BlackItalic.ttf
|
||||||
|
static/SourceSerif4_48pt-ExtraLightItalic.ttf
|
||||||
|
static/SourceSerif4_48pt-LightItalic.ttf
|
||||||
|
static/SourceSerif4_48pt-Italic.ttf
|
||||||
|
static/SourceSerif4_48pt-MediumItalic.ttf
|
||||||
|
static/SourceSerif4_48pt-SemiBoldItalic.ttf
|
||||||
|
static/SourceSerif4_48pt-BoldItalic.ttf
|
||||||
|
static/SourceSerif4_48pt-ExtraBoldItalic.ttf
|
||||||
|
static/SourceSerif4_48pt-BlackItalic.ttf
|
||||||
|
|
||||||
|
Get started
|
||||||
|
-----------
|
||||||
|
|
||||||
|
1. Install the font files you want to use
|
||||||
|
|
||||||
|
2. Use your app's font picker to view the font family and all the
|
||||||
|
available styles
|
||||||
|
|
||||||
|
Learn more about variable fonts
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
|
||||||
|
https://variablefonts.typenetwork.com
|
||||||
|
https://medium.com/variable-fonts
|
||||||
|
|
||||||
|
In desktop apps
|
||||||
|
|
||||||
|
https://theblog.adobe.com/can-variable-fonts-illustrator-cc
|
||||||
|
https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
|
||||||
|
|
||||||
|
Online
|
||||||
|
|
||||||
|
https://developers.google.com/fonts/docs/getting_started
|
||||||
|
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
|
||||||
|
https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
|
||||||
|
|
||||||
|
Installing fonts
|
||||||
|
|
||||||
|
MacOS: https://support.apple.com/en-us/HT201749
|
||||||
|
Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
|
||||||
|
Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
|
||||||
|
|
||||||
|
Android Apps
|
||||||
|
|
||||||
|
https://developers.google.com/fonts/docs/android
|
||||||
|
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
Please read the full license text (OFL.txt) to understand the permissions,
|
||||||
|
restrictions and requirements for usage, redistribution, and modification.
|
||||||
|
|
||||||
|
You can use them in your products & projects – print or digital,
|
||||||
|
commercial or otherwise.
|
||||||
|
|
||||||
|
This isn't legal advice, please consider consulting a lawyer and see the full
|
||||||
|
license for all details.
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in new issue
Block a user