PageSourceSearch

https://www.talktomedi.com/site/inbound-timeline.mjs

js talktomedi.com collected 2026-10-04 03:10:05 UTC 5,704 bytes, 79 lines download raw bytes

1// Illustrative clinic workflows, not live activity or processing-speed claims.
2export const inboundParallelCalls=[7,3,5,14,9];
3export const inboundTasks = [
4  {id:'answer',action:`Answer ${inboundParallelCalls[0]} incoming calls`,detail:'Family practice + specialty clinics',working:'In parallel…',result:`${inboundParallelCalls[0]} answered`},
5  {id:'booking',action:'Book 3 new appointments',detail:'Match provider, visit type and availability',working:'Finding times…',result:'3 booked'},
6  {id:'reschedule',action:'Reschedule 2 visits',detail:'Keep the right provider and duration',working:'Updating times…',result:'2 rescheduled'},
7  {id:'intake',action:'Complete 1 pain-clinic intake',detail:'Pain history and prior treatments',working:'Taking intake…',result:'Saved to EMR'},
8  {id:'specialty',action:'Forward a dermatology referral',detail:'To the referral department',working:'Routing request…',result:'Forwarded'},
9  {id:'billing',action:'Answer a specialty billing question',detail:'Clinic-approved consultation fees',working:'Checking fees…',result:'Patient informed'}
10];
11export const clamp=(value,min=0,max=1)=>Math.max(min,Math.min(max,value));
12export const ease=value=>{const t=clamp(value);return t*t*(3-2*t);};
13export const inboundCycleMs=15000;
14const cadence=2000,firstComplete=2500,completedHold=620,swipeDuration=550,archiveFade=200,shiftDuration=540,arrivalGap=1000;
15// Accelerate all the way out: a slow lead-in followed by a fast exit, without a braking tail.
16const swipeEase=value=>{const t=clamp(value);return t*t*t;};
17const completeAt=index=>firstComplete+index*cadence;
18const clearAt=index=>completeAt(index)+completedHold+swipeDuration+archiveFade;
19const enterAt=index=>index<3?index*arrivalGap:clearAt(index-3);
20const restartFade=500,restartAt=inboundCycleMs-restartFade;
21
22// Fill 1 → 2 → 3, replace the oldest row three times without resizing,
23// then drain 3 → 2 → 1. Hold the empty one-row space briefly before the next fade-in.
24export function inboundFrame(elapsedMs,staticMode=false){
25  const elapsed=Math.max(0,elapsedMs),cycle=Math.floor(elapsed/inboundCycleMs),time=elapsed%inboundCycleMs;
26  const startingNext=!staticMode&&time>=restartAt;
27  const displayCycle=cycle+(startingNext?1:0),parallelCalls=inboundParallelCalls[displayCycle%inboundParallelCalls.length];
28  const shift=index=>ease((time-clearAt(index))/shiftDuration);
29  const rows=inboundTasks.map((originalTask,index)=>{
30    const task=index===0?{...originalTask,action:`Answer ${parallelCalls} incoming calls`,result:`${parallelCalls} answered`}:originalTask;
31    // The last row clears at 13.87s; wait 630ms, then fade the first in over 500ms.
32    // Keep it visible across the clock boundary rather than entering twice.
33    if(!staticMode&&index===0&&time>=restartAt)return {...task,open:ease((time-restartAt)/restartFade),position:0,
34      archive:0,taskOpacity:1,state:'working',doneProgress:0,title:task.action,status:task.working};
35    const birth=enterAt(index),age=time-birth,finish=completeAt(index),clear=clearAt(index);
36    const present=age>=0&&time<clear;
37    const entry=index===0?1:ease(age/shiftDuration);
38    const swipe=(time-finish-completedHold)/swipeDuration;
39    const archive=staticMode?0:swipeEase(swipe);
40    const open=staticMode?1:present?entry*(1-ease((time-clear+archiveFade)/archiveFade)):0;
41    const done=staticMode||time>=finish;
42    const position=index-inboundTasks.slice(0,index).reduce((sum,_,previous)=>sum+shift(previous),0);
43    return {...task,open,position:staticMode?index:position,
44      archive,
45      // Follow distance, so the row stays readable through the slow start and
46      // dissolves during the fast departure instead of fading before it moves.
47      taskOpacity:staticMode?1:1-ease((archive-.08)/.92),
48      state:!present&&!staticMode?'waiting':done?'done':'working',
49      doneProgress:staticMode?1:ease((time-finish)/300),
50      title:task.action,status:done?task.result:task.working};
51  });
52  // Keep one row of space at the handoff; the window never contracts to its header.
53  const heightRows=staticMode?inboundTasks.length:1+ease((time-arrivalGap)/shiftDuration)+ease((time-2*arrivalGap)/shiftDuration)
54    -shift(3)-shift(4);
55  const completed=staticMode?inboundTasks.length:startingNext?0:inboundTasks.filter((_,i)=>time>=completeAt(i)).length;
56  const allComplete=completed===inboundTasks.length;
57  const heading=allComplete?'MEDI · All tasks complete':`MEDI · ${parallelCalls} calls in parallel`;
58  return {rows,heightRows,completed,cycle,parallelCalls,allComplete,heading};
59}
60
61// Distances are viewport-height percentages. Keep the first card's travel;
62// give outbound and messaging a longer expansion and a brief settled interval.
63export const deckScenes=[
64  {expand:22,hold:0,exit:50},
65  {expand:30,hold:6,exit:50},
66  {expand:30,hold:20,exit:0}
67].map((scene,index,scenes)=>({...scene,start:scenes.slice(0,index).reduce((sum,s)=>sum+s.expand+s.hold+s.exit,0)}));
68export const deckTravelVh=deckScenes.reduce((sum,s)=>sum+s.expand+s.hold+s.exit,0);
69export const deckAnchors=deckScenes.map(scene=>scene.start/deckTravelVh);
70export function deckFrame(progress){
71  const travel=clamp(progress)*deckTravelVh;
72  const arrivals=deckScenes.map(scene=>ease((travel-scene.start)/scene.expand));
73  const [first,second]=deckScenes.slice(0,2).map(scene=>ease((travel-scene.start-scene.expand-scene.hold)/scene.exit));
74  // Each card settles at 96.5%, then has its own short expansion before leaving.
75  const scales=[.965+.035*arrivals[0]-.035*first,
76    .94+.025*first+.035*arrivals[1]-.035*second,
77    .88+.06*first+.025*second+.035*arrivals[2]];
78  return {arrivals,scales,first,second,active:first<.82?0:second<.82?1:2};
79}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.