feat: Add Source Serif 4 and Fractul font families and integrate them across the admin UI.

This commit is contained in:
pradeepkumar
2026-02-11 03:22:06 +05:30
parent 4bdb9fe1f7
commit 3dd98d137e
99 changed files with 829 additions and 454 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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">
&larr; Back to Profile Sections &larr; 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'} &bull; Order: {ats.sortOrder} {ats.isRequired ? 'Required' : 'Optional'} &bull; 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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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);
} }

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>
); );
} }

View File

@@ -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>
); );

View File

@@ -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.

View File

@@ -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 arent 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.