193 lines
9.5 KiB
TypeScript
193 lines
9.5 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { Layout } from '../components/Layout/Layout';
|
|
import { Settings, Key, Database, Palette, Save } from 'lucide-react';
|
|
|
|
export const SystemSettings: React.FC = () => {
|
|
const [activeTab, setActiveTab] = useState<'users' | 'api' | 'automation' | 'backup' | 'branding'>('users');
|
|
|
|
return (
|
|
<Layout>
|
|
<div>
|
|
<h1 className="text-3xl font-bold text-gray-900 mb-6">System Settings</h1>
|
|
|
|
<div className="flex gap-6">
|
|
{/* Sidebar */}
|
|
<div className="w-64 bg-white rounded-lg shadow-sm border border-gray-200 p-4">
|
|
<nav className="space-y-1">
|
|
{[
|
|
{ id: 'users', label: 'User & Roles', icon: <Settings className="w-4 h-4" /> },
|
|
{ id: 'api', label: 'API Keys', icon: <Key className="w-4 h-4" /> },
|
|
{ id: 'automation', label: 'n8n Connections', icon: <Settings className="w-4 h-4" /> },
|
|
{ id: 'backup', label: 'Backup/Restore', icon: <Database className="w-4 h-4" /> },
|
|
{ id: 'branding', label: 'Branding', icon: <Palette className="w-4 h-4" /> },
|
|
].map(tab => (
|
|
<button
|
|
key={tab.id}
|
|
onClick={() => setActiveTab(tab.id as any)}
|
|
className={`w-full flex items-center gap-2 px-4 py-3 rounded-lg transition-colors ${
|
|
activeTab === tab.id
|
|
? 'bg-primary-600 text-white'
|
|
: 'text-gray-700 hover:bg-gray-100'
|
|
}`}
|
|
>
|
|
{tab.icon}
|
|
<span>{tab.label}</span>
|
|
</button>
|
|
))}
|
|
</nav>
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div className="flex-1 bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
|
{activeTab === 'users' && (
|
|
<div>
|
|
<h2 className="text-lg font-semibold text-gray-900 mb-4">User & Role Management</h2>
|
|
<div className="space-y-4">
|
|
<div>
|
|
<h3 className="font-medium text-gray-900 mb-2">Permissions Matrix</h3>
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full text-sm">
|
|
<thead className="bg-gray-50">
|
|
<tr>
|
|
<th className="px-4 py-2 text-left">Role</th>
|
|
<th className="px-4 py-2 text-center">View</th>
|
|
<th className="px-4 py-2 text-center">Edit</th>
|
|
<th className="px-4 py-2 text-center">Delete</th>
|
|
<th className="px-4 py-2 text-center">Admin</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{['Employee', 'Manager', 'HR', 'Payroll', 'Admin'].map(role => (
|
|
<tr key={role} className="border-t">
|
|
<td className="px-4 py-2 font-medium">{role}</td>
|
|
<td className="px-4 py-2 text-center">
|
|
<input type="checkbox" defaultChecked className="rounded" />
|
|
</td>
|
|
<td className="px-4 py-2 text-center">
|
|
<input type="checkbox" defaultChecked={['Manager', 'HR', 'Admin'].includes(role)} className="rounded" />
|
|
</td>
|
|
<td className="px-4 py-2 text-center">
|
|
<input type="checkbox" defaultChecked={role === 'Admin'} className="rounded" />
|
|
</td>
|
|
<td className="px-4 py-2 text-center">
|
|
<input type="checkbox" defaultChecked={role === 'Admin'} className="rounded" />
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{activeTab === 'api' && (
|
|
<div>
|
|
<h2 className="text-lg font-semibold text-gray-900 mb-4">API Keys</h2>
|
|
<div className="space-y-4">
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">OCR API Key</label>
|
|
<div className="flex gap-2">
|
|
<input type="password" className="flex-1 px-3 py-2 border border-gray-300 rounded-lg" defaultValue="••••••••••••" />
|
|
<button className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300">Show</button>
|
|
<button className="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700">Regenerate</button>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">LLM API Key</label>
|
|
<div className="flex gap-2">
|
|
<input type="password" className="flex-1 px-3 py-2 border border-gray-300 rounded-lg" defaultValue="••••••••••••" />
|
|
<button className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300">Show</button>
|
|
<button className="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700">Regenerate</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{activeTab === 'automation' && (
|
|
<div>
|
|
<h2 className="text-lg font-semibold text-gray-900 mb-4">n8n Connections</h2>
|
|
<div className="space-y-4">
|
|
<div className="p-4 bg-gray-50 rounded-lg">
|
|
<div className="flex items-center justify-between mb-2">
|
|
<span className="font-medium">Email Workflow</span>
|
|
<span className="px-2 py-1 bg-green-100 text-green-800 rounded text-xs">Active</span>
|
|
</div>
|
|
<p className="text-sm text-gray-600">n8n workflow URL: https://n8n.company.com/webhook/email</p>
|
|
</div>
|
|
<div className="p-4 bg-gray-50 rounded-lg">
|
|
<div className="flex items-center justify-between mb-2">
|
|
<span className="font-medium">SMS Workflow</span>
|
|
<span className="px-2 py-1 bg-green-100 text-green-800 rounded text-xs">Active</span>
|
|
</div>
|
|
<p className="text-sm text-gray-600">n8n workflow URL: https://n8n.company.com/webhook/sms</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{activeTab === 'backup' && (
|
|
<div>
|
|
<h2 className="text-lg font-semibold text-gray-900 mb-4">Backup & Restore</h2>
|
|
<div className="space-y-4">
|
|
<div className="p-4 bg-gray-50 rounded-lg">
|
|
<div className="flex items-center justify-between mb-2">
|
|
<span className="font-medium">Last Backup</span>
|
|
<span className="text-sm text-gray-600">2 hours ago</span>
|
|
</div>
|
|
<button className="mt-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700">
|
|
Create Backup Now
|
|
</button>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Restore from Backup</label>
|
|
<input type="file" className="w-full px-3 py-2 border border-gray-300 rounded-lg" />
|
|
<button className="mt-2 px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700">
|
|
Restore
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{activeTab === 'branding' && (
|
|
<div>
|
|
<h2 className="text-lg font-semibold text-gray-900 mb-4">Branding</h2>
|
|
<div className="space-y-4">
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Company Logo</label>
|
|
<div className="flex items-center gap-4">
|
|
<div className="w-32 h-32 bg-gray-100 rounded-lg flex items-center justify-center">
|
|
<span className="text-gray-400">Logo</span>
|
|
</div>
|
|
<div>
|
|
<input type="file" className="mb-2" />
|
|
<p className="text-xs text-gray-500">Recommended: 200x200px PNG</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Primary Color</label>
|
|
<input type="color" className="w-32 h-10 rounded" defaultValue="#0ea5e9" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="mt-6 flex justify-end">
|
|
<button className="px-6 py-2 bg-primary-600 text-white rounded-lg font-medium hover:bg-primary-700 flex items-center gap-2">
|
|
<Save className="w-4 h-4" />
|
|
Save Changes
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Layout>
|
|
);
|
|
};
|
|
|
|
|