diff --git a/packages/journey-manager/src/index.ts b/packages/journey-manager/src/index.ts index 11818b40..7687abd7 100644 --- a/packages/journey-manager/src/index.ts +++ b/packages/journey-manager/src/index.ts @@ -112,7 +112,12 @@ export const run = async (props: RunProps): Promise => { // ----- Set up UI ----- await dom.contentLoaded(); - const ui = createUi(props.ui, client, findActiveTriggers); + const ui = createUi( + props.config.conversationId, + props.ui, + client, + findActiveTriggers, + ); // --- Set up Digression detection --- const checkForDigressions = prepareDigression(triggers, () => { diff --git a/packages/journey-manager/src/ui/components/index.tsx b/packages/journey-manager/src/ui/components/index.tsx index a1d9395c..1b6146e9 100644 --- a/packages/journey-manager/src/ui/components/index.tsx +++ b/packages/journey-manager/src/ui/components/index.tsx @@ -248,7 +248,11 @@ interface PinBubbleProps { const PinBubble: FC = ({ isActive, content, onClick }) => (
{content}
-
); +const nudgeStateLocalStorageKey = (conversationId: string): string => { + return `jb-nudge-state-${conversationId}`; +}; + +type NudgeState = "visible" | "hidden" | "dismissed"; + +const saveNudgeState = ( + conversationId: string, + nudgeState: NudgeState, +): void => { + localStorage.setItem(nudgeStateLocalStorageKey(conversationId), nudgeState); +}; + +const retrieveNudgeState = (conversationId: string): NudgeState => { + const val = localStorage.getItem(nudgeStateLocalStorageKey(conversationId)); + if (val === "visible") { + return "visible"; + } + if (val === "dismissed") { + return "dismissed"; + } + return "hidden"; +}; + export const ControlCenter: FC<{ config: UiConfig; + conversationId: string; client: Client; triggeredSteps: TriggeredStep[]; digression: boolean; highlightElements: HTMLElement[]; -}> = ({ config, client, triggeredSteps, highlightElements, digression }) => { - const [hasBeenOpened, setHasBeenOpened] = useState(false); - const [isOpen, setIsOpen] = useState(false); +}> = ({ + config, + client, + conversationId, + triggeredSteps, + highlightElements, + digression, +}) => { + const [isOpen, setIsOpen] = useState(); const drawerContentRef = useRef(null); const drawerDialogRef = useRef(null); - const [isNudgeVisible, setIsNudgeVisible] = useState(false); + const [nudgeState, setNudgeState] = useState( + retrieveNudgeState(conversationId), + ); useEffect(() => { - if (isOpen) setHasBeenOpened(true); + if (isOpen) { + setNudgeState("dismissed"); + } }, [isOpen]); useEffect(() => { - if (hasBeenOpened || config.nudgeContent == null) { - setIsNudgeVisible(false); + saveNudgeState(conversationId, nudgeState); + }, [nudgeState, conversationId]); + + useEffect(() => { + if (config.nudgeContent == null) { return; } - - let hideTimeout: null | NodeJS.Timeout = null; - const showTimeout = setTimeout(() => { - setIsNudgeVisible(true); - hideTimeout = setTimeout(() => { - setIsNudgeVisible(false); - }, config.nudgeHideAfterMs ?? 20000); - }, config.nudgeShowAfterMs ?? 3000); - return () => { - clearTimeout(showTimeout); - if (hideTimeout) clearTimeout(hideTimeout); - }; + if (nudgeState === "hidden") { + const showTimeout = setTimeout(() => { + setNudgeState("visible"); + }, config.nudgeShowAfterMs ?? 3000); + return () => { + clearTimeout(showTimeout); + }; + } else if (nudgeState === "visible") { + const hideTimeout = setTimeout( + () => { + setNudgeState("dismissed"); + }, + (config.nudgeHideAfterMs ?? 20000) - (config.nudgeShowAfterMs ?? 3000), + ); + return () => { + clearTimeout(hideTimeout); + }; + } }, [ config.nudgeContent, config.nudgeShowAfterMs, config.nudgeHideAfterMs, - hasBeenOpened, + nudgeState, + setNudgeState, ]); const onPreviousStep = config.onPreviousStep @@ -322,9 +371,9 @@ export const ControlCenter: FC<{ <> { - setIsNudgeVisible(false); + setNudgeState("dismissed"); }} content={config.nudgeContent ?? ""} /> diff --git a/packages/journey-manager/src/ui/custom-element.tsx b/packages/journey-manager/src/ui/custom-element.tsx index ae5218a9..a38f0f50 100644 --- a/packages/journey-manager/src/ui/custom-element.tsx +++ b/packages/journey-manager/src/ui/custom-element.tsx @@ -10,6 +10,7 @@ import type { UiConfig, TriggeredStep } from "../configuration"; export default class JourneyManagerElement extends HTMLElement { private _shadowRoot: ShadowRoot | null = null; private _client: Client | null = null; + private _conversationId: string | null = null; private _triggeredSteps: TriggeredStep[] | null = null; private _config: UiConfig | null = null; private _digression: boolean = false; @@ -41,6 +42,14 @@ export default class JourneyManagerElement extends HTMLElement { this.render(); } + /** + * Conversation ID + */ + set conversationId(value: string) { + this._conversationId = value; + this.render(); + } + /** * Set triggered steps */ @@ -65,6 +74,7 @@ export default class JourneyManagerElement extends HTMLElement { if ( this._config == null || this._client == null || + this._conversationId == null || this._triggeredSteps == null ) { return; @@ -74,6 +84,7 @@ export default class JourneyManagerElement extends HTMLElement { config={this._config} digression={this._digression} client={this._client} + conversationId={this._conversationId} triggeredSteps={this._triggeredSteps} highlightElements={this._highlightElements} />, diff --git a/packages/journey-manager/src/ui/index.tsx b/packages/journey-manager/src/ui/index.tsx index 62a9c116..fe7bb68f 100644 --- a/packages/journey-manager/src/ui/index.tsx +++ b/packages/journey-manager/src/ui/index.tsx @@ -20,6 +20,7 @@ export interface Ui { } const create = ( + conversationId: string, config: UiConfig | undefined, client: Client, findActiveTriggers: ( @@ -40,6 +41,7 @@ const create = ( uiElement.style.zIndex = "1000"; uiElement.config = config; uiElement.client = client; + uiElement.conversationId = conversationId; document.body.appendChild(uiElement); const updateHighlights = config.highlights diff --git a/packages/journey-manager/src/ui/style.css b/packages/journey-manager/src/ui/style.css index 0125d6bf..eec34200 100644 --- a/packages/journey-manager/src/ui/style.css +++ b/packages/journey-manager/src/ui/style.css @@ -315,6 +315,11 @@ button { display: flex; flex-direction: column; gap: 20px; + padding: 0 20px; +} + +.confirmation p { + text-align: center; } .confirmation-buttons {