Nest amendments inside parent submission on Requests page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+69
-40
@@ -44,52 +44,81 @@ export default function Requests() {
|
||||
<h3>No requests yet</h3>
|
||||
<p>Client requests will appear here.</p>
|
||||
</div>
|
||||
) : submissions.map(sub => {
|
||||
const task = tasks.find(t => t.id === sub.task_id);
|
||||
const project = projects.find(p => p.id === task?.project_id);
|
||||
const company = companies.find(co => co.id === project?.company_id);
|
||||
) : (() => {
|
||||
// Group by task_id + version_number
|
||||
const groupMap = {};
|
||||
submissions.forEach(sub => {
|
||||
const key = `${sub.task_id}-${sub.version_number}`;
|
||||
if (!groupMap[key]) groupMap[key] = [];
|
||||
groupMap[key].push(sub);
|
||||
});
|
||||
|
||||
return (
|
||||
<div key={sub.id} className="request-card">
|
||||
<div className="request-card-header">
|
||||
<div>
|
||||
<div className="request-card-title">
|
||||
{sub.service_type}
|
||||
{sub.type === 'revision' && (
|
||||
<span className="badge badge-revision" style={{ marginLeft: 8 }}>Revision v{sub.version_number}</span>
|
||||
)}
|
||||
// Sort groups by latest submitted_at descending
|
||||
const groups = Object.values(groupMap).sort((a, b) => {
|
||||
const aMax = Math.max(...a.map(s => new Date(s.submitted_at)));
|
||||
const bMax = Math.max(...b.map(s => new Date(s.submitted_at)));
|
||||
return bMax - aMax;
|
||||
});
|
||||
|
||||
return groups.map(group => {
|
||||
const primary = group.find(s => s.type !== 'amendment') || group[0];
|
||||
const amendments = group.filter(s => s.type === 'amendment');
|
||||
const task = tasks.find(t => t.id === primary.task_id);
|
||||
const project = projects.find(p => p.id === task?.project_id);
|
||||
const company = companies.find(co => co.id === project?.company_id);
|
||||
|
||||
return (
|
||||
<div key={primary.id} className="request-card">
|
||||
<div className="request-card-header">
|
||||
<div>
|
||||
<div className="request-card-title">
|
||||
{primary.service_type}
|
||||
<StatusBadge status={primary.type} />
|
||||
</div>
|
||||
<div className="request-card-meta">
|
||||
From <strong>{primary.submitted_by_name}</strong>
|
||||
{company && (
|
||||
<> · <Link to={`/companies/${company.id}`} className="table-link">{company.name}</Link></>
|
||||
)}
|
||||
{' · '}{new Date(primary.submitted_at).toLocaleDateString()}
|
||||
</div>
|
||||
</div>
|
||||
<div className="request-card-meta">
|
||||
From <strong>{sub.submitted_by_name}</strong>
|
||||
{company && (
|
||||
<> · <Link to={`/companies/${company.id}`} className="table-link">{company.name}</Link></>
|
||||
)}
|
||||
{' · '}{new Date(sub.submitted_at).toLocaleDateString()}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<StatusBadge status={task?.status || 'not_started'} />
|
||||
{task && <Link to={`/tasks/${task.id}`} className="btn btn-outline btn-sm">View Job</Link>}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<StatusBadge status={task?.status || 'not_started'} />
|
||||
{task && <Link to={`/tasks/${task.id}`} className="btn btn-outline btn-sm">View Job</Link>}
|
||||
|
||||
<div style={{ display: 'flex', gap: 24, marginBottom: 12 }}>
|
||||
<div>
|
||||
<span style={{ fontSize: 11, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.5px', color: 'var(--text-muted)' }}>Deadline</span>
|
||||
<div style={{ fontSize: 13, marginTop: 2 }}>{primary.deadline || 'Not specified'}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span style={{ fontSize: 11, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.5px', color: 'var(--text-muted)' }}>Project</span>
|
||||
<div style={{ fontSize: 13, marginTop: 2 }}>
|
||||
{project ? <Link to={`/projects/${project.id}`} className="table-link">{project.name}</Link> : '—'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p style={{ fontSize: 13, color: 'var(--text-secondary)', lineHeight: 1.6, marginBottom: amendments.length > 0 ? 12 : 0 }}>{primary.description}</p>
|
||||
|
||||
{amendments.map(amendment => (
|
||||
<div key={amendment.id} style={{ padding: '12px 14px', background: 'var(--bg)', borderRadius: 8, border: '1px solid var(--border)', marginTop: 8 }}>
|
||||
<div style={{ fontSize: 11, fontWeight: 700, textTransform: 'uppercase', color: 'var(--accent)', marginBottom: 6, letterSpacing: 0.5 }}>
|
||||
Amended Request
|
||||
</div>
|
||||
<div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 6 }}>
|
||||
{amendment.submitted_by_name} · {new Date(amendment.submitted_at).toLocaleDateString()}
|
||||
</div>
|
||||
<p style={{ fontSize: 13, lineHeight: 1.6, color: 'var(--text-secondary)', whiteSpace: 'pre-wrap', margin: 0 }}>{amendment.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 24, marginBottom: 12 }}>
|
||||
<div>
|
||||
<span style={{ fontSize: 11, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.5px', color: 'var(--text-muted)' }}>Deadline</span>
|
||||
<div style={{ fontSize: 13, marginTop: 2 }}>{sub.deadline || 'Not specified'}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span style={{ fontSize: 11, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.5px', color: 'var(--text-muted)' }}>Project</span>
|
||||
<div style={{ fontSize: 13, marginTop: 2 }}>
|
||||
{project ? <Link to={`/projects/${project.id}`} className="table-link">{project.name}</Link> : '—'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p style={{ fontSize: 13, color: 'var(--text-secondary)', lineHeight: 1.6 }}>{sub.description}</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
);
|
||||
});
|
||||
})()}
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user