A calendar can make a screen appear to have a booking function. The selected date and time still need a path into a request and an established acceptance result. I reread the form source and replacement-engine conditions, then distilled those states into a small module.

The executable example accepts no real bookings. It explains what the code checks, what a server integration still needs and how an unknown result is retained. The criterion keeps visible completion wording within the evidence actually available.

Date selection and acceptance are separate stages

The inspected booking source contains a calendar and time controls alongside validation, a busy state, server-result checking and failure messages. The replacement engine prevents actual acceptance in preview and checks connection preparation before an enabled release. A visible calendar is not treated as a completed acceptance function.

I distinguish selected values, a request being sent and a request accepted by the server. An acceptance response does not automatically establish final appointment confirmation or email delivery. Availability policy and delivery outcomes need their own evidence.

Pass the business calendar and allowed times explicitly

The replacement engine allows project-specific time slots and a booking horizon. The new module receives minimum and maximum dates, allowed times and a business-calendar current date and cutoff. It also checks calendar validity rather than treating a nonexistent date as an ordinary in-range value.

An international website should not automatically treat the visitor’s computer date as the business’s calendar. Actual operation establishes the business timezone and server policy, then connects selection and revalidation to those values. The example uses fixed synthetic dates rather than actual availability.

Distinguish invalid input from an unconnected service

An unselected date or time differs from a missing acceptance adapter. One needs input correction; the other needs an honest statement that no service is connected. The new function validates the choice, then returns an unconnected state without sending anything when the adapter is absent.

The example acknowledgement requires actual boolean true rather than a truthy string. That is an illustrative input condition, not a completed legal consent form. Personal-data fields and notices belong to the actual site’s separate design. This module handles dates and times without collecting or transmitting personal data.

Manage repeat activation during and after acceptance

The current form disables its action during processing and checks an explicit server acceptance condition before completion UI. The new module also prevents another call while busy and requires an explicit reset after acceptance before a new example request. Activation alone does not create a completion state.

This client guard is not server deduplication or a capacity reservation. Actual operation needs request identity, server duplicate handling and current availability reviewed together. The example identifier connects local states and is not linked to a real booking store.

A lost response needs resolution before another send

The server may process a request while its response is lost. Treating every communication failure as non-acceptance and resending can create a duplicate. The new module distinguishes explicit rejection from an unknown outcome and blocks a new send or reset while uncertain.

Application needs a status lookup using the same request identifier to establish acceptance or rejection. This function’s reconciliation method requires that matching identifier and an explicit result but does not perform the lookup. The example button supplies a synthetic lookup result rather than claiming a real server observation.

Implementation connecting choice to request state

The code checks a choice policy and updates state from an injected adapter. It contains no actual endpoint or recipient configuration. The integration responsible for networking and personal data needs a reviewed server contract. Publishing code in an article is separate from enabling customer bookings.

Twelve checks used a synthetic calendar and local adapters: choice validation, elapsed time, missing connection, repeated activation and acceptance timing, explicit rejection and lost response, invalid acceptance values, identifier reconciliation, input copying, reset after acceptance and invalid policy. These are not actual booking, email or browser-calendar tests.

Explore the implementation

JavaScript · From date choice to request outcome

function validDate(value){
 if(typeof value!=='string'||!/^\d{4}-\d{2}-\d{2}$/.test(value))return false;
 const d=new Date(value+'T00:00:00Z');return Number.isFinite(d.valueOf())&&d.toISOString().slice(0,10)===value;
}
export function validateBookingChoice(choice,policy){
 if(!validDate(policy?.minDate)||!validDate(policy?.maxDate)||policy.minDate>policy.maxDate||!Array.isArray(policy.timeSlots)||policy.timeSlots.some(x=>!/^([01]\d|2[0-3]):[0-5]\d$/.test(x)))throw new TypeError('Valid business-calendar policy required');
 if((policy.businessToday!==undefined||policy.cutoffTime!==undefined)&&(!validDate(policy.businessToday)||typeof policy.cutoffTime!=='string'||!/^([01]\d|2[0-3]):[0-5]\d$/.test(policy.cutoffTime)))throw new TypeError('Valid paired business-date and cutoff required');
 const issues=[];
 if(!validDate(choice?.date)||choice.date<policy.minDate||choice.date>policy.maxDate)issues.push('date');
 if(!policy.timeSlots.includes(choice?.time))issues.push('time');
 if(choice?.date===policy.businessToday&&typeof policy.cutoffTime==='string'&&choice.time<=policy.cutoffTime)issues.push('elapsed-time');
 if(choice?.agreed!==true)issues.push('agreement');
 return [...new Set(issues)];
}
export function createBookingFlow({policy,send,notify=()=>{},makeId=()=>crypto.randomUUID()}){
 let status='idle',request=null,issues=[],busy=false;
 const snapshot=()=>({status,requestId:request?.id||null,issues:[...issues],busy});
 function update(next){status=next;notify(snapshot());return snapshot();}
 return {snapshot,
  async submit(choice){
   if(busy||status==='uncertain'||status==='accepted')return snapshot();
   issues=validateBookingChoice(choice,policy);if(issues.length)return update('invalid');
   if(typeof send!=='function')return update('unconnected');
   const requestId=makeId();if(typeof requestId!=='string'||!requestId.trim())throw new TypeError('Request identifier required');
   request={id:requestId,date:choice.date,time:choice.time,agreed:true};
   busy=true;update('submitting');
   try{
    const result=await send({...request});
    if(result?.ok===true&&result.accepted===true)status='accepted';
    else if(result?.rejected===true&&result.accepted===false)status='rejected';
    else status='uncertain';
   }catch{status='uncertain';}
   finally{busy=false;notify(snapshot());}
   return snapshot();
  },
  reconcile(result){
   if(status!=='uncertain'||result?.requestId!==request?.id)throw new Error('Matching uncertain request required');
   if(result.accepted===true)return update('accepted');
   if(result.accepted===false&&result.rejected===true)return update('rejected');
   throw new Error('Authoritative acceptance or rejection required');
  },
  reset(){if(busy||status==='uncertain')throw new Error('Resolve the outstanding result first');request=null;issues=[];return update('idle');}
 };
}

An example with unconnected and simulated outcomes

The example uses synthetic dates and times in May 2030. It is implemented with unconnected, simulated acceptance, simulated rejection and simulated response loss options. No real acceptance, email or personal-data transmission occurs. The chosen condition determines processing and whether another run is permitted.

Publication checks inspect the execution frame and script syntax, not actual desktop or mobile calendar and button interaction. Contact on this website remains email. The booking module is reusable implementation material for a separate reviewed server integration when needed.