You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor(disputes): deduplicate client/freelancer dispute pages into shared logic
📘 Description
The client and freelancer dispute flows are near-duplicate page pairs, each violating the orchestrator pattern independently:
app/disputes/page.tsx + freelancer/disputes/page.tsx — both call listDisputes() directly inline, manage pagination state by hand, and define an identical inline getTabLabel()/LoadingFallback.
app/disputes/new/page.tsx + freelancer/disputes/new/page.tsx — both call listOrders()/openDispute() directly inline, duplicate an inline validateForm(), and duplicate a ~185-line inline form.
app/disputes/[id]/page.tsx + freelancer/disputes/[id]/page.tsx — both have a fake setTimeout-based comment-submission stub building a DisputeComment object inline, duplicate module-scope formatDate/formatDateTime/toEvidenceUploadItems/InfoRow helpers, and the freelancer version hand-rolls a ~35-line timeline instead of reusing the client version's <DisputeTimeline> component.
✅ Acceptance Criteria
A single useDisputeList, useDisputeForm, and useDisputeDetail hook (or equivalent) is shared by both the client and freelancer variants — no duplicated data-fetching/pagination/validation logic between the two
formatDate, formatDateTime, toEvidenceUploadItems, InfoRow, getTabLabel, LoadingFallback each exist in exactly one place, imported by both flows
freelancer/disputes/[id]/page.tsx uses the existing <DisputeTimeline> component instead of a hand-rolled inline timeline
The fake setTimeout comment-submission stub is replaced with a real API call (or, if the backend endpoint doesn't exist yet, filed as its own follow-up issue and linked here — do not ship a fake network call disguised as real in either page)
npx tsc --noEmit, npx eslint, npx vitest run, and npm run build all stay clean
Compare app/disputes/[id]/page.tsx (uses <DisputeTimeline>) against freelancer/disputes/[id]/page.tsx (doesn't) for the reference component to reuse.
📋 Additional Notes
Part of the frontend architecture cleanup milestone, not a Tranche 2 paid deliverable. If the comment-submission backend endpoint doesn't exist, note that as a discovered gap rather than silently leaving the stub in place.
🔧 Title:
refactor(disputes): deduplicate client/freelancer dispute pages into shared logic
📘 Description
The client and freelancer dispute flows are near-duplicate page pairs, each violating the orchestrator pattern independently:
app/disputes/page.tsx+freelancer/disputes/page.tsx— both calllistDisputes()directly inline, manage pagination state by hand, and define an identical inlinegetTabLabel()/LoadingFallback.app/disputes/new/page.tsx+freelancer/disputes/new/page.tsx— both calllistOrders()/openDispute()directly inline, duplicate an inlinevalidateForm(), and duplicate a ~185-line inline form.app/disputes/[id]/page.tsx+freelancer/disputes/[id]/page.tsx— both have a fakesetTimeout-based comment-submission stub building aDisputeCommentobject inline, duplicate module-scopeformatDate/formatDateTime/toEvidenceUploadItems/InfoRowhelpers, and the freelancer version hand-rolls a ~35-line timeline instead of reusing the client version's<DisputeTimeline>component.✅ Acceptance Criteria
useDisputeList,useDisputeForm, anduseDisputeDetailhook (or equivalent) is shared by both the client and freelancer variants — no duplicated data-fetching/pagination/validation logic between the twoformatDate,formatDateTime,toEvidenceUploadItems,InfoRow,getTabLabel,LoadingFallbackeach exist in exactly one place, imported by both flowsfreelancer/disputes/[id]/page.tsxuses the existing<DisputeTimeline>component instead of a hand-rolled inline timelinesetTimeoutcomment-submission stub is replaced with a real API call (or, if the backend endpoint doesn't exist yet, filed as its own follow-up issue and linked here — do not ship a fake network call disguised as real in either page)npx tsc --noEmit,npx eslint,npx vitest run, andnpm run buildall stay clean🔧 Context AI
app/disputes/[id]/page.tsx(uses<DisputeTimeline>) againstfreelancer/disputes/[id]/page.tsx(doesn't) for the reference component to reuse.📋 Additional Notes
Part of the frontend architecture cleanup milestone, not a Tranche 2 paid deliverable. If the comment-submission backend endpoint doesn't exist, note that as a discovered gap rather than silently leaving the stub in place.