fix: crash bugs in TeamInvoices + faster load
Bug fixes: - TeamInvoices: add useAuth import/currentUser (invoice-create crash) - TeamInvoices: setChartYear -> setExportYear (year-dropdown crash) - TeamDashboard: drop redundant setState-in-effect (cascading renders) - Companies: delete dead _UnusedClientCompanies (illegal hook calls) - annotate intentional empty PDF-fallback catches Load speed: - preconnect/dns-prefetch to Supabase origin - lazy-load heic-to in Converters: page chunk 2737KB -> 9KB - split recharts into its own 'charts' vendor chunk Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+21
-14
@@ -1,13 +1,14 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useParams, Link, useNavigate } from 'react-router-dom';
|
||||
import Layout from '../components/Layout';
|
||||
import PageLoader from '../components/PageLoader';
|
||||
import StatusBadge from '../components/StatusBadge';
|
||||
import { supabase } from '../lib/supabase';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { serviceTypes } from '../data/mockData';
|
||||
import { cleanupTaskStorage, deleteCompanyData } from '../lib/deleteHelpers';
|
||||
import { logActivity } from '../lib/activityLog';
|
||||
import { createProjectFolder } from '../lib/filebrowserFolders';
|
||||
import { ensureProjectFolder, renameCompanyFolder } from '../lib/folderSync';
|
||||
|
||||
export default function CompanyDetail() {
|
||||
const { id } = useParams();
|
||||
@@ -78,8 +79,14 @@ export default function CompanyDetail() {
|
||||
if (!nameVal.trim()) return;
|
||||
setSavingName(true);
|
||||
const oldName = company.name;
|
||||
await supabase.from('companies').update({ name: nameVal.trim() }).eq('id', id);
|
||||
setCompany(c => ({ ...c, name: nameVal.trim() }));
|
||||
const newName = nameVal.trim();
|
||||
await supabase.from('companies').update({ name: newName }).eq('id', id);
|
||||
try {
|
||||
await renameCompanyFolder({ companyId: id, oldName, newName });
|
||||
} catch (folderError) {
|
||||
console.error('Company folder rename failed:', folderError);
|
||||
}
|
||||
setCompany(c => ({ ...c, name: newName }));
|
||||
setEditingName(false);
|
||||
setSavingName(false);
|
||||
};
|
||||
@@ -179,8 +186,12 @@ export default function CompanyDetail() {
|
||||
status: 'active',
|
||||
}).select().single();
|
||||
if (data) {
|
||||
try {
|
||||
await ensureProjectFolder({ projectId: data.id });
|
||||
} catch (folderError) {
|
||||
console.error('Project folder sync failed:', folderError);
|
||||
}
|
||||
logActivity({ actorId: currentUser.id, actorName: currentUser.name, action: 'project_created', projectId: data.id, projectName: data.name });
|
||||
createProjectFolder(company.name, data.name).catch(() => {});
|
||||
setProjects(prev => [data, ...prev]);
|
||||
setNewProjectName('');
|
||||
setShowNewProject(false);
|
||||
@@ -248,7 +259,7 @@ export default function CompanyDetail() {
|
||||
setSavingSignFamilyPrice(null);
|
||||
};
|
||||
|
||||
if (loading) return <Layout><p style={{ padding: 24, color: 'var(--text-muted)' }}>Loading...</p></Layout>;
|
||||
if (loading) return <Layout><PageLoader /></Layout>;
|
||||
if (!company) return <Layout><p>Company not found.</p></Layout>;
|
||||
|
||||
const activeTasks = tasks.filter(t => t.status !== 'client_approved');
|
||||
@@ -318,15 +329,14 @@ export default function CompanyDetail() {
|
||||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<div style={{ display: 'flex', gap: 4, marginBottom: 24, flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', gap: 4, marginBottom: 10, flexWrap: 'wrap', minHeight: 'var(--btn-height)' }}>
|
||||
{(isTeam ? ['users', 'projects', 'pricing'] : ['users', 'projects']).map(t => (
|
||||
<button
|
||||
key={t}
|
||||
onClick={() => setTab(t)}
|
||||
className={`tab-btn${tab === t ? ' active' : ''}`}
|
||||
style={{ textTransform: 'capitalize' }}
|
||||
className={`section-tab-btn${tab === t ? ' is-active' : ''}`}
|
||||
>
|
||||
{t}
|
||||
{t.charAt(0).toUpperCase() + t.slice(1)}
|
||||
{t === 'users' && availableUsers.length > 0 && (
|
||||
<span style={{ marginLeft: 6, fontSize: 10, background: tab === t ? 'rgba(0,0,0,0.3)' : 'var(--danger)', color: 'white', padding: '1px 5px', borderRadius: 4, fontWeight: 400 }}>
|
||||
{availableUsers.length}
|
||||
@@ -342,7 +352,7 @@ export default function CompanyDetail() {
|
||||
<div className="card">
|
||||
<div className="card-title">Assigned Users</div>
|
||||
{users.length === 0 ? (
|
||||
<p style={{ fontSize: 13, color: 'var(--text-muted)' }}>No users assigned to this company yet.</p>
|
||||
<div className="card-empty-center">No users</div>
|
||||
) : (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
|
||||
{users.map((user, i) => (
|
||||
@@ -494,10 +504,7 @@ export default function CompanyDetail() {
|
||||
)}
|
||||
|
||||
{projects.length === 0 ? (
|
||||
<div className="empty-state">
|
||||
<h3>No projects yet</h3>
|
||||
<p>Create a project to start adding jobs.</p>
|
||||
</div>
|
||||
<div className="card card-empty-center">No projects</div>
|
||||
) : (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||
{projects.map(project => {
|
||||
|
||||
Reference in New Issue
Block a user