Refactor: clients → companies schema v2

This commit is contained in:
Krao Hasanee
2026-03-26 23:42:06 -04:00
commit 719209fa25
61 changed files with 8192 additions and 0 deletions
+142
View File
@@ -0,0 +1,142 @@
import { useState } from 'react';
import Layout from '../components/Layout';
import { supabase } from '../lib/supabase';
import { useAuth } from '../context/AuthContext';
export default function Settings() {
const { currentUser } = useAuth();
const [form, setForm] = useState({
name: currentUser?.name || '',
company: currentUser?.company || '',
});
const [passwords, setPasswords] = useState({ current: '', next: '', confirm: '' });
const [profileSaved, setProfileSaved] = useState(false);
const [passwordSaved, setPasswordSaved] = useState(false);
const [passwordError, setPasswordError] = useState('');
const [saving, setSaving] = useState(false);
const [savingPw, setSavingPw] = useState(false);
const set = (field) => (e) => setForm(f => ({ ...f, [field]: e.target.value }));
const setPw = (field) => (e) => setPasswords(p => ({ ...p, [field]: e.target.value }));
const handleProfileSave = async (e) => {
e.preventDefault();
setSaving(true);
await supabase.from('profiles').update({
name: form.name.trim(),
company: form.company.trim(),
}).eq('id', currentUser.id);
setProfileSaved(true);
setSaving(false);
setTimeout(() => setProfileSaved(false), 3000);
};
const handlePasswordSave = async (e) => {
e.preventDefault();
setPasswordError('');
if (passwords.next !== passwords.confirm) { setPasswordError('New passwords do not match.'); return; }
if (passwords.next.length < 6) { setPasswordError('Password must be at least 6 characters.'); return; }
setSavingPw(true);
const { error } = await supabase.auth.updateUser({ password: passwords.next });
if (error) { setPasswordError(error.message); setSavingPw(false); return; }
setPasswords({ current: '', next: '', confirm: '' });
setPasswordSaved(true);
setSavingPw(false);
setTimeout(() => setPasswordSaved(false), 3000);
};
const initials = form.name
.split(' ')
.map(n => n[0])
.join('')
.toUpperCase()
.slice(0, 2);
return (
<Layout>
<div className="page-header">
<div>
<div className="page-title">Profile & Settings</div>
<div className="page-subtitle">Update your name, company, and password.</div>
</div>
</div>
<div style={{ maxWidth: 520, display: 'flex', flexDirection: 'column', gap: 24 }}>
{/* Avatar preview */}
<div className="card" style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
<div className="sidebar-avatar" style={{ width: 56, height: 56, fontSize: 20, flexShrink: 0 }}>
{initials || '?'}
</div>
<div>
<div style={{ fontWeight: 700, fontSize: 15 }}>{form.name || 'Your Name'}</div>
<div style={{ fontSize: 13, color: 'var(--text-secondary)' }}>{currentUser?.email}</div>
<div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2, textTransform: 'capitalize' }}>{currentUser?.role}</div>
</div>
</div>
{/* Profile form */}
<div className="card">
<div className="card-title">Profile Info</div>
<form onSubmit={handleProfileSave}>
<div className="form-group">
<label>Full Name *</label>
<input
type="text"
placeholder="First Last"
value={form.name}
onChange={set('name')}
required
/>
</div>
<div className="form-group">
<label>Company / Organization</label>
<input
type="text"
placeholder="Your company"
value={form.company}
onChange={set('company')}
/>
</div>
<div className="form-group">
<label>Email Address</label>
<input type="email" value={currentUser?.email} disabled style={{ opacity: 0.6, cursor: 'not-allowed' }} />
<div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 4 }}>Contact Fourge to change your email.</div>
</div>
{profileSaved && (
<div className="notification notification-success" style={{ marginBottom: 12 }}> Profile updated.</div>
)}
<button type="submit" className="btn btn-primary" disabled={saving}>
{saving ? 'Saving...' : 'Save Changes'}
</button>
</form>
</div>
{/* Password form */}
<div className="card">
<div className="card-title">Change Password</div>
<form onSubmit={handlePasswordSave}>
<div className="form-group">
<label>New Password *</label>
<input type="password" placeholder="Min. 6 characters" value={passwords.next} onChange={setPw('next')} required />
</div>
<div className="form-group">
<label>Confirm New Password *</label>
<input type="password" placeholder="Repeat new password" value={passwords.confirm} onChange={setPw('confirm')} required />
</div>
{passwordError && (
<div style={{ fontSize: 13, color: 'var(--danger)', marginBottom: 12 }}> {passwordError}</div>
)}
{passwordSaved && (
<div className="notification notification-success" style={{ marginBottom: 12 }}> Password updated.</div>
)}
<button type="submit" className="btn btn-primary" disabled={savingPw}>
{savingPw ? 'Updating...' : 'Update Password'}
</button>
</form>
</div>
</div>
</Layout>
);
}