Auto-save intake data to server after every step
Intake data now persists to DB after each step completion (non-blocking). If browser crashes, data is recoverable from compliance_orders.intake_data. Partial saves (_partial: true) only update intake_data without changing payment_status or marking intake_data_validated. Final submit still triggers the full validation + worker dispatch flow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
beb23d777e
commit
c40dfb552e
2 changed files with 43 additions and 10 deletions
|
|
@ -1758,7 +1758,7 @@ router.get("/api/v1/compliance-orders/my-orders", async (req, res) => {
|
|||
*/
|
||||
router.put("/api/v1/compliance-orders/:id/intake", async (req, res) => {
|
||||
const id = req.params.id;
|
||||
const { intake_data, entity, officers } = req.body ?? {};
|
||||
const { intake_data, entity, officers, _partial } = req.body ?? {};
|
||||
|
||||
if (!intake_data) {
|
||||
res.status(400).json({ error: "intake_data required" });
|
||||
|
|
@ -1798,15 +1798,23 @@ router.put("/api/v1/compliance-orders/:id/intake", async (req, res) => {
|
|||
}
|
||||
|
||||
// Update the order with merged intake data + entity link
|
||||
await pool.query(
|
||||
`UPDATE compliance_orders
|
||||
SET intake_data = $1,
|
||||
payment_status = CASE WHEN payment_status = 'pending_intake' THEN 'paid' ELSE payment_status END,
|
||||
intake_data_validated = TRUE,
|
||||
telecom_entity_id = COALESCE($3, telecom_entity_id)
|
||||
WHERE order_number = $2`,
|
||||
[JSON.stringify(merged), id, telecomEntityId],
|
||||
);
|
||||
// Partial saves (auto-save between steps) only update intake_data, not status
|
||||
if (_partial) {
|
||||
await pool.query(
|
||||
`UPDATE compliance_orders SET intake_data = $1 WHERE order_number = $2`,
|
||||
[JSON.stringify(merged), id],
|
||||
);
|
||||
} else {
|
||||
await pool.query(
|
||||
`UPDATE compliance_orders
|
||||
SET intake_data = $1,
|
||||
payment_status = CASE WHEN payment_status = 'pending_intake' THEN 'paid' ELSE payment_status END,
|
||||
intake_data_validated = TRUE,
|
||||
telecom_entity_id = COALESCE($3, telecom_entity_id)
|
||||
WHERE order_number = $2`,
|
||||
[JSON.stringify(merged), id, telecomEntityId],
|
||||
);
|
||||
}
|
||||
|
||||
// If entity data was provided, update the telecom_entity too
|
||||
if (entity && entity.frn) {
|
||||
|
|
|
|||
|
|
@ -484,12 +484,37 @@ const STEP_LABELS: Record<string, string> = {
|
|||
if (cancelEvt.defaultPrevented) return;
|
||||
if (s.step_index < steps.length - 1) {
|
||||
renderStep(s.step_index + 1);
|
||||
// Auto-save intake data to server after every step (non-blocking)
|
||||
autoSaveIntake(loadState());
|
||||
} else {
|
||||
// Last step — submit the intake data
|
||||
submitIntake(s);
|
||||
}
|
||||
});
|
||||
|
||||
// Auto-save intake data to server after each step (non-blocking, fire-and-forget)
|
||||
function autoSaveIntake(state: IntakeState) {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const token = params.get("token");
|
||||
const orderNumber = state.intake_data?.order_number || params.get("order") || "";
|
||||
const API = (window as any).__PW_API || "";
|
||||
if (!orderNumber || !API) return;
|
||||
|
||||
fetch(`${API}/api/v1/compliance-orders/${orderNumber}/intake`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...(token ? { "Authorization": `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
intake_data: state.intake_data,
|
||||
entity: state.entity,
|
||||
officers: state.officers,
|
||||
_partial: true, // flag that this is an intermediate save, not final
|
||||
}),
|
||||
}).catch(() => {}); // silent — don't block the user
|
||||
}
|
||||
|
||||
async function submitIntake(state: IntakeState) {
|
||||
const nextBtn = document.getElementById("pw-next") as HTMLButtonElement;
|
||||
nextBtn.disabled = true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue