1import { useState, useEffect } from 'react';
2import { useNavigate, useParams } from 'react-router-dom';
3import MainLayout from '../components/Layout/MainLayout';
4// import removed: TenantSelector
5import '../styles/forms.css';
6import './CustomerForm.css';
7import { apiFetch } from '../lib/api';
8import { notifySuccess, notifyError } from '../utils/notifications';
10function CustomerForm() {
11 const navigate = useNavigate();
12 const { id } = useParams();
13 const [selectedTenantId, setSelectedTenantId] = useState('');
14 const [isRootTenant, setIsRootTenant] = useState(false);
15 const [tenants, setTenants] = useState([]);
31 const [form, setForm] = useState(defaultForm);
32 const [loading, setLoading] = useState(false);
33 const [error, setError] = useState('');
36 // Check if user is root tenant
37 const token = localStorage.getItem('token');
40 const payload = token.split('.')[1];
41 const decoded = JSON.parse(atob(payload.replace(/-/g, '+').replace(/_/g, '/')));
42 const userTenantId = decoded.tenant_id || decoded.tenantId || '';
43 setIsRootTenant(userTenantId === '00000000-0000-0000-0000-000000000001');
45 console.error('Error decoding token:', e);
49 async function fetchCustomer() {
54 const res = await apiFetch(`/customers/${id}`, { method: 'GET', credentials: 'include' });
55 if (!res.ok) throw new Error('Failed to load customer');
56 const data = await res.json();
57 const cust = data.customer || data || {};
58 if (cust.tenant_id && !selectedTenantId) {
59 setSelectedTenantId(String(cust.tenant_id));
61 const normalized = Object.keys(defaultForm).reduce((acc, key) => {
62 acc[key] = cust[key] ?? defaultForm[key];
68 setError(err.message || 'Failed to load customer');
77 // Fetch tenants list for root tenant
81 const res = await apiFetch('/tenants', { method: 'GET' });
83 const data = await res.json();
84 setTenants(data.tenants || []);
87 console.error('Error fetching tenants:', err);
93 const handleSubmit = async (e) => {
98 if (!form.name?.trim()) {
99 setError('Company name is required');
105 const res = await apiFetch(`/customers${id ? `/${id}` : ''}`, {
106 method: id ? 'PUT' : 'POST',
107 headers: { 'Content-Type': 'application/json' },
108 credentials: 'include',
109 body: JSON.stringify(form),
112 const data = await res.json();
115 const errorMsg = data.error || 'Failed to save customer';
116 await notifyError('Save Failed', errorMsg);
117 throw new Error(errorMsg);
120 await notifySuccess(id ? 'Customer Updated' : 'Customer Created', `Customer has been ${id ? 'updated' : 'created'} successfully`);
121 navigate('/customers');
124 setError(err.message || 'Failed to save customer');
132 <div className="page-content">
133 <div className="page-header">
134 <h2>{id ? 'Edit Customer' : 'Create Customer'}</h2>
137 {error && <div className="error-message">{error}</div>}
140 <form onSubmit={handleSubmit} className="form-container">
141 <div className="form-grid">
142 <div className="form-section">
143 <h3>Basic Information</h3>
146 <div className="form-row">
147 <div className="form-field">
148 <label>Tenant</label>
150 value={form.tenant_id}
151 onChange={(e) => setForm({ ...form, tenant_id: e.target.value })}
153 <option value="">Select Tenant</option>
154 {tenants.map(tenant => (
155 <option key={tenant.tenant_id} value={tenant.tenant_id}>
160 <span className="field-hint">Assign this customer to a specific tenant (Root only)</span>
165 <div className="form-row">
166 <div className="form-field">
167 <label>Company Name<span className="required">*</span></label>
171 onChange={(e) => setForm({ ...form, name: e.target.value })}
174 <span className="field-hint">Required - The name of the company or organization</span>
176 <div className="form-field">
177 <label>Status</label>
178 <select value={form.status} onChange={(e) => setForm({ ...form, status: e.target.value })}>
179 <option value="active">Active</option>
180 <option value="inactive">Inactive</option>
182 <span className="field-hint">Defaults to Active if not specified</span>
187 <div className="form-section">
188 <h3>Contact Information</h3>
189 <div className="form-row">
190 <div className="form-field">
191 <label>Contact Name</label>
194 value={form.contact_name}
195 onChange={(e) => setForm({ ...form, contact_name: e.target.value })}
197 <span className="field-hint">Primary contact person's name</span>
199 <div className="form-field">
204 onChange={(e) => setForm({ ...form, email: e.target.value })}
207 <div className="form-field">
212 onChange={(e) => setForm({ ...form, phone: e.target.value })}
216 <div className="form-row">
217 <div className="form-field">
218 <label>Billing Email</label>
221 value={form.billing_email}
222 onChange={(e) => setForm({ ...form, billing_email: e.target.value })}
224 <span className="field-hint">Email address for invoices and billing communications</span>
229 <div className="form-section">
231 <div className="form-row">
232 <div className="form-field">
233 <label>Street Address</label>
237 onChange={(e) => setForm({ ...form, address: e.target.value })}
241 <div className="form-row">
242 <div className="form-field">
247 onChange={(e) => setForm({ ...form, city: e.target.value })}
250 <div className="form-field">
251 <label>State/Province</label>
255 onChange={(e) => setForm({ ...form, state: e.target.value })}
258 <div className="form-field">
259 <label>Postal Code</label>
262 value={form.postal_code}
263 onChange={(e) => setForm({ ...form, postal_code: e.target.value })}
267 <div className="form-row">
268 <div className="form-field">
269 <label>Country</label>
273 onChange={(e) => setForm({ ...form, country: e.target.value })}
279 <div className="form-section">
280 <h3>Additional Information</h3>
281 <div className="form-field">
285 onChange={(e) => setForm({ ...form, notes: e.target.value })}
288 <span className="field-hint">Any additional notes or comments about the customer</span>
293 <div className="form-actions">
294 <button type="submit" disabled={loading} className="btn">
295 {loading ? 'Saving...' : (<><span className="material-symbols-outlined">save</span> Save</>)}
297 <button type="button" className="btn" onClick={() => navigate('/customers')}>
298 <span className="material-symbols-outlined">close</span> Cancel
307export default CustomerForm;