/* Exported promotion-detail composition, backed by persisted promotion snapshots. */ (function(){ const {useState,useEffect,useRef}=React; const money=c=>c==null?'—':'$'+(c/100).toFixed(2); const date=s=>s?String(s).slice(0,10).split('-').reverse().join('/'):'—'; const ACTION={publish:['Publish','Publish this promotion? It writes prices or rules to the register sync feed.'],pause:['Pause','Pause it? The registers stop applying it until you resume.'],resume:['Resume'],endEarly:['End early','End it now? Prices revert on the registers and it cannot be resumed.'],extend:['Extend'],cancel:['Cancel','Cancel it? It will not start.'],startNow:['Start now','Start today instead of the scheduled date?'],rerun:['Run it again'],edit:['Edit'],discard:['Discard','Discard this draft?']}; const API_ACTION={endEarly:'end',startNow:'start-now'}; const CHANNELS={pos:'Register & receipt',esl:'Electronic shelf labels',ticket:'Printed tickets',cfd:'Customer display',online:'Online & click-collect',cat:'Catalogue export',prompt:'Staff prompt at the till'}; const Fact=({label,children})=>
{label}{children}
; const Card=({title,children})=>
{title}
{children}
; function Detail(){ const {screenState={},setScreen,setScreenState,pushToast}=window.useOffice();const id=screenState.promotionId; const [d,setD]=useState(null),[error,setError]=useState(null),[busy,setBusy]=useState(false),[loading,setLoading]=useState(true),[extendTo,setExtendTo]=useState(''); const inFlight=useRef(false),mounted=useRef(false),currentId=useRef(id);currentId.current=id; useEffect(()=>{mounted.current=true;return()=>{mounted.current=false;};},[]); useEffect(()=>{let alive=true;setD(null);setError(null);setLoading(true);if(!id){setError('No promotion selected.');setLoading(false);return;} window.OfficeAPI.promotion(id).then(value=>{if(alive){if(!value)throw Error('Promotion not found.');setD(value);setExtendTo(value.endsOn);}}).catch(e=>{if(alive)setError(e.message||"Couldn't load this promotion.");}).finally(()=>{if(alive)setLoading(false);});return()=>{alive=false;}; },[id]); const act=async key=>{ if(inFlight.current||!d?.actions?.includes(key))return; if(key==='edit'||key==='rerun'){setScreenState(s=>({...s,promotionEditId:key==='edit'?id:null,promotionRerunOf:key==='rerun'?id:null}));setScreen('promotionNew');return;} if(key==='extend'&&(!extendTo||extendTo<=d.endsOn)){setError('Pick a later end date first.');return;} if(ACTION[key]?.[1]&&!window.confirm(ACTION[key][1]))return; inFlight.current=true;setBusy(true);setError(null);const actionId=id; try{ if(key==='discard'){await window.OfficeAPI.discardPromotion(id);if(mounted.current&¤tId.current===actionId){pushToast?.({kind:'ok',text:'Draft discarded.'});setScreen('promotions');}} else{await window.OfficeAPI.promotionAction(id,API_ACTION[key]||key,key==='extend'?{endsOn:extendTo}:undefined);const fresh=await window.OfficeAPI.promotion(id);if(mounted.current&¤tId.current===actionId){setD(fresh);setExtendTo(fresh.endsOn);pushToast?.({kind:'ok',text:(ACTION[key]?.[0]||key)+' — done.'});}} }catch(e){if(mounted.current&¤tId.current===actionId)setError(e.message||"That didn't work.");} finally{inFlight.current=false;if(mounted.current)setBusy(false);} }; const lines=d?.lines||[],holds=d?.tillHolds,channels=d?.channels||['pos']; return

{d?.name||'Promotion'}

{d&&<>{d.state[0].toUpperCase()+d.state.slice(1)}{d.where==='price'?'Shelf price':'Basket rule'}}
{d&&
{d.id} · {date(d.startsOn)} to {date(d.endsOn)} · {d.siteName||d.siteId}
}
{d&&
{d.actions?.includes('extend')&&setExtendTo(e.target.value)} style={{width:150}}/>}{(d.actions||[]).map(key=>)}
}
{loading&&
Loading promotion…
}{error&&
{error}
}{d&&
{d.say}
{d.where==='price'?'A promotional unit price in the register pricing profile.':'A basket rule evaluated when the qualifying quantity is bought.'}
{d.mechanicLabel}{d.scopeLabel}{lines.length}{d.where==='price'?'A price the register receives':'A rule the register runs'}{date(d.startsOn)} – {date(d.endsOn)}
{d.exclusions?.length>0&&
Selected exclusions: {d.exclusions.join(', ')}. Mandatory exclusions are also enforced at publication.
}{d.why&&
{d.why}
}
{d.where==='price'?'The promotional override expires or is removed. Registers use the shelf price in their current pricing profile; the pre-promotion snapshot is not written back.':'The basket rule stops being evaluated when its window ends or it is disabled. No unit price needs to revert.'}
{d.funded&&
{d.funded.supplier}{d.funded.ref||'—'}{money(d.funded.perCents)} per unit
Documented claims and eligible sales are shown in Supplier funding. This saved funding rate alone does not establish a claim value.
}
What the register holds
Read back from the tables the tills sync. This does not confirm delivery to an individual till.
{holds?
{(d.where==='price'?holds.profilesWithPromoPrice:holds.profilesInGroup)??'—'}{d.where==='basket'&&<>{holds.pricingGroup??'—'}{holds.rule?(holds.rule.isActive?'active':'inactive'):'not written'}{holds.rule&&<>{holds.rule.quantityA} for {money(holds.rule.bundlePriceCents)}{holds.rule.startDate||'—'} → {holds.rule.endDate||'—'}}}{d.publishedAt||'not yet'}
:
Register diagnostics are unavailable.
}
{d.state==='draft'?'Nothing has been written yet. Edit the draft to review its current scope and exclusions before publishing.':'These are the saved publication lines. They are historical snapshots, not the effective prices for a different date.'}
{lines.length>0?<>
{['Line','Was','Promo','Margin','Against the market','Note'].map(h=>
{h}
)}{lines.map(line=>
{line.name}{line.sku}
{money(line.beforeCents)}
{line.promoCents==null?(d.where==='basket'?'at till':'—'):money(line.promoCents)}
{d.where==='basket'?'No unit price to compare':'Not in the saved snapshot'}
{d.where==='basket'?d.say:'Published price'}
)}
Cost and competitor observations were not stored with these lines; historical margins and market comparisons are unavailable.
:
No published lines.
}
{Object.entries(CHANNELS).map(([key,label])=>
{label}
)}
Saved channel selections; print tickets separately. Delivery and display playback are not confirmed here.
{d.prompt&&
Staff prompt at the till
“{d.prompt}”
}
}
; } window.OFFICE_SCREENS=Object.assign(window.OFFICE_SCREENS||{},{promotionDetail:Detail}); })();