1import{useState,useEffect,useMemo}from"preact/hooks";import{html}from"htm/preact";import{dispatchStepEvent}from"onboarding-dispatch-event";import{useStorage}from"onboarding-use-storage";import{useRequiredStepData}from"onboarding-use-required-step-data";import{ONBOARDING_STORAGE_KEYS,ONBOARDING_EVENTS,CTA_GROUPS}from"onboarding-step-constants";export function App({sectionSettings:e,blockSettings:t,stepId:l,sectionId:o}){const r=e.namespace||"onboarding",s=useRequiredStepData(t,r),i=useMemo((()=>t.filter((e=>"cta"===e._type&&!1!==s[e._id]))),[t,s]);if(0===i.length)throw new Error("Embedded quiz question template requires at least one CTA that passes visibility rules.");const n=useMemo((()=>t.find((e=>"text"===e._type&&"title"===e.key))),[t]),a=useMemo((()=>t.find((e=>"color_picker"===e._type&&"textColor"===e.key))),[t]),d=a?.value||"#530c18",[p]=useStorage(r,ONBOARDING_STORAGE_KEYS.STEP_TREES),[c]=useStorage(r,ONBOARDING_STORAGE_KEYS.RECOMMENDATIONS_RESULT),[g,m]=useState((()=>{const e=`${l}_${o}`;if(p&&p.steps&&p.steps[e]&&p.steps[e].selectionHistory)return p.steps[e].selectionHistory.map((e=>e.blockId));const t=i.find((e=>e.is_selected));return t&&t._id?[t._id]:[]}));useEffect((()=>{const e=`${l}_${o}`;p&&p.steps&&p.steps[e]&&p.steps[e].selectionHistory&&m(p.steps[e].selectionHistory.map((e=>e.blockId)))}),[p,l,o]);const u=e=>g.includes(e),x=i.filter((e=>(e.cta_group||CTA_GROUPS.PRIMARY)===CTA_GROUPS.PRIMARY));if(0===x.length)throw new Error("Embedded quiz question template requires at least one primary CTA.");const _=e=>{const t=!1!==e.allow_toggle,r=u(e._id);let s;if(t&&r)s=g.filter((t=>t!==e._id));else{s=[...g.filter((e=>{const t=i.find((t=>t._id===e));return(t?.cta_group||CTA_GROUPS.PRIMARY)!==CTA_GROUPS.PRIMARY})),e._id]}m(s);const n=["decaf","flavor","roast_level"],a=e.recommendations?.some((e=>n.includes(e.field))),d=e.advance_on_click&&(!c||!a);dispatchStepEvent(t&&r?{eventType:ONBOARDING_EVENTS.CTA_UNSELECTED,selectedBlockIds:s,stepId:l,stepDataKey:ONBOARDING_STORAGE_KEYS.STEP_DATA,sectionId:o}:d?{eventType:ONBOARDING_EVENTS.CTA_NAVIGATE,selectedBlockIds:s,triggeringBlockId:e._id,stepId:l,stepDataKey:ONBOARDING_STORAGE_KEYS.STEP_DATA,sectionId:o,nextStepId:e["next-step-id"]}:{eventType:ONBOARDING_EVENTS.CTA_SELECTED,selectedBlockIds:s,stepId:l,stepDataKey:ONBOARDING_STORAGE_KEYS.STEP_DATA,sectionId:o})},f=i.filter((e=>(e.cta_group||CTA_GROUPS.PRIMARY)===CTA_GROUPS.SECONDARY)),E=x.some((e=>e.image));return html` 2 <div 3 class="flex flex-col justify-start items-center w-full px-4 py-15 md:py-25 lg:py-30" 4 > 5 <!-- Title --> 6 <div class="w-full max-w-[362px] md:max-w-[600px] text-center pb-10"> 7 <h1 8 class="w-full font-serif text-display-36 md:text-display-40 text-center" 9 style="color: ${d}" 10 > 11 ${n?.value||"Quiz Question"} 12 </h1> 13 </div> 14 15 <!-- Primary CTAs --> 16 <div 17 class="w-full max-w-[362px] md:max-w-[438px] ${E?"lg:max-w-none":""} flex flex-col ${E?"lg:flex-row":""} gap-4 md:gap-6 ${E?"lg:gap-[28.918px] lg:justify-center":""}" 18 > 19 ${x.map((e=>(e=>{const t=u(e._id),l=e.image,o=e.description;return l?html` 20 <div class="w-full lg:w-auto"> 21 <div 22 class="flex lg:flex-col items-center lg:items-center gap-[14px] lg:gap-[18px] rounded-2xl lg:rounded-20 cursor-pointer h-[148px] lg:h-[300px] w-full lg:max-w-[256px] bg-white ${t?"border-2 border-charcoal-600":"border border-[rgba(37,37,37,0.25)] lg:border-[rgba(37,37,37,0.15)] hover:border-[rgba(37,37,37,0.33)]"} transition-all duration-150 pl-4 pr-6 py-6 lg:pt-8 lg:px-6 lg:pb-0" 23 onClick=${()=>_(e)} 24 > 25 <div 26 class="overflow-hidden shrink-0 w-[139.394px] md:w-[151.515px] lg:w-[200px] h-[92px] md:h-[100px] lg:h-[132px]" 27 > 28 <img 29 class="w-full h-full object-contain select-none pointer-events-none" 30 src=${e.image} 31 draggable=${!1} 32 onDragStart=${e=>e.preventDefault()} 33 onSelectStart=${e=>e.preventDefault()} 34 /> 35 </div> 36 <div 37 class="flex flex-col gap-3 lg:gap-4 grow lg:grow-0 lg:items-center lg:text-center" 38 > 39 <h2 40 class="font-semibold text-[20px] leading-[1.1] tracking-[-0.4px]" 41 style="color: ${d}" 42 > 43 ${e.title||""} 44 </h2> 45 ${o?html` 46 <p 47 class="text-body-16 lg:leading-[1.4] lg:w-[212.066px]" 48 style="color: ${d}" 49 dangerouslySetInnerHTML=${{__html:(r=e.description,r&&"string"==typeof r&&r.includes("GRIND_TYPE_FOR_BREW_METHOD")?r.replace("GRIND_TYPE_FOR_BREW_METHOD","cold brew"):r).replace(/<\/?p>/g,"")}} 50 ></p> 51 `:""} 52 </div> 53 </div> 54 </div> 55 `:html` 56 <div class="w-full"> 57 <div 58 class="flex items-center px-6 rounded-2xl cursor-pointer h-[80px] w-full bg-white ${t?"border-2 border-charcoal-600":"border border-[rgba(37,37,37,0.15)] hover:border-[rgba(37,37,37,0.33)]"} transition-all duration-150" 59 onClick=${()=>_(e)} 60 > 61 <p 62 class="font-normal text-[16px] leading-[1.5]" 63 style="color: ${d}" 64 > 65 ${e.title||""} 66 </p> 67 </div> 68 </div> 69 `;var r})(e)))} 70 </div> 71 72 <!-- Secondary CTAs (e.g., "I'm not sure" link) --> 73 ${f.length>0?html` 74 <div class="w-full max-w-[362px] md:max-w-[438px] mt-6"> 75 ${f.map((e=>html` 76 <a 77 href="#" 78 class="text-[16px] font-normal leading-[27.938px] underline decoration-solid cursor-pointer block text-center" 79 style="color: ${d}; text-decoration-skip-ink: none; text-underline-offset: 40%;" 80 onClick=${t=>{t.preventDefault(),_(e)}} 81 > 82 ${e.title||""} 83 </a> 84 `))} 85 </div> 86 `:""} 87 </div> 88 `}
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.