Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | 40x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x | import { createRoot } from "react-dom/client"; import Tour from "./tour/tour"; import { toggleShadowWhenSticky } from "./market/stickyListingBar"; import type { Step } from "./listing/types"; // returns true if % of truthy values in the array is above the threshold function isCompleted(fields: unknown[], threshold = 0.5): boolean { const completed = fields.filter((isCompleted) => isCompleted); return completed.length / fields.length >= threshold; } export function initTour({ container, steps, onTourStarted, onTourClosed, startTour, }: { container: HTMLElement; steps: Step[]; onTourStarted: () => void; onTourClosed: () => void; startTour: boolean; }) { Iif (!document.contains(container)) { throw Error("initTour container element not found in document."); } Iif (!steps || !steps.length) { throw Error("initTour expects steps array as an argument."); } const root = createRoot(container); root.render( <Tour steps={steps} onTourStarted={onTourStarted} onTourClosed={onTourClosed} startTour={startTour} />, ); } export function initListingTour({ snapName, container, steps, formFields, }: { snapName: string; container: HTMLElement; steps: Step[]; formFields: { title: string; snap_name: string; categories: string[]; video_urls: string[]; images: Array<{ type: string; }>; summary: string; website: string[]; contact: string[]; }; }) { const storageKey = `listing-tour-finished-${snapName}`; // check form fields completed status // truthy value means field is considered completed const completedFields = [ // title is completed if it is different from package name formFields.title !== formFields.snap_name, // category formFields.categories.length, // video formFields.video_urls.length, // icon formFields.images.filter((i) => i.type === "icon").length, // images formFields.images.filter((i) => i.type === "screenshot").length, // banner formFields.images.filter((i) => i.type === "banner").length, // summary is completed if it is different from the title formFields.summary !== formFields.title, // if one of website or contact is filled we consider it completed formFields.website || formFields.contact, ]; const isFormCompleted = isCompleted(completedFields); const isTourFinished = !!( window.localStorage && window.localStorage.getItem(storageKey) === "true" ); // start the tour automatically if form is not completed // (has less than 50% fields filled), and the tour wasn't closed before const startTour = !isFormCompleted && !isTourFinished; const stickyHeader = document.querySelector(".js-sticky-bar"); const onTourClosed = (): void => { // save that tour was seen by user window.localStorage && window.localStorage.setItem(storageKey, "true"); // make header sticky again if (stickyHeader) { stickyHeader.classList.remove("is-static"); } toggleShadowWhenSticky(stickyHeader); }; const onTourStarted = (): void => { Eif (stickyHeader) { stickyHeader.classList.add("is-static"); } }; initTour({ container, steps, onTourStarted, onTourClosed, startTour }); } |