Treat the input as an incomplete scheduling proposal
The WHATWG local date and time input state does not include time-zone-offset information. Pair the draft with an explicitly selected or service-supplied zone before submission, but do not use the browser value to decide availability or an appointment instant.
Keep the appointment ID, current revision, and a new client request token with the pending request. The trusted service must decide whether that identified appointment can move and return the confirmed zoned representation with the token it received. React's useReducer reference is useful for keeping related state transitions together; it does not provide the booking contract.
Accept only the current service response
The small model represents editing, missing zone, missing request token, missing identity, checking, confirmed, and unavailable states. Require a nonempty appointment ID, revision, and client request token before checking availability. Editing the draft clears a pending request, and a response is accepted only when appointment ID, revision, token, and service-supplied zoned time satisfy the current pending request:
function reduce(state, action) {
if (action.type === "drafted") {
return { ...state, draftLocal: action.local, draftZone: action.zone,
pending: null, status: "editing" };
}
if (action.type === "submitted" && !action.requestId) {
return { ...state, status: "needs-request-token" };
}
if (action.type === "submitted" &&
(!action.appointmentId || !action.revision)) {
return { ...state, status: "needs-identity" };
}
if (action.type === "confirmed" && state.pending &&
action.appointmentId === state.pending.appointmentId &&
action.revision === state.pending.revision &&
action.requestId === state.pending.requestId && action.zonedTime) {
return { ...state, pending: null, status: "confirmed",
confirmed: { appointmentId: action.appointmentId,
revision: action.revision, zonedTime: action.zonedTime } };
}
return state;
}
The complete dependency-free model exercises the same transition shape:
node --test sites/reactjsx.com/evidence/P138/reschedule-state.test.mjs
Its result is not browser-tested JSX. An illustrative status region might communicate a returned state without moving focus:
<p role="status">The requested time is no longer available. Choose another time.</p>
ARIA22 describes using role=status for ordinary status messages. Test the delivered UI with the browsers and assistive technologies that matter to the operation.
Keep uncertainty and recovery visible
While the service is checking, identify the appointment and requested time rather than showing a success message. If the draft changes, invalidate the previous pending request. A same-revision re-submit needs a new client request token, and the service must echo it with the result. If the service returns unavailable, preserve the draft where policy permits and offer a safe next step. Ignore a late response that does not match the current request token. Only render a confirmed state from the service result that matches the current request.
For stale field validation, see Ignore Stale Async Validation Results in React. For a save conflict, see Preserve a React Draft After a Current Save Conflict.
Can this form reserve or reschedule an appointment?
No. The service must enforce eligibility, availability, policy, and authorization. The interface only represents the result for the identified request.