@tiendanube/live-state 1.0.0-beta.10 → 1.0.0-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`react`);c=s(c,1);let l=require(`swr`);l=s(l,1);let u=require(`@amplitude/analytics-browser`);u=s(u,1);let d=require(`react/jsx-runtime`),f=require(`@nimbus-ds/components`),p=require(`@nimbus-ds/icons`);var m=u.createInstance();function h(e){try{if(!e){console.warn(`[LiveState] Amplitude API key not provided`);return}m.init(e,{defaultTracking:!1})}catch(e){console.warn(`[LiveState] Failed to initialize Amplitude:`,e)}}async function g(e){try{if(window.clarity){console.log(`[LiveState] Clarity already initialized by client`);return}let t=e||_();if(!t){console.warn(`[LiveState] Clarity project ID not provided`);return}(await import(`@microsoft/clarity`)).default.init(t)}catch(e){console.warn(`[LiveState] Failed to initialize Clarity:`,e)}}function _(){try{let e=document.querySelector(`script[src*="clarity.ms"]`);if(e)return e.getAttribute(`src`)?.match(/\/([a-z0-9]+)$/)?.[1];let t=window.clarity?.q?.[0]?.[1];if(typeof t==`string`)return t}catch{}}function v(e,t){try{m.track(e,t)}catch(e){console.warn(`[LiveState] Failed to track Amplitude event:`,e)}}function y(e,t){try{window.clarity&&(window.clarity(`event`,e),t&&Object.entries(t).forEach(([e,t])=>{window.clarity?.(`set`,e,String(t))}))}catch(e){console.warn(`[LiveState] Failed to track Clarity event:`,e)}}function b(e){return Object.fromEntries(Object.entries(e).filter(e=>e[1]!==void 0))}function x(e,t){v(e,t),y(e,t)}var S=(0,c.createContext)(null);function C({children:e,fetcher:t,analytics:n,onEvent:r}){return(0,c.useEffect)(()=>{n?.amplitudeKey&&h(n.amplitudeKey),n?.clarityProjectId&&g(n.clarityProjectId)},[n]),(0,d.jsx)(l.SWRConfig,{value:{provider:()=>new Map},children:(0,d.jsx)(S.Provider,{value:{fetcher:t,analytics:n,onEvent:r},children:e})})}function w(){let e=(0,c.useContext)(S);if(!e)throw Error(`useLiveState must be used within LiveStateProvider`);return e}function T(){let{fetcher:e}=w(),{data:t,error:n,isLoading:r,mutate:i}=(0,l.default)(`live-state`,e,{revalidateOnFocus:!1,revalidateOnReconnect:!0,dedupingInterval:6e4,shouldRetryOnError:!1,onError:e=>{console.warn(`[LiveState] Failed to fetch live state:`,e)}});return{liveState:t??null,isLoading:r,error:n??null,refresh:async()=>{try{await i()}catch(e){console.warn(`[LiveState] Failed to refresh live state:`,e)}}}}function E(){let{onEvent:e}=w();return(0,c.useCallback)((t,n)=>{e?.(t,n),x(t,n)},[e])}var D=`@tiendanube/live-state:closable`,O=D;function k(){try{let e=localStorage.getItem(O);if(!e)return{};let t=JSON.parse(e);if(typeof t!=`object`||!t)return{};let n={};for(let[e,r]of Object.entries(t))if(!(typeof r!=`object`||!r)){n[e]={};for(let[t,i]of Object.entries(r))if(typeof i==`number`)n[e][t]={count:i,closedAt:0};else if(typeof i==`object`&&i){let r=i;n[e][t]={count:typeof r.count==`number`?r.count:0,closedAt:typeof r.closedAt==`number`?r.closedAt:0}}}return n}catch{return{}}}function A(e){try{localStorage.setItem(O,JSON.stringify(e))}catch{}}function j({context:e,id:t,maxCloseTimes:n=3,expiresIn:r}){let[i,a]=(0,c.useState)(null);return(0,c.useEffect)(()=>{if(!t){a(!0);return}let i=k(),o=i[e]?.[t];if(!o){a(!0);return}let{count:s,closedAt:c}=o;if(r!=null&&c>0&&Date.now()-c>r){let n={...i};n[e]&&(delete n[e][t],A(n)),a(!0);return}a(s<n)},[e,t,n,r]),{isVisible:i,close:(0,c.useCallback)(()=>{if(!t)return;let n=k(),r=n[e]?.[t]?.count??0,i={...n,[e]:{...n[e]??{},[t]:{count:r+1,closedAt:Date.now()}}};a(!1),A(i)},[e,t])}}function M(e){try{switch(e.type){case`redirect`:window.location.href=e.url;break;case`whatsapp`:{let t=e.whatsappMessage?`${e.url}?text=${encodeURIComponent(e.whatsappMessage)}`:e.url;window.open(t,`_blank`);break}case`external`:window.open(e.url,`_blank`);break;default:console.warn(`[LiveState] Unknown CTA type: ${e.type}`)}}catch(e){console.warn(`[LiveState] Failed to handle CTA click:`,e)}}function N({data:e,trackingConfig:t,onClose:n,onCtaClick:r}){let i=E(),a=e.type===`alert`?`danger`:`warning`,o=(0,c.useCallback)(()=>b({context:e.context,campaignId:e.campaignId,group:e.group,...e.metadata,...t.properties}),[e,t.properties]),s=(0,c.useCallback)(()=>{i(`${t.prefix}${t.page}_${e.context}_click`,o()),r?r(e.cta):M(e.cta)},[e,t,o,i,r]),l=(0,c.useCallback)(()=>{i(`${t.prefix}${t.page}_${e.context}_close`,o()),n?.()},[n,e,t,o,i]);return(0,c.useEffect)(()=>{i(`${t.prefix}${t.page}_${e.context}_view`,o())},[]),(0,d.jsx)(f.Alert,{appearance:a,title:e.title,onRemove:n?l:void 0,children:(0,d.jsxs)(f.Box,{display:`flex`,alignItems:`flex-start`,gap:`3`,flexWrap:`wrap`,flexDirection:`column`,children:[(0,d.jsx)(f.Box,{flex:`1 1 auto`,minWidth:`220px`,children:(0,d.jsx)(f.Text,{children:e.message})}),(0,d.jsx)(f.Box,{display:`flex`,justifyContent:`flex-end`,marginTop:`2`,children:(0,d.jsx)(f.Button,{appearance:`primary`,onClick:s,children:e.cta.label})})]})})}var P={blue:{background:`#0050C3`,icon:`#FFFFFF`},white:{background:`#FFFFFF`,icon:`#0059D5`}};function F({data:e,trackingConfig:t,defaultVariant:n=`blue`,onClose:r,isMobile:i,onCtaClick:a}){let o=E(),s=e.variant||n,l=P[s],[u,m]=(0,c.useState)(()=>window.innerWidth<750);(0,c.useEffect)(()=>{let e=()=>m(window.innerWidth<750);return window.addEventListener(`resize`,e),()=>window.removeEventListener(`resize`,e)},[]);let h=i??u,g=(0,c.useCallback)(()=>b({context:e.context,campaignId:e.campaignId,group:e.group,...e.metadata,...t.properties}),[e,t.properties]),_=(0,c.useCallback)(()=>{o(`${t.prefix}${t.page}_${e.context}_click`,g()),a?a(e.cta):M(e.cta)},[e,t,g,o,a]),v=(0,c.useCallback)(()=>{o(`${t.prefix}${t.page}_${e.context}_close`,g()),r?.()},[r,e,t,g,o]);(0,c.useEffect)(()=>{o(`${t.prefix}${t.page}_${e.context}_view`,g())},[]);let y=(0,d.jsx)(f.Link,{as:`a`,textDecoration:`none`,onClick:_,"data-testid":`live-state-cta-link`,children:(0,d.jsx)(f.Text,{color:`primary-interactive`,fontSize:`base`,children:e.cta.label})});return(0,d.jsx)(f.Card,{children:(0,d.jsxs)(f.Box,{display:`flex`,flexDirection:`row`,justifyContent:`space-between`,children:[(0,d.jsxs)(f.Box,{display:`flex`,gap:`4`,alignItems:h?`flex-start`:`center`,paddingRight:`1-5`,children:[(0,d.jsx)(f.Box,{minWidth:`32px`,children:(0,d.jsx)(`div`,{style:{width:32,height:32,borderRadius:`35%`,borderColor:s===`white`?`#E7E7E7`:`transparent`,borderWidth:1,borderStyle:`solid`,background:l.background,display:`flex`,alignItems:`center`,justifyContent:`center`},children:(0,d.jsx)(p.MoneyIcon,{style:{color:l.icon}})})}),(0,d.jsxs)(f.Box,{display:`grid`,gap:`2`,children:[(0,d.jsxs)(f.Box,{children:[(0,d.jsx)(f.Text,{fontSize:`base`,color:`neutral-textHigh`,children:e.title}),(0,d.jsx)(f.Text,{fontSize:`base`,color:`neutral-textLow`,children:e.message})]}),h&&y]})]}),(!h||r)&&(0,d.jsxs)(f.Box,{display:`flex`,flexDirection:h?`column`:`row`,alignItems:h?`flex-end`:`center`,gap:`2`,children:[!h&&y,r&&(0,d.jsx)(`button`,{type:`button`,"data-testid":`live-state-close-button`,"aria-label":`Fechar notificação`,onClick:v,style:{background:`none`,border:`none`,padding:0,cursor:`pointer`,display:`flex`,alignItems:`center`,justifyContent:`center`},children:(0,d.jsx)(f.Icon,{source:(0,d.jsx)(p.CloseIcon,{width:`18px`,height:`18px`}),color:`neutral-interactive`})})]})]})})}function I({data:e,loading:t,trackingConfig:n,allowedContexts:r,defaultVariant:i,isMobile:a,onCtaClick:o}){let{isVisible:s,close:c}=j({context:e?.context??``,id:e?.campaignId,maxCloseTimes:e?.metadata?.maxCloseTimes,expiresIn:e?.metadata?.expiresIn});if(t||!e)return null;if(!e.context||!e.type||!e.title||!e.message||!e.cta?.label||!e.cta?.url||!e.cta?.type)return console.warn(`[LiveState] Invalid payload, missing required fields`,e),null;if(r&&!r.includes(e.context)||s===null||!s)return null;let l=e.closable&&e.campaignId?c:void 0;return e.type===`alert`||e.type===`warning`?(0,d.jsx)(N,{data:e,onClose:l,trackingConfig:n,onCtaClick:o}):e.type===`info`?(0,d.jsx)(F,{data:e,onClose:l,trackingConfig:n,defaultVariant:i,isMobile:a,onCtaClick:o}):(console.warn(`[LiveState] Unknown type: ${e.type}`),null)}exports.LIVE_STATE_STORAGE_KEY=D,exports.LiveStateAlert=N,exports.LiveStateInfo=F,exports.LiveStateProvider=C,exports.LiveStateRenderer=I,exports.handleCtaClick=M,exports.trackEvent=x,exports.useLiveState=T,exports.useTrackEvent=E;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`react`);c=s(c,1);let l=require(`swr`);l=s(l,1);let u=require(`@amplitude/analytics-browser`);u=s(u,1);let d=require(`react/jsx-runtime`),f=require(`@nimbus-ds/components`),p=require(`@nimbus-ds/icons`);var m=u.createInstance();function h(e){try{if(!e){console.warn(`[LiveState] Amplitude API key not provided`);return}m.init(e,{defaultTracking:!1})}catch(e){console.warn(`[LiveState] Failed to initialize Amplitude:`,e)}}async function g(e){try{if(window.clarity){console.log(`[LiveState] Clarity already initialized by client`);return}let t=e||_();if(!t){console.warn(`[LiveState] Clarity project ID not provided`);return}(await import(`@microsoft/clarity`)).default.init(t)}catch(e){console.warn(`[LiveState] Failed to initialize Clarity:`,e)}}function _(){try{let e=document.querySelector(`script[src*="clarity.ms"]`);if(e)return e.getAttribute(`src`)?.match(/\/([a-z0-9]+)$/)?.[1];let t=window.clarity?.q?.[0]?.[1];if(typeof t==`string`)return t}catch{}}function v(e,t){try{m.track(e,t)}catch(e){console.warn(`[LiveState] Failed to track Amplitude event:`,e)}}function y(e,t){try{window.clarity&&(window.clarity(`event`,e),t&&Object.entries(t).forEach(([e,t])=>{window.clarity?.(`set`,e,String(t))}))}catch(e){console.warn(`[LiveState] Failed to track Clarity event:`,e)}}function b(e){return Object.fromEntries(Object.entries(e).filter(e=>e[1]!==void 0))}function x(e,t){v(e,t),y(e,t)}var S=(0,c.createContext)(null);function C({children:e,fetcher:t,analytics:n,onEvent:r}){return(0,c.useEffect)(()=>{n?.amplitudeKey&&h(n.amplitudeKey),n?.clarityProjectId&&g(n.clarityProjectId)},[n]),(0,d.jsx)(l.SWRConfig,{value:{provider:()=>new Map},children:(0,d.jsx)(S.Provider,{value:{fetcher:t,analytics:n,onEvent:r},children:e})})}function w(){let e=(0,c.useContext)(S);if(!e)throw Error(`useLiveState must be used within LiveStateProvider`);return e}function T(){let{fetcher:e}=w(),{data:t,error:n,isLoading:r,mutate:i}=(0,l.default)(`live-state`,e,{revalidateOnFocus:!1,revalidateOnReconnect:!0,dedupingInterval:6e4,shouldRetryOnError:!1,onError:e=>{console.warn(`[LiveState] Failed to fetch live state:`,e)}});return{liveState:t??null,isLoading:r,error:n??null,refresh:async()=>{try{await i()}catch(e){console.warn(`[LiveState] Failed to refresh live state:`,e)}}}}function E(){let{onEvent:e}=w();return(0,c.useCallback)((t,n)=>{e?.(t,n),x(t,n)},[e])}var D=`@tiendanube/live-state:closable`,O=D;function k(){try{let e=localStorage.getItem(O);if(!e)return{};let t=JSON.parse(e);if(typeof t!=`object`||!t)return{};let n={};for(let[e,r]of Object.entries(t))if(!(typeof r!=`object`||!r)){n[e]={};for(let[t,i]of Object.entries(r))if(typeof i==`number`)n[e][t]={count:i,closedAt:0};else if(typeof i==`object`&&i){let r=i;n[e][t]={count:typeof r.count==`number`?r.count:0,closedAt:typeof r.closedAt==`number`?r.closedAt:0}}}return n}catch{return{}}}function A(e){try{localStorage.setItem(O,JSON.stringify(e))}catch{}}function j({context:e,id:t,maxCloseTimes:n=3,expiresIn:r}){let[i,a]=(0,c.useState)(null);return(0,c.useEffect)(()=>{if(!t){a(!0);return}let i=k(),o=i[e]?.[t];if(!o){a(!0);return}let{count:s,closedAt:c}=o;if(r!=null&&c>0&&Date.now()-c>r){let n={...i};n[e]&&(delete n[e][t],A(n)),a(!0);return}a(s<n)},[e,t,n,r]),{isVisible:i,close:(0,c.useCallback)(()=>{if(a(!1),!t)return;let n=k(),r=n[e]?.[t]?.count??0;A({...n,[e]:{...n[e]??{},[t]:{count:r+1,closedAt:Date.now()}}})},[e,t])}}function M(e){try{switch(e.type){case`redirect`:window.location.href=e.url;break;case`whatsapp`:{let t=e.whatsappMessage?`${e.url}?text=${encodeURIComponent(e.whatsappMessage)}`:e.url;window.open(t,`_blank`);break}case`external`:window.open(e.url,`_blank`);break;default:console.warn(`[LiveState] Unknown CTA type: ${e.type}`)}}catch(e){console.warn(`[LiveState] Failed to handle CTA click:`,e)}}function N({data:e,trackingConfig:t,onClose:n,onCtaClick:r}){let i=E(),a=e.type===`alert`?`danger`:`warning`,o=(0,c.useCallback)(()=>b({context:e.context,campaignId:e.campaignId,group:e.group,...e.metadata,...t.properties}),[e,t.properties]),s=(0,c.useCallback)(()=>{i(`${t.prefix}${t.page}_${e.context}_click`,o()),r?r(e.cta):M(e.cta)},[e,t,o,i,r]),l=(0,c.useCallback)(()=>{i(`${t.prefix}${t.page}_${e.context}_close`,o()),n?.()},[n,e,t,o,i]);return(0,c.useEffect)(()=>{i(`${t.prefix}${t.page}_${e.context}_view`,o())},[]),(0,d.jsx)(f.Alert,{appearance:a,title:e.title,onRemove:n?l:void 0,children:(0,d.jsxs)(f.Box,{display:`flex`,alignItems:`flex-start`,gap:`3`,flexWrap:`wrap`,flexDirection:`column`,children:[(0,d.jsx)(f.Box,{flex:`1 1 auto`,minWidth:`220px`,children:(0,d.jsx)(f.Text,{children:e.message})}),(0,d.jsx)(f.Box,{display:`flex`,justifyContent:`flex-end`,marginTop:`2`,children:(0,d.jsx)(f.Button,{appearance:`primary`,onClick:s,children:e.cta.label})})]})})}var P={blue:{background:`#0050C3`,icon:`#FFFFFF`},white:{background:`#FFFFFF`,icon:`#0059D5`}};function F({data:e,trackingConfig:t,defaultVariant:n=`blue`,onClose:r,isMobile:i,onCtaClick:a}){let o=E(),s=e.variant||n,l=P[s],[u,m]=(0,c.useState)(()=>window.innerWidth<750);(0,c.useEffect)(()=>{let e=()=>m(window.innerWidth<750);return window.addEventListener(`resize`,e),()=>window.removeEventListener(`resize`,e)},[]);let h=i??u,g=(0,c.useCallback)(()=>b({context:e.context,campaignId:e.campaignId,group:e.group,...e.metadata,...t.properties}),[e,t.properties]),_=(0,c.useCallback)(()=>{o(`${t.prefix}${t.page}_${e.context}_click`,g()),a?a(e.cta):M(e.cta)},[e,t,g,o,a]),v=(0,c.useCallback)(()=>{o(`${t.prefix}${t.page}_${e.context}_close`,g()),r?.()},[r,e,t,g,o]);(0,c.useEffect)(()=>{o(`${t.prefix}${t.page}_${e.context}_view`,g())},[]);let y=(0,d.jsx)(f.Link,{as:`a`,textDecoration:`none`,onClick:_,"data-testid":`live-state-cta-link`,children:(0,d.jsx)(f.Text,{color:`primary-interactive`,fontSize:`base`,children:e.cta.label})});return(0,d.jsx)(f.Card,{children:(0,d.jsxs)(f.Box,{display:`flex`,flexDirection:`row`,justifyContent:`space-between`,children:[(0,d.jsxs)(f.Box,{display:`flex`,gap:`4`,alignItems:h?`flex-start`:`center`,paddingRight:`1-5`,children:[(0,d.jsx)(f.Box,{minWidth:`32px`,children:(0,d.jsx)(`div`,{style:{width:32,height:32,borderRadius:`35%`,borderColor:s===`white`?`#E7E7E7`:`transparent`,borderWidth:1,borderStyle:`solid`,background:l.background,display:`flex`,alignItems:`center`,justifyContent:`center`},children:(0,d.jsx)(p.MoneyIcon,{style:{color:l.icon}})})}),(0,d.jsxs)(f.Box,{display:`grid`,gap:`2`,children:[(0,d.jsxs)(f.Box,{children:[(0,d.jsx)(f.Text,{fontSize:`base`,color:`neutral-textHigh`,children:e.title}),(0,d.jsx)(f.Text,{fontSize:`base`,color:`neutral-textLow`,children:e.message})]}),h&&y]})]}),(!h||r)&&(0,d.jsxs)(f.Box,{display:`flex`,flexDirection:h?`column`:`row`,alignItems:h?`flex-end`:`center`,gap:`2`,children:[!h&&y,r&&(0,d.jsx)(`button`,{type:`button`,"data-testid":`live-state-close-button`,"aria-label":`Fechar notificação`,onClick:v,style:{background:`none`,border:`none`,padding:0,cursor:`pointer`,display:`flex`,alignItems:`center`,justifyContent:`center`},children:(0,d.jsx)(f.Icon,{source:(0,d.jsx)(p.CloseIcon,{width:`18px`,height:`18px`}),color:`neutral-interactive`})})]})]})})}function I({data:e,loading:t,trackingConfig:n,allowedContexts:r,defaultVariant:i,isMobile:a,onCtaClick:o}){let{isVisible:s,close:c}=j({context:e?.context??``,id:e?.campaignId,maxCloseTimes:e?.metadata?.maxCloseTimes,expiresIn:e?.metadata?.expiresIn});if(t||!e)return null;if(!e.context||!e.type||!e.title||!e.message||!e.cta?.label||!e.cta?.url||!e.cta?.type)return console.warn(`[LiveState] Invalid payload, missing required fields`,e),null;if(r&&!r.includes(e.context)||s===null||!s)return null;let l=e.closable?c:void 0;return e.type===`alert`||e.type===`warning`?(0,d.jsx)(N,{data:e,onClose:l,trackingConfig:n,onCtaClick:o}):e.type===`info`?(0,d.jsx)(F,{data:e,onClose:l,trackingConfig:n,defaultVariant:i,isMobile:a,onCtaClick:o}):(console.warn(`[LiveState] Unknown type: ${e.type}`),null)}exports.LIVE_STATE_STORAGE_KEY=D,exports.LiveStateAlert=N,exports.LiveStateInfo=F,exports.LiveStateProvider=C,exports.LiveStateRenderer=I,exports.handleCtaClick=M,exports.trackEvent=x,exports.useLiveState=T,exports.useTrackEvent=E;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/utils/analytics.ts","../src/providers/LiveStateProvider.tsx","../src/hooks/useLiveState.ts","../src/hooks/useTrackEvent.ts","../src/utils/closable-storage.ts","../src/hooks/useClosable.ts","../src/utils/cta.ts","../src/components/LiveStateAlert.tsx","../src/components/LiveStateInfo.tsx","../src/components/LiveStateRenderer.tsx"],"sourcesContent":["import * as amplitude from '@amplitude/analytics-browser';\nimport type { TrackingProperties, TrackingValue } from '../types';\n\n/**\n * Isolated Amplitude instance for the lib — avoids conflicts with the\n * consumer app's own Amplitude instance when both coexist on the same page.\n */\nconst amplitudeInstance = amplitude.createInstance();\n\n/**\n * Initialize Amplitude (fail silently)\n */\nexport function initializeAmplitude(apiKey: string): void {\n try {\n if (!apiKey) {\n console.warn('[LiveState] Amplitude API key not provided');\n return;\n }\n\n amplitudeInstance.init(apiKey, {\n defaultTracking: false,\n });\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Amplitude:', error);\n }\n}\n\n/**\n * Initialize Clarity (fail silently)\n */\nexport async function initializeClarity(projectId?: string): Promise<void> {\n try {\n // Check if Clarity is already loaded by the client\n if (window.clarity) {\n console.log('[LiveState] Clarity already initialized by client');\n return;\n }\n\n // If client provided project ID, use it\n const finalProjectId = projectId || getClientClarityProjectId();\n\n if (!finalProjectId) {\n console.warn('[LiveState] Clarity project ID not provided');\n return;\n }\n\n // Initialize Clarity with project ID\n const Clarity = (await import('@microsoft/clarity')).default;\n Clarity.init(finalProjectId);\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Clarity:', error);\n }\n}\n\n/**\n * Try to extract Clarity project ID from client's installation\n */\nfunction getClientClarityProjectId(): string | undefined {\n try {\n // Check if Clarity script tag exists\n const clarityScript = document.querySelector('script[src*=\"clarity.ms\"]');\n if (clarityScript) {\n const src = clarityScript.getAttribute('src');\n const match = src?.match(/\\/([a-z0-9]+)$/);\n return match?.[1];\n }\n\n // Check global clarity config: shape is clarity.q = [['init', projectId, ...]]\n const projectId = window.clarity?.q?.[0]?.[1];\n if (typeof projectId === 'string') {\n return projectId;\n }\n } catch {\n // Fail silently\n }\n\n return undefined;\n}\n\n/**\n * Track event with Amplitude (fail silently)\n */\nexport function trackAmplitudeEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n amplitudeInstance.track(eventName, properties);\n } catch (error) {\n console.warn('[LiveState] Failed to track Amplitude event:', error);\n }\n}\n\n/**\n * Track event with Clarity (fail silently)\n */\nexport function trackClarityEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n if (window.clarity) {\n window.clarity('event', eventName);\n\n // Set custom tags for properties\n if (properties) {\n Object.entries(properties).forEach(([key, value]) => {\n window.clarity?.('set', key, String(value));\n });\n }\n }\n } catch (error) {\n console.warn('[LiveState] Failed to track Clarity event:', error);\n }\n}\n\n/**\n * Builds a TrackingProperties object from a loose record, dropping entries\n * whose value is undefined so callers don't need to guard optional fields.\n */\nexport function buildTrackingProperties(\n source: Record<string, TrackingValue | undefined>,\n): TrackingProperties {\n return Object.fromEntries(\n Object.entries(source).filter(\n (entry): entry is [string, TrackingValue] => entry[1] !== undefined,\n ),\n );\n}\n\n/**\n * Track event with both Amplitude and Clarity (fail silently)\n */\nexport function trackEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n trackAmplitudeEvent(eventName, properties);\n trackClarityEvent(eventName, properties);\n}\n\n/**\n * Clarity command API shape as documented in the Clarity SDK\n * https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-api\n */\ntype ClarityCommand =\n | 'init'\n | 'event'\n | 'set'\n | 'identify'\n | 'consent'\n | 'upgrade';\n\ndeclare global {\n interface Window {\n clarity?: {\n (command: ClarityCommand, ...args: string[]): void;\n q?: string[][];\n };\n }\n}\n","import React, { createContext, useContext, useEffect } from 'react';\nimport { SWRConfig } from 'swr';\nimport type {\n LiveStateFetcher,\n AnalyticsConfig,\n TrackingProperties,\n} from '../types';\nimport { initializeAmplitude, initializeClarity } from '../utils/analytics';\n\ninterface LiveStateContextValue {\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\nconst LiveStateContext = createContext<LiveStateContextValue | null>(null);\n\nexport interface LiveStateProviderProps {\n children: React.ReactNode;\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\n/**\n * LiveStateProvider\n *\n * Root-level provider that configures fetcher function and analytics.\n * Initializes Amplitude and Clarity on mount.\n *\n * The optional `onEvent` callback is fired on every tracking event before\n * sending to Amplitude/Clarity — useful for simulators and debugging tools.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateProvider({\n children,\n fetcher,\n analytics,\n onEvent,\n}: LiveStateProviderProps) {\n useEffect(() => {\n if (analytics?.amplitudeKey) {\n initializeAmplitude(analytics.amplitudeKey);\n }\n\n if (analytics?.clarityProjectId) {\n initializeClarity(analytics.clarityProjectId);\n }\n }, [analytics]);\n\n return (\n <SWRConfig value={{ provider: () => new Map() }}>\n <LiveStateContext.Provider value={{ fetcher, analytics, onEvent }}>\n {children}\n </LiveStateContext.Provider>\n </SWRConfig>\n );\n}\n\n/**\n * useLiveStateContext\n *\n * Internal hook to access LiveStateContext\n */\nexport function useLiveStateContext() {\n const context = useContext(LiveStateContext);\n\n if (!context) {\n throw new Error('useLiveState must be used within LiveStateProvider');\n }\n\n return context;\n}\n","import useSWR from 'swr';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport type { LiveStateResponse } from '../types';\n\ninterface UseLiveStateReturn {\n /** Live state data */\n liveState: LiveStateResponse | null;\n\n /** Loading state */\n isLoading: boolean;\n\n /** Error state */\n error: Error | null;\n\n /** Manual refresh function */\n refresh: () => Promise<void>;\n}\n\n/**\n * useLiveState hook\n *\n * Fetches and manages live state data using SWR with automatic caching,\n * deduplication, and revalidation.\n *\n * Must be used within LiveStateProvider. See examples/ directory for usage.\n */\nexport function useLiveState(): UseLiveStateReturn {\n const { fetcher } = useLiveStateContext();\n\n const { data, error, isLoading, mutate } = useSWR<LiveStateResponse | null>(\n 'live-state',\n fetcher,\n {\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n dedupingInterval: 60000, // 1 minute\n shouldRetryOnError: false, // Fail silently\n onError: err => {\n console.warn('[LiveState] Failed to fetch live state:', err);\n },\n },\n );\n\n const refresh = async () => {\n try {\n await mutate();\n } catch (err) {\n console.warn('[LiveState] Failed to refresh live state:', err);\n }\n };\n\n return {\n liveState: data ?? null,\n isLoading,\n error: error ?? null,\n refresh,\n };\n}\n","import { useCallback } from 'react';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport { trackEvent } from '../utils/analytics';\nimport type { TrackingProperties } from '../types';\n\n/**\n * useTrackEvent\n *\n * Returns a `track` function that fires both the internal analytics\n * (Amplitude + Clarity) and the optional `onEvent` callback provided\n * to LiveStateProvider — useful for simulators and debugging tools.\n */\nexport function useTrackEvent() {\n const { onEvent } = useLiveStateContext();\n\n const track = useCallback(\n (eventName: string, properties?: TrackingProperties) => {\n onEvent?.(eventName, properties);\n trackEvent(eventName, properties);\n },\n [onEvent],\n );\n\n return track;\n}\n","export const LIVE_STATE_STORAGE_KEY = '@tiendanube/live-state:closable';\n\n/** @internal */\nconst STORAGE_KEY = LIVE_STATE_STORAGE_KEY;\n\nexport interface ClosableState {\n count: number;\n closedAt: number;\n}\n\nexport type ClosableStates = Record<string, Record<string, ClosableState>>;\n\n/**\n * Reads closable states from localStorage.\n * Normalises legacy format (plain number) to the current shape ({ count, closedAt }).\n * Returns an empty object on any error (fail-silent).\n */\nexport function getClosableStates(): ClosableStates {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return {};\n\n const parsed = JSON.parse(raw) as unknown;\n if (typeof parsed !== 'object' || parsed === null) return {};\n\n const normalized: ClosableStates = {};\n\n for (const [ctx, ctxState] of Object.entries(\n parsed as Record<string, unknown>,\n )) {\n if (typeof ctxState !== 'object' || ctxState === null) continue;\n\n normalized[ctx] = {};\n\n for (const [id, entry] of Object.entries(\n ctxState as Record<string, unknown>,\n )) {\n if (typeof entry === 'number') {\n // legacy format: plain close count\n normalized[ctx][id] = { count: entry, closedAt: 0 };\n } else if (typeof entry === 'object' && entry !== null) {\n const candidate = entry as Partial<ClosableState>;\n normalized[ctx][id] = {\n count: typeof candidate.count === 'number' ? candidate.count : 0,\n closedAt:\n typeof candidate.closedAt === 'number' ? candidate.closedAt : 0,\n };\n }\n }\n }\n\n return normalized;\n } catch {\n return {};\n }\n}\n\n/**\n * Persists closable states to localStorage.\n * Fails silently if localStorage is unavailable or full.\n */\nexport function setClosableStates(states: ClosableStates): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(states));\n } catch {\n // localStorage unavailable or quota exceeded — application continues normally\n }\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport {\n getClosableStates,\n setClosableStates,\n} from '../utils/closable-storage';\n\nexport interface UseClosableOptions {\n /** Notification context (e.g. 'awareness', 'charge') */\n context: string;\n /** Unique notification ID (campaignId). If absent, always visible — no close tracking. */\n id: string | undefined;\n /** Maximum number of times the user can close before it is hidden permanently */\n maxCloseTimes?: number;\n /** Milliseconds after which the close counter resets (optional) */\n expiresIn?: number;\n}\n\nexport interface UseClosableReturn {\n /** Whether the notification should be shown. null = initial check in progress. */\n isVisible: boolean | null;\n /** Call this to record a close action */\n close: () => void;\n}\n\n/**\n * Manages the close state of a notification using localStorage.\n *\n * After the user closes a notification `maxCloseTimes` times, it is hidden\n * permanently. Optionally, the counter resets after `expiresIn` milliseconds.\n *\n * Fails silently — errors in localStorage never break the application.\n *\n * @example\n * ```tsx\n * const { isVisible, close } = useClosable({\n * context: 'awareness',\n * id: 'awareness-2026-q1',\n * maxCloseTimes: 3,\n * expiresIn: 86_400_000, // 1 day\n * });\n *\n * if (!isVisible) return null;\n * return <Notification onClose={close} />;\n * ```\n */\nexport function useClosable({\n context,\n id,\n maxCloseTimes = 3,\n expiresIn,\n}: UseClosableOptions): UseClosableReturn {\n const [isVisible, setIsVisible] = useState<boolean | null>(null);\n\n useEffect(() => {\n // No ID means no close tracking — always show\n if (!id) {\n setIsVisible(true);\n return;\n }\n\n const states = getClosableStates();\n const entry = states[context]?.[id];\n\n if (!entry) {\n setIsVisible(true);\n return;\n }\n\n const { count, closedAt } = entry;\n\n // Check expiry — reset counter and show if expired\n if (expiresIn != null && closedAt > 0) {\n const elapsed = Date.now() - closedAt;\n if (elapsed > expiresIn) {\n const updated = { ...states };\n if (updated[context]) {\n delete updated[context][id];\n setClosableStates(updated);\n }\n setIsVisible(true);\n return;\n }\n }\n\n setIsVisible(count < maxCloseTimes);\n }, [context, id, maxCloseTimes, expiresIn]);\n\n const close = useCallback(() => {\n if (!id) return;\n\n const states = getClosableStates();\n const currentCount = states[context]?.[id]?.count ?? 0;\n\n const updated: typeof states = {\n ...states,\n [context]: {\n ...(states[context] ?? {}),\n [id]: {\n count: currentCount + 1,\n closedAt: Date.now(),\n },\n },\n };\n\n setIsVisible(false);\n setClosableStates(updated);\n }, [context, id]);\n\n return { isVisible, close };\n}\n","import type { CtaConfig } from '../types';\n\n/**\n * Handle CTA click based on type\n *\n * @param cta - CTA configuration from LiveStateResponse\n */\nexport function handleCtaClick(cta: CtaConfig): void {\n try {\n switch (cta.type) {\n case 'redirect':\n // Navigate in same window\n window.location.href = cta.url;\n break;\n\n case 'whatsapp': {\n // Open WhatsApp in new tab\n const whatsappUrl = cta.whatsappMessage\n ? `${cta.url}?text=${encodeURIComponent(cta.whatsappMessage)}`\n : cta.url;\n window.open(whatsappUrl, '_blank');\n break;\n }\n\n case 'external':\n // Open in new tab\n window.open(cta.url, '_blank');\n break;\n\n default:\n console.warn(`[LiveState] Unknown CTA type: ${cta.type}`);\n }\n } catch (error) {\n console.warn('[LiveState] Failed to handle CTA click:', error);\n }\n}\n","import { useCallback, useEffect } from 'react';\nimport { Alert, Box, Button, Text } from '@nimbus-ds/components';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateAlertProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n /**\n * Override CTA click behaviour.\n * When provided, replaces default navigation so the caller controls what\n * happens on click (e.g. prevent navigation in a simulator, use a router).\n */\n onCtaClick?: (cta: import('../types').CtaConfig) => void;\n}\n\n/**\n * LiveStateAlert\n *\n * Renders an Alert component (Nimbus) for alert/warning types.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateAlert({\n data,\n trackingConfig,\n onClose,\n onCtaClick,\n}: LiveStateAlertProps) {\n const track = useTrackEvent();\n const appearance = data.type === 'alert' ? 'danger' : 'warning';\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n if (onCtaClick) {\n onCtaClick(data.cta);\n } else {\n handleCtaClick(data.cta);\n }\n }, [data, trackingConfig, buildEventProperties, track, onCtaClick]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <Alert\n appearance={appearance}\n title={data.title}\n onRemove={onClose ? handleClose : undefined}>\n <Box\n display=\"flex\"\n alignItems=\"flex-start\"\n gap=\"3\"\n flexWrap=\"wrap\"\n flexDirection=\"column\">\n <Box flex=\"1 1 auto\" minWidth=\"220px\">\n <Text>{data.message}</Text>\n </Box>\n\n <Box display=\"flex\" justifyContent=\"flex-end\" marginTop=\"2\">\n <Button appearance=\"primary\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Box>\n </Box>\n </Alert>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { Card, Box, Text, Link, Icon } from '@nimbus-ds/components';\nimport { MoneyIcon, CloseIcon } from '@nimbus-ds/icons';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateInfoProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n defaultVariant?: 'blue' | 'white';\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n /**\n * Override mobile layout detection.\n * When provided, bypasses `window.innerWidth < 750` so simulators and\n * testing tools can force a specific layout without resizing the window.\n */\n isMobile?: boolean;\n /**\n * Override CTA click behaviour.\n * When provided, replaces default navigation so the caller controls what\n * happens on click (e.g. prevent navigation in a simulator, use a router).\n */\n onCtaClick?: (cta: import('../types').CtaConfig) => void;\n}\n\nconst ICON_COLOR_MAP = {\n blue: { background: '#0050C3', icon: '#FFFFFF' },\n white: { background: '#FFFFFF', icon: '#0059D5' },\n} as const;\n\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type.\n * Uses MoneyIcon with colored circle background, Text components,\n * and a Link-style CTA — matching the LendingBanner design reference.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateInfo({\n data,\n trackingConfig,\n defaultVariant = 'blue',\n onClose,\n isMobile: isMobileProp,\n onCtaClick,\n}: LiveStateInfoProps) {\n const track = useTrackEvent();\n const variant = data.variant || defaultVariant;\n const iconConfig = ICON_COLOR_MAP[variant];\n\n const [isMobileWindow, setIsMobileWindow] = useState(\n () => window.innerWidth < 750,\n );\n\n useEffect(() => {\n const handler = () => setIsMobileWindow(window.innerWidth < 750);\n window.addEventListener('resize', handler);\n return () => window.removeEventListener('resize', handler);\n }, []);\n\n // Prop overrides window detection — allows simulators/tests to force layout\n const isMobile = isMobileProp ?? isMobileWindow;\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n if (onCtaClick) {\n onCtaClick(data.cta);\n } else {\n handleCtaClick(data.cta);\n }\n }, [data, trackingConfig, buildEventProperties, track, onCtaClick]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const ctaLink = (\n <Link\n as=\"a\"\n textDecoration=\"none\"\n onClick={handleClick}\n data-testid=\"live-state-cta-link\">\n <Text color=\"primary-interactive\" fontSize=\"base\">\n {data.cta.label}\n </Text>\n </Link>\n );\n\n return (\n <Card>\n <Box display=\"flex\" flexDirection=\"row\" justifyContent=\"space-between\">\n {/* Left: icon + text (+ cta on mobile) */}\n <Box\n display=\"flex\"\n gap=\"4\"\n alignItems={isMobile ? 'flex-start' : 'center'}\n paddingRight=\"1-5\">\n <Box minWidth=\"32px\">\n <div\n style={{\n width: 32,\n height: 32,\n borderRadius: '35%',\n borderColor: variant === 'white' ? '#E7E7E7' : 'transparent',\n borderWidth: 1,\n borderStyle: 'solid',\n background: iconConfig.background,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}>\n <MoneyIcon style={{ color: iconConfig.icon }} />\n </div>\n </Box>\n\n <Box display=\"grid\" gap=\"2\">\n <Box>\n <Text fontSize=\"base\" color=\"neutral-textHigh\">\n {data.title}\n </Text>\n <Text fontSize=\"base\" color=\"neutral-textLow\">\n {data.message}\n </Text>\n </Box>\n\n {/* CTA shown below text on mobile */}\n {isMobile && ctaLink}\n </Box>\n </Box>\n\n {/* Right: cta (desktop only) + close button */}\n {(!isMobile || onClose) && (\n <Box\n display=\"flex\"\n flexDirection={isMobile ? 'column' : 'row'}\n alignItems={isMobile ? 'flex-end' : 'center'}\n gap=\"2\">\n {/* CTA shown on the right side on desktop */}\n {!isMobile && ctaLink}\n\n {onClose && (\n <button\n type=\"button\"\n data-testid=\"live-state-close-button\"\n aria-label=\"Fechar notificação\"\n onClick={handleClose}\n style={{\n background: 'none',\n border: 'none',\n padding: 0,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}>\n <Icon\n source={<CloseIcon width=\"18px\" height=\"18px\" />}\n color=\"neutral-interactive\"\n />\n </button>\n )}\n </Box>\n )}\n </Box>\n </Card>\n );\n}\n","import type { LiveStateRendererProps } from '../types';\nimport { useClosable } from '../hooks/useClosable';\nimport { LiveStateAlert } from './LiveStateAlert';\nimport { LiveStateInfo } from './LiveStateInfo';\n\n/**\n * LiveStateRenderer\n *\n * Main component that validates payload, filters by context, and renders\n * the appropriate visual component (Alert or Info) based on type.\n * Handles closable notifications via useClosable when closable is configured.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateRenderer({\n data,\n loading,\n trackingConfig,\n allowedContexts,\n defaultVariant,\n isMobile,\n onCtaClick,\n}: LiveStateRendererProps) {\n const { isVisible, close } = useClosable({\n context: data?.context ?? '',\n id: data?.campaignId,\n maxCloseTimes: data?.metadata?.maxCloseTimes,\n expiresIn: data?.metadata?.expiresIn,\n });\n\n // Don't render while loading or no data\n if (loading || !data) {\n return null;\n }\n\n // Validate required fields\n if (\n !data.context ||\n !data.type ||\n !data.title ||\n !data.message ||\n !data.cta?.label ||\n !data.cta?.url ||\n !data.cta?.type\n ) {\n console.warn('[LiveState] Invalid payload, missing required fields', data);\n return null;\n }\n\n // Filter by allowed contexts\n if (allowedContexts && !allowedContexts.includes(data.context)) {\n return null;\n }\n\n // Awaiting localStorage check\n if (isVisible === null) {\n return null;\n }\n\n // Hidden — user reached maxCloseTimes\n if (!isVisible) {\n return null;\n }\n\n // Only pass onClose when closable is configured and notification has a campaignId to track\n const onClose = data.closable && data.campaignId ? close : undefined;\n\n // Render appropriate component based on type\n if (data.type === 'alert' || data.type === 'warning') {\n return (\n <LiveStateAlert\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n onCtaClick={onCtaClick}\n />\n );\n }\n\n if (data.type === 'info') {\n return (\n <LiveStateInfo\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n defaultVariant={defaultVariant}\n isMobile={isMobile}\n onCtaClick={onCtaClick}\n />\n );\n }\n\n console.warn(`[LiveState] Unknown type: ${data.type}`);\n return null;\n}\n"],"mappings":"0vBAOA,IAAM,EAAoB,EAAU,gBAAgB,CAKpD,SAAgB,EAAoB,EAAsB,CACxD,GAAI,CACF,GAAI,CAAC,EAAQ,CACX,QAAQ,KAAK,6CAA6C,CAC1D,OAGF,EAAkB,KAAK,EAAQ,CAC7B,gBAAiB,GAClB,CAAC,OACK,EAAO,CACd,QAAQ,KAAK,8CAA+C,EAAM,EAOtE,eAAsB,EAAkB,EAAmC,CACzE,GAAI,CAEF,GAAI,OAAO,QAAS,CAClB,QAAQ,IAAI,oDAAoD,CAChE,OAIF,IAAM,EAAiB,GAAa,GAA2B,CAE/D,GAAI,CAAC,EAAgB,CACnB,QAAQ,KAAK,8CAA8C,CAC3D,QAIe,MAAM,OAAO,uBAAuB,QAC7C,KAAK,EAAe,OACrB,EAAO,CACd,QAAQ,KAAK,4CAA6C,EAAM,EAOpE,SAAS,GAAgD,CACvD,GAAI,CAEF,IAAM,EAAgB,SAAS,cAAc,4BAA4B,CACzE,GAAI,EAGF,OAFY,EAAc,aAAa,MAAM,EAC1B,MAAM,iBAAiB,GAC3B,GAIjB,IAAM,EAAY,OAAO,SAAS,IAAI,KAAK,GAC3C,GAAI,OAAO,GAAc,SACvB,OAAO,OAEH,GAUV,SAAgB,EACd,EACA,EACM,CACN,GAAI,CACF,EAAkB,MAAM,EAAW,EAAW,OACvC,EAAO,CACd,QAAQ,KAAK,+CAAgD,EAAM,EAOvE,SAAgB,EACd,EACA,EACM,CACN,GAAI,CACE,OAAO,UACT,OAAO,QAAQ,QAAS,EAAU,CAG9B,GACF,OAAO,QAAQ,EAAW,CAAC,SAAS,CAAC,EAAK,KAAW,CACnD,OAAO,UAAU,MAAO,EAAK,OAAO,EAAM,CAAC,EAC3C,QAGC,EAAO,CACd,QAAQ,KAAK,6CAA8C,EAAM,EAQrE,SAAgB,EACd,EACoB,CACpB,OAAO,OAAO,YACZ,OAAO,QAAQ,EAAO,CAAC,OACpB,GAA4C,EAAM,KAAO,IAAA,GAC3D,CACF,CAMH,SAAgB,EACd,EACA,EACM,CACN,EAAoB,EAAW,EAAW,CAC1C,EAAkB,EAAW,EAAW,CC3H1C,IAAM,GAAA,EAAA,EAAA,eAA+D,KAAK,CAoB1E,SAAgB,EAAkB,CAChC,WACA,UACA,YACA,WACyB,CAWzB,OAVA,EAAA,EAAA,eAAgB,CACV,GAAW,cACb,EAAoB,EAAU,aAAa,CAGzC,GAAW,kBACb,EAAkB,EAAU,iBAAiB,EAE9C,CAAC,EAAU,CAAC,EAGb,EAAA,EAAA,KAAC,EAAA,UAAD,CAAW,MAAO,CAAE,aAAgB,IAAI,IAAO,WAC7C,EAAA,EAAA,KAAC,EAAiB,SAAlB,CAA2B,MAAO,CAAE,UAAS,YAAW,UAAS,CAC9D,WACyB,CAAA,CAClB,CAAA,CAShB,SAAgB,GAAsB,CACpC,IAAM,GAAA,EAAA,EAAA,YAAqB,EAAiB,CAE5C,GAAI,CAAC,EACH,MAAU,MAAM,qDAAqD,CAGvE,OAAO,EC9CT,SAAgB,GAAmC,CACjD,GAAM,CAAE,WAAY,GAAqB,CAEnC,CAAE,OAAM,QAAO,YAAW,WAAA,EAAA,EAAA,SAC9B,aACA,EACA,CACE,kBAAmB,GACnB,sBAAuB,GACvB,iBAAkB,IAClB,mBAAoB,GACpB,QAAS,GAAO,CACd,QAAQ,KAAK,0CAA2C,EAAI,EAE/D,CACF,CAUD,MAAO,CACL,UAAW,GAAQ,KACnB,YACA,MAAO,GAAS,KAChB,QAZc,SAAY,CAC1B,GAAI,CACF,MAAM,GAAQ,OACP,EAAK,CACZ,QAAQ,KAAK,4CAA6C,EAAI,GASjE,CC5CH,SAAgB,GAAgB,CAC9B,GAAM,CAAE,WAAY,GAAqB,CAUzC,OAAA,EAAA,EAAA,cAPG,EAAmB,IAAoC,CACtD,IAAU,EAAW,EAAW,CAChC,EAAW,EAAW,EAAW,EAEnC,CAAC,EAAQ,CACV,CCrBH,IAAa,EAAyB,kCAGhC,EAAc,EAcpB,SAAgB,GAAoC,CAClD,GAAI,CACF,IAAM,EAAM,aAAa,QAAQ,EAAY,CAC7C,GAAI,CAAC,EAAK,MAAO,EAAE,CAEnB,IAAM,EAAS,KAAK,MAAM,EAAI,CAC9B,GAAI,OAAO,GAAW,WAAY,EAAiB,MAAO,EAAE,CAE5D,IAAM,EAA6B,EAAE,CAErC,IAAK,GAAM,CAAC,EAAK,KAAa,OAAO,QACnC,EACD,CACK,YAAO,GAAa,WAAY,GAEpC,GAAW,GAAO,EAAE,CAEpB,IAAK,GAAM,CAAC,EAAI,KAAU,OAAO,QAC/B,EACD,CACC,GAAI,OAAO,GAAU,SAEnB,EAAW,GAAK,GAAM,CAAE,MAAO,EAAO,SAAU,EAAG,SAC1C,OAAO,GAAU,UAAY,EAAgB,CACtD,IAAM,EAAY,EAClB,EAAW,GAAK,GAAM,CACpB,MAAO,OAAO,EAAU,OAAU,SAAW,EAAU,MAAQ,EAC/D,SACE,OAAO,EAAU,UAAa,SAAW,EAAU,SAAW,EACjE,EAKP,OAAO,OACD,CACN,MAAO,EAAE,EAQb,SAAgB,EAAkB,EAA8B,CAC9D,GAAI,CACF,aAAa,QAAQ,EAAa,KAAK,UAAU,EAAO,CAAC,MACnD,GCnBV,SAAgB,EAAY,CAC1B,UACA,KACA,gBAAgB,EAChB,aACwC,CACxC,GAAM,CAAC,EAAW,IAAA,EAAA,EAAA,UAAyC,KAAK,CAyDhE,OAvDA,EAAA,EAAA,eAAgB,CAEd,GAAI,CAAC,EAAI,CACP,EAAa,GAAK,CAClB,OAGF,IAAM,EAAS,GAAmB,CAC5B,EAAQ,EAAO,KAAW,GAEhC,GAAI,CAAC,EAAO,CACV,EAAa,GAAK,CAClB,OAGF,GAAM,CAAE,QAAO,YAAa,EAG5B,GAAI,GAAa,MAAQ,EAAW,GAClB,KAAK,KAAK,CAAG,EACf,EAAW,CACvB,IAAM,EAAU,CAAE,GAAG,EAAQ,CACzB,EAAQ,KACV,OAAO,EAAQ,GAAS,GACxB,EAAkB,EAAQ,EAE5B,EAAa,GAAK,CAClB,OAIJ,EAAa,EAAQ,EAAc,EAClC,CAAC,EAAS,EAAI,EAAe,EAAU,CAAC,CAuBpC,CAAE,YAAW,OAAA,EAAA,EAAA,iBArBY,CAC9B,GAAI,CAAC,EAAI,OAET,IAAM,EAAS,GAAmB,CAC5B,EAAe,EAAO,KAAW,IAAK,OAAS,EAE/C,EAAyB,CAC7B,GAAG,GACF,GAAU,CACT,GAAI,EAAO,IAAY,EAAE,EACxB,GAAK,CACJ,MAAO,EAAe,EACtB,SAAU,KAAK,KAAK,CACrB,CACF,CACF,CAED,EAAa,GAAM,CACnB,EAAkB,EAAQ,EACzB,CAAC,EAAS,EAAG,CAAC,CAEU,CCrG7B,SAAgB,EAAe,EAAsB,CACnD,GAAI,CACF,OAAQ,EAAI,KAAZ,CACE,IAAK,WAEH,OAAO,SAAS,KAAO,EAAI,IAC3B,MAEF,IAAK,WAAY,CAEf,IAAM,EAAc,EAAI,gBACpB,GAAG,EAAI,IAAI,QAAQ,mBAAmB,EAAI,gBAAgB,GAC1D,EAAI,IACR,OAAO,KAAK,EAAa,SAAS,CAClC,MAGF,IAAK,WAEH,OAAO,KAAK,EAAI,IAAK,SAAS,CAC9B,MAEF,QACE,QAAQ,KAAK,iCAAiC,EAAI,OAAO,QAEtD,EAAO,CACd,QAAQ,KAAK,0CAA2C,EAAM,ECJlE,SAAgB,EAAe,CAC7B,OACA,iBACA,UACA,cACsB,CACtB,IAAM,EAAQ,GAAe,CACvB,EAAa,EAAK,OAAS,QAAU,SAAW,UAEhD,GAAA,EAAA,EAAA,iBAEF,EAAwB,CACtB,QAAS,EAAK,QACd,WAAY,EAAK,WACjB,MAAO,EAAK,MACZ,GAAG,EAAK,SACR,GAAG,EAAe,WACnB,CAAC,CACJ,CAAC,EAAM,EAAe,WAAW,CAClC,CAEK,GAAA,EAAA,EAAA,iBAAgC,CAEpC,EADkB,GAAG,EAAe,SAAS,EAAe,KAAK,GAAG,EAAK,QAAQ,QAChE,GAAsB,CAAC,CACpC,EACF,EAAW,EAAK,IAAI,CAEpB,EAAe,EAAK,IAAI,EAEzB,CAAC,EAAM,EAAgB,EAAsB,EAAO,EAAW,CAAC,CAE7D,GAAA,EAAA,EAAA,iBAAgC,CAEpC,EADkB,GAAG,EAAe,SAAS,EAAe,KAAK,GAAG,EAAK,QAAQ,QAChE,GAAsB,CAAC,CACxC,KAAW,EACV,CAAC,EAAS,EAAM,EAAgB,EAAsB,EAAM,CAAC,CAQhE,OANA,EAAA,EAAA,eAAgB,CAEd,EADkB,GAAG,EAAe,SAAS,EAAe,KAAK,GAAG,EAAK,QAAQ,OAChE,GAAsB,CAAC,EAEvC,EAAE,CAAC,EAGJ,EAAA,EAAA,KAAC,EAAA,MAAD,CACc,aACZ,MAAO,EAAK,MACZ,SAAU,EAAU,EAAc,IAAA,aAClC,EAAA,EAAA,MAAC,EAAA,IAAD,CACE,QAAQ,OACR,WAAW,aACX,IAAI,IACJ,SAAS,OACT,cAAc,kBALhB,EAME,EAAA,EAAA,KAAC,EAAA,IAAD,CAAK,KAAK,WAAW,SAAS,kBAC5B,EAAA,EAAA,KAAC,EAAA,KAAD,CAAA,SAAO,EAAK,QAAe,CAAA,CACvB,CAAA,EAEN,EAAA,EAAA,KAAC,EAAA,IAAD,CAAK,QAAQ,OAAO,eAAe,WAAW,UAAU,cACtD,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,WAAW,UAAU,QAAS,WACnC,EAAK,IAAI,MACH,CAAA,CACL,CAAA,CACF,GACA,CAAA,CCjEZ,IAAM,EAAiB,CACrB,KAAM,CAAE,WAAY,UAAW,KAAM,UAAW,CAChD,MAAO,CAAE,WAAY,UAAW,KAAM,UAAW,CAClD,CAaD,SAAgB,EAAc,CAC5B,OACA,iBACA,iBAAiB,OACjB,UACA,SAAU,EACV,cACqB,CACrB,IAAM,EAAQ,GAAe,CACvB,EAAU,EAAK,SAAW,EAC1B,EAAa,EAAe,GAE5B,CAAC,EAAgB,IAAA,EAAA,EAAA,cACf,OAAO,WAAa,IAC3B,EAED,EAAA,EAAA,eAAgB,CACd,IAAM,MAAgB,EAAkB,OAAO,WAAa,IAAI,CAEhE,OADA,OAAO,iBAAiB,SAAU,EAAQ,KAC7B,OAAO,oBAAoB,SAAU,EAAQ,EACzD,EAAE,CAAC,CAGN,IAAM,EAAW,GAAgB,EAE3B,GAAA,EAAA,EAAA,iBAEF,EAAwB,CACtB,QAAS,EAAK,QACd,WAAY,EAAK,WACjB,MAAO,EAAK,MACZ,GAAG,EAAK,SACR,GAAG,EAAe,WACnB,CAAC,CACJ,CAAC,EAAM,EAAe,WAAW,CAClC,CAEK,GAAA,EAAA,EAAA,iBAAgC,CAEpC,EADkB,GAAG,EAAe,SAAS,EAAe,KAAK,GAAG,EAAK,QAAQ,QAChE,GAAsB,CAAC,CACpC,EACF,EAAW,EAAK,IAAI,CAEpB,EAAe,EAAK,IAAI,EAEzB,CAAC,EAAM,EAAgB,EAAsB,EAAO,EAAW,CAAC,CAE7D,GAAA,EAAA,EAAA,iBAAgC,CAEpC,EADkB,GAAG,EAAe,SAAS,EAAe,KAAK,GAAG,EAAK,QAAQ,QAChE,GAAsB,CAAC,CACxC,KAAW,EACV,CAAC,EAAS,EAAM,EAAgB,EAAsB,EAAM,CAAC,EAEhE,EAAA,EAAA,eAAgB,CAEd,EADkB,GAAG,EAAe,SAAS,EAAe,KAAK,GAAG,EAAK,QAAQ,OAChE,GAAsB,CAAC,EAEvC,EAAE,CAAC,CAEN,IAAM,GACJ,EAAA,EAAA,KAAC,EAAA,KAAD,CACE,GAAG,IACH,eAAe,OACf,QAAS,EACT,cAAY,gCACZ,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,MAAM,sBAAsB,SAAS,gBACxC,EAAK,IAAI,MACL,CAAA,CACF,CAAA,CAGT,OACE,EAAA,EAAA,KAAC,EAAA,KAAD,CAAA,UACE,EAAA,EAAA,MAAC,EAAA,IAAD,CAAK,QAAQ,OAAO,cAAc,MAAM,eAAe,yBAAvD,EAEE,EAAA,EAAA,MAAC,EAAA,IAAD,CACE,QAAQ,OACR,IAAI,IACJ,WAAY,EAAW,aAAe,SACtC,aAAa,eAJf,EAKE,EAAA,EAAA,KAAC,EAAA,IAAD,CAAK,SAAS,iBACZ,EAAA,EAAA,KAAC,MAAD,CACE,MAAO,CACL,MAAO,GACP,OAAQ,GACR,aAAc,MACd,YAAa,IAAY,QAAU,UAAY,cAC/C,YAAa,EACb,YAAa,QACb,WAAY,EAAW,WACvB,QAAS,OACT,WAAY,SACZ,eAAgB,SACjB,WACD,EAAA,EAAA,KAAC,EAAA,UAAD,CAAW,MAAO,CAAE,MAAO,EAAW,KAAM,CAAI,CAAA,CAC5C,CAAA,CACF,CAAA,EAEN,EAAA,EAAA,MAAC,EAAA,IAAD,CAAK,QAAQ,OAAO,IAAI,aAAxB,EACE,EAAA,EAAA,MAAC,EAAA,IAAD,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,SAAS,OAAO,MAAM,4BACzB,EAAK,MACD,CAAA,EACP,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,SAAS,OAAO,MAAM,2BACzB,EAAK,QACD,CAAA,CACH,CAAA,CAAA,CAGL,GAAY,EACT,GACF,IAGJ,CAAC,GAAY,KACb,EAAA,EAAA,MAAC,EAAA,IAAD,CACE,QAAQ,OACR,cAAe,EAAW,SAAW,MACrC,WAAY,EAAW,WAAa,SACpC,IAAI,aAJN,CAMG,CAAC,GAAY,EAEb,IACC,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,cAAY,0BACZ,aAAW,qBACX,QAAS,EACT,MAAO,CACL,WAAY,OACZ,OAAQ,OACR,QAAS,EACT,OAAQ,UACR,QAAS,OACT,WAAY,SACZ,eAAgB,SACjB,WACD,EAAA,EAAA,KAAC,EAAA,KAAD,CACE,QAAQ,EAAA,EAAA,KAAC,EAAA,UAAD,CAAW,MAAM,OAAO,OAAO,OAAS,CAAA,CAChD,MAAM,sBACN,CAAA,CACK,CAAA,CAEP,GAEJ,GACD,CAAA,CCjLX,SAAgB,EAAkB,CAChC,OACA,UACA,iBACA,kBACA,iBACA,WACA,cACyB,CACzB,GAAM,CAAE,YAAW,SAAU,EAAY,CACvC,QAAS,GAAM,SAAW,GAC1B,GAAI,GAAM,WACV,cAAe,GAAM,UAAU,cAC/B,UAAW,GAAM,UAAU,UAC5B,CAAC,CAGF,GAAI,GAAW,CAAC,EACd,OAAO,KAIT,GACE,CAAC,EAAK,SACN,CAAC,EAAK,MACN,CAAC,EAAK,OACN,CAAC,EAAK,SACN,CAAC,EAAK,KAAK,OACX,CAAC,EAAK,KAAK,KACX,CAAC,EAAK,KAAK,KAGX,OADA,QAAQ,KAAK,uDAAwD,EAAK,CACnE,KAcT,GAVI,GAAmB,CAAC,EAAgB,SAAS,EAAK,QAAQ,EAK1D,IAAc,MAKd,CAAC,EACH,OAAO,KAIT,IAAM,EAAU,EAAK,UAAY,EAAK,WAAa,EAAQ,IAAA,GA4B3D,OAzBI,EAAK,OAAS,SAAW,EAAK,OAAS,WAEvC,EAAA,EAAA,KAAC,EAAD,CACQ,OACG,UACO,iBACJ,aACZ,CAAA,CAIF,EAAK,OAAS,QAEd,EAAA,EAAA,KAAC,EAAD,CACQ,OACG,UACO,iBACA,iBACN,WACE,aACZ,CAAA,EAIN,QAAQ,KAAK,6BAA6B,EAAK,OAAO,CAC/C"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/utils/analytics.ts","../src/providers/LiveStateProvider.tsx","../src/hooks/useLiveState.ts","../src/hooks/useTrackEvent.ts","../src/utils/closable-storage.ts","../src/hooks/useClosable.ts","../src/utils/cta.ts","../src/components/LiveStateAlert.tsx","../src/components/LiveStateInfo.tsx","../src/components/LiveStateRenderer.tsx"],"sourcesContent":["import * as amplitude from '@amplitude/analytics-browser';\nimport type { TrackingProperties, TrackingValue } from '../types';\n\n/**\n * Isolated Amplitude instance for the lib — avoids conflicts with the\n * consumer app's own Amplitude instance when both coexist on the same page.\n */\nconst amplitudeInstance = amplitude.createInstance();\n\n/**\n * Initialize Amplitude (fail silently)\n */\nexport function initializeAmplitude(apiKey: string): void {\n try {\n if (!apiKey) {\n console.warn('[LiveState] Amplitude API key not provided');\n return;\n }\n\n amplitudeInstance.init(apiKey, {\n defaultTracking: false,\n });\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Amplitude:', error);\n }\n}\n\n/**\n * Initialize Clarity (fail silently)\n */\nexport async function initializeClarity(projectId?: string): Promise<void> {\n try {\n // Check if Clarity is already loaded by the client\n if (window.clarity) {\n console.log('[LiveState] Clarity already initialized by client');\n return;\n }\n\n // If client provided project ID, use it\n const finalProjectId = projectId || getClientClarityProjectId();\n\n if (!finalProjectId) {\n console.warn('[LiveState] Clarity project ID not provided');\n return;\n }\n\n // Initialize Clarity with project ID\n const Clarity = (await import('@microsoft/clarity')).default;\n Clarity.init(finalProjectId);\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Clarity:', error);\n }\n}\n\n/**\n * Try to extract Clarity project ID from client's installation\n */\nfunction getClientClarityProjectId(): string | undefined {\n try {\n // Check if Clarity script tag exists\n const clarityScript = document.querySelector('script[src*=\"clarity.ms\"]');\n if (clarityScript) {\n const src = clarityScript.getAttribute('src');\n const match = src?.match(/\\/([a-z0-9]+)$/);\n return match?.[1];\n }\n\n // Check global clarity config: shape is clarity.q = [['init', projectId, ...]]\n const projectId = window.clarity?.q?.[0]?.[1];\n if (typeof projectId === 'string') {\n return projectId;\n }\n } catch {\n // Fail silently\n }\n\n return undefined;\n}\n\n/**\n * Track event with Amplitude (fail silently)\n */\nexport function trackAmplitudeEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n amplitudeInstance.track(eventName, properties);\n } catch (error) {\n console.warn('[LiveState] Failed to track Amplitude event:', error);\n }\n}\n\n/**\n * Track event with Clarity (fail silently)\n */\nexport function trackClarityEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n if (window.clarity) {\n window.clarity('event', eventName);\n\n // Set custom tags for properties\n if (properties) {\n Object.entries(properties).forEach(([key, value]) => {\n window.clarity?.('set', key, String(value));\n });\n }\n }\n } catch (error) {\n console.warn('[LiveState] Failed to track Clarity event:', error);\n }\n}\n\n/**\n * Builds a TrackingProperties object from a loose record, dropping entries\n * whose value is undefined so callers don't need to guard optional fields.\n */\nexport function buildTrackingProperties(\n source: Record<string, TrackingValue | undefined>,\n): TrackingProperties {\n return Object.fromEntries(\n Object.entries(source).filter(\n (entry): entry is [string, TrackingValue] => entry[1] !== undefined,\n ),\n );\n}\n\n/**\n * Track event with both Amplitude and Clarity (fail silently)\n */\nexport function trackEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n trackAmplitudeEvent(eventName, properties);\n trackClarityEvent(eventName, properties);\n}\n\n/**\n * Clarity command API shape as documented in the Clarity SDK\n * https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-api\n */\ntype ClarityCommand =\n | 'init'\n | 'event'\n | 'set'\n | 'identify'\n | 'consent'\n | 'upgrade';\n\ndeclare global {\n interface Window {\n clarity?: {\n (command: ClarityCommand, ...args: string[]): void;\n q?: string[][];\n };\n }\n}\n","import React, { createContext, useContext, useEffect } from 'react';\nimport { SWRConfig } from 'swr';\nimport type {\n LiveStateFetcher,\n AnalyticsConfig,\n TrackingProperties,\n} from '../types';\nimport { initializeAmplitude, initializeClarity } from '../utils/analytics';\n\ninterface LiveStateContextValue {\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\nconst LiveStateContext = createContext<LiveStateContextValue | null>(null);\n\nexport interface LiveStateProviderProps {\n children: React.ReactNode;\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\n/**\n * LiveStateProvider\n *\n * Root-level provider that configures fetcher function and analytics.\n * Initializes Amplitude and Clarity on mount.\n *\n * The optional `onEvent` callback is fired on every tracking event before\n * sending to Amplitude/Clarity — useful for simulators and debugging tools.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateProvider({\n children,\n fetcher,\n analytics,\n onEvent,\n}: LiveStateProviderProps) {\n useEffect(() => {\n if (analytics?.amplitudeKey) {\n initializeAmplitude(analytics.amplitudeKey);\n }\n\n if (analytics?.clarityProjectId) {\n initializeClarity(analytics.clarityProjectId);\n }\n }, [analytics]);\n\n return (\n <SWRConfig value={{ provider: () => new Map() }}>\n <LiveStateContext.Provider value={{ fetcher, analytics, onEvent }}>\n {children}\n </LiveStateContext.Provider>\n </SWRConfig>\n );\n}\n\n/**\n * useLiveStateContext\n *\n * Internal hook to access LiveStateContext\n */\nexport function useLiveStateContext() {\n const context = useContext(LiveStateContext);\n\n if (!context) {\n throw new Error('useLiveState must be used within LiveStateProvider');\n }\n\n return context;\n}\n","import useSWR from 'swr';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport type { LiveStateResponse } from '../types';\n\ninterface UseLiveStateReturn {\n /** Live state data */\n liveState: LiveStateResponse | null;\n\n /** Loading state */\n isLoading: boolean;\n\n /** Error state */\n error: Error | null;\n\n /** Manual refresh function */\n refresh: () => Promise<void>;\n}\n\n/**\n * useLiveState hook\n *\n * Fetches and manages live state data using SWR with automatic caching,\n * deduplication, and revalidation.\n *\n * Must be used within LiveStateProvider. See examples/ directory for usage.\n */\nexport function useLiveState(): UseLiveStateReturn {\n const { fetcher } = useLiveStateContext();\n\n const { data, error, isLoading, mutate } = useSWR<LiveStateResponse | null>(\n 'live-state',\n fetcher,\n {\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n dedupingInterval: 60000, // 1 minute\n shouldRetryOnError: false, // Fail silently\n onError: err => {\n console.warn('[LiveState] Failed to fetch live state:', err);\n },\n },\n );\n\n const refresh = async () => {\n try {\n await mutate();\n } catch (err) {\n console.warn('[LiveState] Failed to refresh live state:', err);\n }\n };\n\n return {\n liveState: data ?? null,\n isLoading,\n error: error ?? null,\n refresh,\n };\n}\n","import { useCallback } from 'react';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport { trackEvent } from '../utils/analytics';\nimport type { TrackingProperties } from '../types';\n\n/**\n * useTrackEvent\n *\n * Returns a `track` function that fires both the internal analytics\n * (Amplitude + Clarity) and the optional `onEvent` callback provided\n * to LiveStateProvider — useful for simulators and debugging tools.\n */\nexport function useTrackEvent() {\n const { onEvent } = useLiveStateContext();\n\n const track = useCallback(\n (eventName: string, properties?: TrackingProperties) => {\n onEvent?.(eventName, properties);\n trackEvent(eventName, properties);\n },\n [onEvent],\n );\n\n return track;\n}\n","export const LIVE_STATE_STORAGE_KEY = '@tiendanube/live-state:closable';\n\n/** @internal */\nconst STORAGE_KEY = LIVE_STATE_STORAGE_KEY;\n\nexport interface ClosableState {\n count: number;\n closedAt: number;\n}\n\nexport type ClosableStates = Record<string, Record<string, ClosableState>>;\n\n/**\n * Reads closable states from localStorage.\n * Normalises legacy format (plain number) to the current shape ({ count, closedAt }).\n * Returns an empty object on any error (fail-silent).\n */\nexport function getClosableStates(): ClosableStates {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return {};\n\n const parsed = JSON.parse(raw) as unknown;\n if (typeof parsed !== 'object' || parsed === null) return {};\n\n const normalized: ClosableStates = {};\n\n for (const [ctx, ctxState] of Object.entries(\n parsed as Record<string, unknown>,\n )) {\n if (typeof ctxState !== 'object' || ctxState === null) continue;\n\n normalized[ctx] = {};\n\n for (const [id, entry] of Object.entries(\n ctxState as Record<string, unknown>,\n )) {\n if (typeof entry === 'number') {\n // legacy format: plain close count\n normalized[ctx][id] = { count: entry, closedAt: 0 };\n } else if (typeof entry === 'object' && entry !== null) {\n const candidate = entry as Partial<ClosableState>;\n normalized[ctx][id] = {\n count: typeof candidate.count === 'number' ? candidate.count : 0,\n closedAt:\n typeof candidate.closedAt === 'number' ? candidate.closedAt : 0,\n };\n }\n }\n }\n\n return normalized;\n } catch {\n return {};\n }\n}\n\n/**\n * Persists closable states to localStorage.\n * Fails silently if localStorage is unavailable or full.\n */\nexport function setClosableStates(states: ClosableStates): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(states));\n } catch {\n // localStorage unavailable or quota exceeded — application continues normally\n }\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport {\n getClosableStates,\n setClosableStates,\n} from '../utils/closable-storage';\n\nexport interface UseClosableOptions {\n /** Notification context (e.g. 'awareness', 'charge') */\n context: string;\n /** Unique notification ID (campaignId). If absent, always visible — no close tracking. */\n id: string | undefined;\n /** Maximum number of times the user can close before it is hidden permanently */\n maxCloseTimes?: number;\n /** Milliseconds after which the close counter resets (optional) */\n expiresIn?: number;\n}\n\nexport interface UseClosableReturn {\n /** Whether the notification should be shown. null = initial check in progress. */\n isVisible: boolean | null;\n /** Call this to record a close action */\n close: () => void;\n}\n\n/**\n * Manages the close state of a notification using localStorage.\n *\n * After the user closes a notification `maxCloseTimes` times, it is hidden\n * permanently. Optionally, the counter resets after `expiresIn` milliseconds.\n *\n * Fails silently — errors in localStorage never break the application.\n *\n * @example\n * ```tsx\n * const { isVisible, close } = useClosable({\n * context: 'awareness',\n * id: 'awareness-2026-q1',\n * maxCloseTimes: 3,\n * expiresIn: 86_400_000, // 1 day\n * });\n *\n * if (!isVisible) return null;\n * return <Notification onClose={close} />;\n * ```\n */\nexport function useClosable({\n context,\n id,\n maxCloseTimes = 3,\n expiresIn,\n}: UseClosableOptions): UseClosableReturn {\n const [isVisible, setIsVisible] = useState<boolean | null>(null);\n\n useEffect(() => {\n // No ID means no close tracking — always show\n if (!id) {\n setIsVisible(true);\n return;\n }\n\n const states = getClosableStates();\n const entry = states[context]?.[id];\n\n if (!entry) {\n setIsVisible(true);\n return;\n }\n\n const { count, closedAt } = entry;\n\n // Check expiry — reset counter and show if expired\n if (expiresIn != null && closedAt > 0) {\n const elapsed = Date.now() - closedAt;\n if (elapsed > expiresIn) {\n const updated = { ...states };\n if (updated[context]) {\n delete updated[context][id];\n setClosableStates(updated);\n }\n setIsVisible(true);\n return;\n }\n }\n\n setIsVisible(count < maxCloseTimes);\n }, [context, id, maxCloseTimes, expiresIn]);\n\n const close = useCallback(() => {\n // Always hide visually\n setIsVisible(false);\n\n // Only persist to localStorage if there is an id to track\n if (!id) return;\n\n const states = getClosableStates();\n const currentCount = states[context]?.[id]?.count ?? 0;\n\n const updated: typeof states = {\n ...states,\n [context]: {\n ...(states[context] ?? {}),\n [id]: {\n count: currentCount + 1,\n closedAt: Date.now(),\n },\n },\n };\n\n setClosableStates(updated);\n }, [context, id]);\n\n return { isVisible, close };\n}\n","import type { CtaConfig } from '../types';\n\n/**\n * Handle CTA click based on type\n *\n * @param cta - CTA configuration from LiveStateResponse\n */\nexport function handleCtaClick(cta: CtaConfig): void {\n try {\n switch (cta.type) {\n case 'redirect':\n // Navigate in same window\n window.location.href = cta.url;\n break;\n\n case 'whatsapp': {\n // Open WhatsApp in new tab\n const whatsappUrl = cta.whatsappMessage\n ? `${cta.url}?text=${encodeURIComponent(cta.whatsappMessage)}`\n : cta.url;\n window.open(whatsappUrl, '_blank');\n break;\n }\n\n case 'external':\n // Open in new tab\n window.open(cta.url, '_blank');\n break;\n\n default:\n console.warn(`[LiveState] Unknown CTA type: ${cta.type}`);\n }\n } catch (error) {\n console.warn('[LiveState] Failed to handle CTA click:', error);\n }\n}\n","import { useCallback, useEffect } from 'react';\nimport { Alert, Box, Button, Text } from '@nimbus-ds/components';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateAlertProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n /**\n * Override CTA click behaviour.\n * When provided, replaces default navigation so the caller controls what\n * happens on click (e.g. prevent navigation in a simulator, use a router).\n */\n onCtaClick?: (cta: import('../types').CtaConfig) => void;\n}\n\n/**\n * LiveStateAlert\n *\n * Renders an Alert component (Nimbus) for alert/warning types.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateAlert({\n data,\n trackingConfig,\n onClose,\n onCtaClick,\n}: LiveStateAlertProps) {\n const track = useTrackEvent();\n const appearance = data.type === 'alert' ? 'danger' : 'warning';\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n if (onCtaClick) {\n onCtaClick(data.cta);\n } else {\n handleCtaClick(data.cta);\n }\n }, [data, trackingConfig, buildEventProperties, track, onCtaClick]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <Alert\n appearance={appearance}\n title={data.title}\n onRemove={onClose ? handleClose : undefined}>\n <Box\n display=\"flex\"\n alignItems=\"flex-start\"\n gap=\"3\"\n flexWrap=\"wrap\"\n flexDirection=\"column\">\n <Box flex=\"1 1 auto\" minWidth=\"220px\">\n <Text>{data.message}</Text>\n </Box>\n\n <Box display=\"flex\" justifyContent=\"flex-end\" marginTop=\"2\">\n <Button appearance=\"primary\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Box>\n </Box>\n </Alert>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { Card, Box, Text, Link, Icon } from '@nimbus-ds/components';\nimport { MoneyIcon, CloseIcon } from '@nimbus-ds/icons';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateInfoProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n defaultVariant?: 'blue' | 'white';\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n /**\n * Override mobile layout detection.\n * When provided, bypasses `window.innerWidth < 750` so simulators and\n * testing tools can force a specific layout without resizing the window.\n */\n isMobile?: boolean;\n /**\n * Override CTA click behaviour.\n * When provided, replaces default navigation so the caller controls what\n * happens on click (e.g. prevent navigation in a simulator, use a router).\n */\n onCtaClick?: (cta: import('../types').CtaConfig) => void;\n}\n\nconst ICON_COLOR_MAP = {\n blue: { background: '#0050C3', icon: '#FFFFFF' },\n white: { background: '#FFFFFF', icon: '#0059D5' },\n} as const;\n\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type.\n * Uses MoneyIcon with colored circle background, Text components,\n * and a Link-style CTA — matching the LendingBanner design reference.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateInfo({\n data,\n trackingConfig,\n defaultVariant = 'blue',\n onClose,\n isMobile: isMobileProp,\n onCtaClick,\n}: LiveStateInfoProps) {\n const track = useTrackEvent();\n const variant = data.variant || defaultVariant;\n const iconConfig = ICON_COLOR_MAP[variant];\n\n const [isMobileWindow, setIsMobileWindow] = useState(\n () => window.innerWidth < 750,\n );\n\n useEffect(() => {\n const handler = () => setIsMobileWindow(window.innerWidth < 750);\n window.addEventListener('resize', handler);\n return () => window.removeEventListener('resize', handler);\n }, []);\n\n // Prop overrides window detection — allows simulators/tests to force layout\n const isMobile = isMobileProp ?? isMobileWindow;\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n if (onCtaClick) {\n onCtaClick(data.cta);\n } else {\n handleCtaClick(data.cta);\n }\n }, [data, trackingConfig, buildEventProperties, track, onCtaClick]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const ctaLink = (\n <Link\n as=\"a\"\n textDecoration=\"none\"\n onClick={handleClick}\n data-testid=\"live-state-cta-link\">\n <Text color=\"primary-interactive\" fontSize=\"base\">\n {data.cta.label}\n </Text>\n </Link>\n );\n\n return (\n <Card>\n <Box display=\"flex\" flexDirection=\"row\" justifyContent=\"space-between\">\n {/* Left: icon + text (+ cta on mobile) */}\n <Box\n display=\"flex\"\n gap=\"4\"\n alignItems={isMobile ? 'flex-start' : 'center'}\n paddingRight=\"1-5\">\n <Box minWidth=\"32px\">\n <div\n style={{\n width: 32,\n height: 32,\n borderRadius: '35%',\n borderColor: variant === 'white' ? '#E7E7E7' : 'transparent',\n borderWidth: 1,\n borderStyle: 'solid',\n background: iconConfig.background,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}>\n <MoneyIcon style={{ color: iconConfig.icon }} />\n </div>\n </Box>\n\n <Box display=\"grid\" gap=\"2\">\n <Box>\n <Text fontSize=\"base\" color=\"neutral-textHigh\">\n {data.title}\n </Text>\n <Text fontSize=\"base\" color=\"neutral-textLow\">\n {data.message}\n </Text>\n </Box>\n\n {/* CTA shown below text on mobile */}\n {isMobile && ctaLink}\n </Box>\n </Box>\n\n {/* Right: cta (desktop only) + close button */}\n {(!isMobile || onClose) && (\n <Box\n display=\"flex\"\n flexDirection={isMobile ? 'column' : 'row'}\n alignItems={isMobile ? 'flex-end' : 'center'}\n gap=\"2\">\n {/* CTA shown on the right side on desktop */}\n {!isMobile && ctaLink}\n\n {onClose && (\n <button\n type=\"button\"\n data-testid=\"live-state-close-button\"\n aria-label=\"Fechar notificação\"\n onClick={handleClose}\n style={{\n background: 'none',\n border: 'none',\n padding: 0,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}>\n <Icon\n source={<CloseIcon width=\"18px\" height=\"18px\" />}\n color=\"neutral-interactive\"\n />\n </button>\n )}\n </Box>\n )}\n </Box>\n </Card>\n );\n}\n","import type { LiveStateRendererProps } from '../types';\nimport { useClosable } from '../hooks/useClosable';\nimport { LiveStateAlert } from './LiveStateAlert';\nimport { LiveStateInfo } from './LiveStateInfo';\n\n/**\n * LiveStateRenderer\n *\n * Main component that validates payload, filters by context, and renders\n * the appropriate visual component (Alert or Info) based on type.\n * Handles closable notifications via useClosable when closable is configured.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateRenderer({\n data,\n loading,\n trackingConfig,\n allowedContexts,\n defaultVariant,\n isMobile,\n onCtaClick,\n}: LiveStateRendererProps) {\n const { isVisible, close } = useClosable({\n context: data?.context ?? '',\n id: data?.campaignId,\n maxCloseTimes: data?.metadata?.maxCloseTimes,\n expiresIn: data?.metadata?.expiresIn,\n });\n\n // Don't render while loading or no data\n if (loading || !data) {\n return null;\n }\n\n // Validate required fields\n if (\n !data.context ||\n !data.type ||\n !data.title ||\n !data.message ||\n !data.cta?.label ||\n !data.cta?.url ||\n !data.cta?.type\n ) {\n console.warn('[LiveState] Invalid payload, missing required fields', data);\n return null;\n }\n\n // Filter by allowed contexts\n if (allowedContexts && !allowedContexts.includes(data.context)) {\n return null;\n }\n\n // Awaiting localStorage check\n if (isVisible === null) {\n return null;\n }\n\n // Hidden — user reached maxCloseTimes\n if (!isVisible) {\n return null;\n }\n\n // Pass onClose whenever closable is true.\n // campaignId is optional — useClosable handles id=undefined gracefully\n // (always visible, no localStorage tracking).\n const onClose = data.closable ? close : undefined;\n\n // Render appropriate component based on type\n if (data.type === 'alert' || data.type === 'warning') {\n return (\n <LiveStateAlert\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n onCtaClick={onCtaClick}\n />\n );\n }\n\n if (data.type === 'info') {\n return (\n <LiveStateInfo\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n defaultVariant={defaultVariant}\n isMobile={isMobile}\n onCtaClick={onCtaClick}\n />\n );\n }\n\n console.warn(`[LiveState] Unknown type: ${data.type}`);\n return null;\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -182,8 +182,9 @@ function I({ context: e, id: n, maxCloseTimes: a = 3, expiresIn: o }) {
182
182
  ]), {
183
183
  isVisible: s,
184
184
  close: t(() => {
185
- if (!n) return;
186
- let t = P(), r = t[e]?.[n]?.count ?? 0, i = {
185
+ if (c(!1), !n) return;
186
+ let t = P(), r = t[e]?.[n]?.count ?? 0;
187
+ F({
187
188
  ...t,
188
189
  [e]: {
189
190
  ...t[e] ?? {},
@@ -192,8 +193,7 @@ function I({ context: e, id: n, maxCloseTimes: a = 3, expiresIn: o }) {
192
193
  closedAt: Date.now()
193
194
  }
194
195
  }
195
- };
196
- c(!1), F(i);
196
+ });
197
197
  }, [e, n])
198
198
  };
199
199
  }
@@ -410,7 +410,7 @@ function V({ data: e, loading: t, trackingConfig: n, allowedContexts: r, default
410
410
  if (t || !e) return null;
411
411
  if (!e.context || !e.type || !e.title || !e.message || !e.cta?.label || !e.cta?.url || !e.cta?.type) return console.warn("[LiveState] Invalid payload, missing required fields", e), null;
412
412
  if (r && !r.includes(e.context) || s === null || !s) return null;
413
- let u = e.closable && e.campaignId ? l : void 0;
413
+ let u = e.closable ? l : void 0;
414
414
  return e.type === "alert" || e.type === "warning" ? /* @__PURE__ */ c(R, {
415
415
  data: e,
416
416
  onClose: u,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/utils/analytics.ts","../src/providers/LiveStateProvider.tsx","../src/hooks/useLiveState.ts","../src/hooks/useTrackEvent.ts","../src/utils/closable-storage.ts","../src/hooks/useClosable.ts","../src/utils/cta.ts","../src/components/LiveStateAlert.tsx","../src/components/LiveStateInfo.tsx","../src/components/LiveStateRenderer.tsx"],"sourcesContent":["import * as amplitude from '@amplitude/analytics-browser';\nimport type { TrackingProperties, TrackingValue } from '../types';\n\n/**\n * Isolated Amplitude instance for the lib — avoids conflicts with the\n * consumer app's own Amplitude instance when both coexist on the same page.\n */\nconst amplitudeInstance = amplitude.createInstance();\n\n/**\n * Initialize Amplitude (fail silently)\n */\nexport function initializeAmplitude(apiKey: string): void {\n try {\n if (!apiKey) {\n console.warn('[LiveState] Amplitude API key not provided');\n return;\n }\n\n amplitudeInstance.init(apiKey, {\n defaultTracking: false,\n });\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Amplitude:', error);\n }\n}\n\n/**\n * Initialize Clarity (fail silently)\n */\nexport async function initializeClarity(projectId?: string): Promise<void> {\n try {\n // Check if Clarity is already loaded by the client\n if (window.clarity) {\n console.log('[LiveState] Clarity already initialized by client');\n return;\n }\n\n // If client provided project ID, use it\n const finalProjectId = projectId || getClientClarityProjectId();\n\n if (!finalProjectId) {\n console.warn('[LiveState] Clarity project ID not provided');\n return;\n }\n\n // Initialize Clarity with project ID\n const Clarity = (await import('@microsoft/clarity')).default;\n Clarity.init(finalProjectId);\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Clarity:', error);\n }\n}\n\n/**\n * Try to extract Clarity project ID from client's installation\n */\nfunction getClientClarityProjectId(): string | undefined {\n try {\n // Check if Clarity script tag exists\n const clarityScript = document.querySelector('script[src*=\"clarity.ms\"]');\n if (clarityScript) {\n const src = clarityScript.getAttribute('src');\n const match = src?.match(/\\/([a-z0-9]+)$/);\n return match?.[1];\n }\n\n // Check global clarity config: shape is clarity.q = [['init', projectId, ...]]\n const projectId = window.clarity?.q?.[0]?.[1];\n if (typeof projectId === 'string') {\n return projectId;\n }\n } catch {\n // Fail silently\n }\n\n return undefined;\n}\n\n/**\n * Track event with Amplitude (fail silently)\n */\nexport function trackAmplitudeEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n amplitudeInstance.track(eventName, properties);\n } catch (error) {\n console.warn('[LiveState] Failed to track Amplitude event:', error);\n }\n}\n\n/**\n * Track event with Clarity (fail silently)\n */\nexport function trackClarityEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n if (window.clarity) {\n window.clarity('event', eventName);\n\n // Set custom tags for properties\n if (properties) {\n Object.entries(properties).forEach(([key, value]) => {\n window.clarity?.('set', key, String(value));\n });\n }\n }\n } catch (error) {\n console.warn('[LiveState] Failed to track Clarity event:', error);\n }\n}\n\n/**\n * Builds a TrackingProperties object from a loose record, dropping entries\n * whose value is undefined so callers don't need to guard optional fields.\n */\nexport function buildTrackingProperties(\n source: Record<string, TrackingValue | undefined>,\n): TrackingProperties {\n return Object.fromEntries(\n Object.entries(source).filter(\n (entry): entry is [string, TrackingValue] => entry[1] !== undefined,\n ),\n );\n}\n\n/**\n * Track event with both Amplitude and Clarity (fail silently)\n */\nexport function trackEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n trackAmplitudeEvent(eventName, properties);\n trackClarityEvent(eventName, properties);\n}\n\n/**\n * Clarity command API shape as documented in the Clarity SDK\n * https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-api\n */\ntype ClarityCommand =\n | 'init'\n | 'event'\n | 'set'\n | 'identify'\n | 'consent'\n | 'upgrade';\n\ndeclare global {\n interface Window {\n clarity?: {\n (command: ClarityCommand, ...args: string[]): void;\n q?: string[][];\n };\n }\n}\n","import React, { createContext, useContext, useEffect } from 'react';\nimport { SWRConfig } from 'swr';\nimport type {\n LiveStateFetcher,\n AnalyticsConfig,\n TrackingProperties,\n} from '../types';\nimport { initializeAmplitude, initializeClarity } from '../utils/analytics';\n\ninterface LiveStateContextValue {\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\nconst LiveStateContext = createContext<LiveStateContextValue | null>(null);\n\nexport interface LiveStateProviderProps {\n children: React.ReactNode;\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\n/**\n * LiveStateProvider\n *\n * Root-level provider that configures fetcher function and analytics.\n * Initializes Amplitude and Clarity on mount.\n *\n * The optional `onEvent` callback is fired on every tracking event before\n * sending to Amplitude/Clarity — useful for simulators and debugging tools.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateProvider({\n children,\n fetcher,\n analytics,\n onEvent,\n}: LiveStateProviderProps) {\n useEffect(() => {\n if (analytics?.amplitudeKey) {\n initializeAmplitude(analytics.amplitudeKey);\n }\n\n if (analytics?.clarityProjectId) {\n initializeClarity(analytics.clarityProjectId);\n }\n }, [analytics]);\n\n return (\n <SWRConfig value={{ provider: () => new Map() }}>\n <LiveStateContext.Provider value={{ fetcher, analytics, onEvent }}>\n {children}\n </LiveStateContext.Provider>\n </SWRConfig>\n );\n}\n\n/**\n * useLiveStateContext\n *\n * Internal hook to access LiveStateContext\n */\nexport function useLiveStateContext() {\n const context = useContext(LiveStateContext);\n\n if (!context) {\n throw new Error('useLiveState must be used within LiveStateProvider');\n }\n\n return context;\n}\n","import useSWR from 'swr';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport type { LiveStateResponse } from '../types';\n\ninterface UseLiveStateReturn {\n /** Live state data */\n liveState: LiveStateResponse | null;\n\n /** Loading state */\n isLoading: boolean;\n\n /** Error state */\n error: Error | null;\n\n /** Manual refresh function */\n refresh: () => Promise<void>;\n}\n\n/**\n * useLiveState hook\n *\n * Fetches and manages live state data using SWR with automatic caching,\n * deduplication, and revalidation.\n *\n * Must be used within LiveStateProvider. See examples/ directory for usage.\n */\nexport function useLiveState(): UseLiveStateReturn {\n const { fetcher } = useLiveStateContext();\n\n const { data, error, isLoading, mutate } = useSWR<LiveStateResponse | null>(\n 'live-state',\n fetcher,\n {\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n dedupingInterval: 60000, // 1 minute\n shouldRetryOnError: false, // Fail silently\n onError: err => {\n console.warn('[LiveState] Failed to fetch live state:', err);\n },\n },\n );\n\n const refresh = async () => {\n try {\n await mutate();\n } catch (err) {\n console.warn('[LiveState] Failed to refresh live state:', err);\n }\n };\n\n return {\n liveState: data ?? null,\n isLoading,\n error: error ?? null,\n refresh,\n };\n}\n","import { useCallback } from 'react';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport { trackEvent } from '../utils/analytics';\nimport type { TrackingProperties } from '../types';\n\n/**\n * useTrackEvent\n *\n * Returns a `track` function that fires both the internal analytics\n * (Amplitude + Clarity) and the optional `onEvent` callback provided\n * to LiveStateProvider — useful for simulators and debugging tools.\n */\nexport function useTrackEvent() {\n const { onEvent } = useLiveStateContext();\n\n const track = useCallback(\n (eventName: string, properties?: TrackingProperties) => {\n onEvent?.(eventName, properties);\n trackEvent(eventName, properties);\n },\n [onEvent],\n );\n\n return track;\n}\n","export const LIVE_STATE_STORAGE_KEY = '@tiendanube/live-state:closable';\n\n/** @internal */\nconst STORAGE_KEY = LIVE_STATE_STORAGE_KEY;\n\nexport interface ClosableState {\n count: number;\n closedAt: number;\n}\n\nexport type ClosableStates = Record<string, Record<string, ClosableState>>;\n\n/**\n * Reads closable states from localStorage.\n * Normalises legacy format (plain number) to the current shape ({ count, closedAt }).\n * Returns an empty object on any error (fail-silent).\n */\nexport function getClosableStates(): ClosableStates {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return {};\n\n const parsed = JSON.parse(raw) as unknown;\n if (typeof parsed !== 'object' || parsed === null) return {};\n\n const normalized: ClosableStates = {};\n\n for (const [ctx, ctxState] of Object.entries(\n parsed as Record<string, unknown>,\n )) {\n if (typeof ctxState !== 'object' || ctxState === null) continue;\n\n normalized[ctx] = {};\n\n for (const [id, entry] of Object.entries(\n ctxState as Record<string, unknown>,\n )) {\n if (typeof entry === 'number') {\n // legacy format: plain close count\n normalized[ctx][id] = { count: entry, closedAt: 0 };\n } else if (typeof entry === 'object' && entry !== null) {\n const candidate = entry as Partial<ClosableState>;\n normalized[ctx][id] = {\n count: typeof candidate.count === 'number' ? candidate.count : 0,\n closedAt:\n typeof candidate.closedAt === 'number' ? candidate.closedAt : 0,\n };\n }\n }\n }\n\n return normalized;\n } catch {\n return {};\n }\n}\n\n/**\n * Persists closable states to localStorage.\n * Fails silently if localStorage is unavailable or full.\n */\nexport function setClosableStates(states: ClosableStates): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(states));\n } catch {\n // localStorage unavailable or quota exceeded — application continues normally\n }\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport {\n getClosableStates,\n setClosableStates,\n} from '../utils/closable-storage';\n\nexport interface UseClosableOptions {\n /** Notification context (e.g. 'awareness', 'charge') */\n context: string;\n /** Unique notification ID (campaignId). If absent, always visible — no close tracking. */\n id: string | undefined;\n /** Maximum number of times the user can close before it is hidden permanently */\n maxCloseTimes?: number;\n /** Milliseconds after which the close counter resets (optional) */\n expiresIn?: number;\n}\n\nexport interface UseClosableReturn {\n /** Whether the notification should be shown. null = initial check in progress. */\n isVisible: boolean | null;\n /** Call this to record a close action */\n close: () => void;\n}\n\n/**\n * Manages the close state of a notification using localStorage.\n *\n * After the user closes a notification `maxCloseTimes` times, it is hidden\n * permanently. Optionally, the counter resets after `expiresIn` milliseconds.\n *\n * Fails silently — errors in localStorage never break the application.\n *\n * @example\n * ```tsx\n * const { isVisible, close } = useClosable({\n * context: 'awareness',\n * id: 'awareness-2026-q1',\n * maxCloseTimes: 3,\n * expiresIn: 86_400_000, // 1 day\n * });\n *\n * if (!isVisible) return null;\n * return <Notification onClose={close} />;\n * ```\n */\nexport function useClosable({\n context,\n id,\n maxCloseTimes = 3,\n expiresIn,\n}: UseClosableOptions): UseClosableReturn {\n const [isVisible, setIsVisible] = useState<boolean | null>(null);\n\n useEffect(() => {\n // No ID means no close tracking — always show\n if (!id) {\n setIsVisible(true);\n return;\n }\n\n const states = getClosableStates();\n const entry = states[context]?.[id];\n\n if (!entry) {\n setIsVisible(true);\n return;\n }\n\n const { count, closedAt } = entry;\n\n // Check expiry — reset counter and show if expired\n if (expiresIn != null && closedAt > 0) {\n const elapsed = Date.now() - closedAt;\n if (elapsed > expiresIn) {\n const updated = { ...states };\n if (updated[context]) {\n delete updated[context][id];\n setClosableStates(updated);\n }\n setIsVisible(true);\n return;\n }\n }\n\n setIsVisible(count < maxCloseTimes);\n }, [context, id, maxCloseTimes, expiresIn]);\n\n const close = useCallback(() => {\n if (!id) return;\n\n const states = getClosableStates();\n const currentCount = states[context]?.[id]?.count ?? 0;\n\n const updated: typeof states = {\n ...states,\n [context]: {\n ...(states[context] ?? {}),\n [id]: {\n count: currentCount + 1,\n closedAt: Date.now(),\n },\n },\n };\n\n setIsVisible(false);\n setClosableStates(updated);\n }, [context, id]);\n\n return { isVisible, close };\n}\n","import type { CtaConfig } from '../types';\n\n/**\n * Handle CTA click based on type\n *\n * @param cta - CTA configuration from LiveStateResponse\n */\nexport function handleCtaClick(cta: CtaConfig): void {\n try {\n switch (cta.type) {\n case 'redirect':\n // Navigate in same window\n window.location.href = cta.url;\n break;\n\n case 'whatsapp': {\n // Open WhatsApp in new tab\n const whatsappUrl = cta.whatsappMessage\n ? `${cta.url}?text=${encodeURIComponent(cta.whatsappMessage)}`\n : cta.url;\n window.open(whatsappUrl, '_blank');\n break;\n }\n\n case 'external':\n // Open in new tab\n window.open(cta.url, '_blank');\n break;\n\n default:\n console.warn(`[LiveState] Unknown CTA type: ${cta.type}`);\n }\n } catch (error) {\n console.warn('[LiveState] Failed to handle CTA click:', error);\n }\n}\n","import { useCallback, useEffect } from 'react';\nimport { Alert, Box, Button, Text } from '@nimbus-ds/components';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateAlertProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n /**\n * Override CTA click behaviour.\n * When provided, replaces default navigation so the caller controls what\n * happens on click (e.g. prevent navigation in a simulator, use a router).\n */\n onCtaClick?: (cta: import('../types').CtaConfig) => void;\n}\n\n/**\n * LiveStateAlert\n *\n * Renders an Alert component (Nimbus) for alert/warning types.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateAlert({\n data,\n trackingConfig,\n onClose,\n onCtaClick,\n}: LiveStateAlertProps) {\n const track = useTrackEvent();\n const appearance = data.type === 'alert' ? 'danger' : 'warning';\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n if (onCtaClick) {\n onCtaClick(data.cta);\n } else {\n handleCtaClick(data.cta);\n }\n }, [data, trackingConfig, buildEventProperties, track, onCtaClick]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <Alert\n appearance={appearance}\n title={data.title}\n onRemove={onClose ? handleClose : undefined}>\n <Box\n display=\"flex\"\n alignItems=\"flex-start\"\n gap=\"3\"\n flexWrap=\"wrap\"\n flexDirection=\"column\">\n <Box flex=\"1 1 auto\" minWidth=\"220px\">\n <Text>{data.message}</Text>\n </Box>\n\n <Box display=\"flex\" justifyContent=\"flex-end\" marginTop=\"2\">\n <Button appearance=\"primary\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Box>\n </Box>\n </Alert>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { Card, Box, Text, Link, Icon } from '@nimbus-ds/components';\nimport { MoneyIcon, CloseIcon } from '@nimbus-ds/icons';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateInfoProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n defaultVariant?: 'blue' | 'white';\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n /**\n * Override mobile layout detection.\n * When provided, bypasses `window.innerWidth < 750` so simulators and\n * testing tools can force a specific layout without resizing the window.\n */\n isMobile?: boolean;\n /**\n * Override CTA click behaviour.\n * When provided, replaces default navigation so the caller controls what\n * happens on click (e.g. prevent navigation in a simulator, use a router).\n */\n onCtaClick?: (cta: import('../types').CtaConfig) => void;\n}\n\nconst ICON_COLOR_MAP = {\n blue: { background: '#0050C3', icon: '#FFFFFF' },\n white: { background: '#FFFFFF', icon: '#0059D5' },\n} as const;\n\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type.\n * Uses MoneyIcon with colored circle background, Text components,\n * and a Link-style CTA — matching the LendingBanner design reference.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateInfo({\n data,\n trackingConfig,\n defaultVariant = 'blue',\n onClose,\n isMobile: isMobileProp,\n onCtaClick,\n}: LiveStateInfoProps) {\n const track = useTrackEvent();\n const variant = data.variant || defaultVariant;\n const iconConfig = ICON_COLOR_MAP[variant];\n\n const [isMobileWindow, setIsMobileWindow] = useState(\n () => window.innerWidth < 750,\n );\n\n useEffect(() => {\n const handler = () => setIsMobileWindow(window.innerWidth < 750);\n window.addEventListener('resize', handler);\n return () => window.removeEventListener('resize', handler);\n }, []);\n\n // Prop overrides window detection — allows simulators/tests to force layout\n const isMobile = isMobileProp ?? isMobileWindow;\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n if (onCtaClick) {\n onCtaClick(data.cta);\n } else {\n handleCtaClick(data.cta);\n }\n }, [data, trackingConfig, buildEventProperties, track, onCtaClick]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const ctaLink = (\n <Link\n as=\"a\"\n textDecoration=\"none\"\n onClick={handleClick}\n data-testid=\"live-state-cta-link\">\n <Text color=\"primary-interactive\" fontSize=\"base\">\n {data.cta.label}\n </Text>\n </Link>\n );\n\n return (\n <Card>\n <Box display=\"flex\" flexDirection=\"row\" justifyContent=\"space-between\">\n {/* Left: icon + text (+ cta on mobile) */}\n <Box\n display=\"flex\"\n gap=\"4\"\n alignItems={isMobile ? 'flex-start' : 'center'}\n paddingRight=\"1-5\">\n <Box minWidth=\"32px\">\n <div\n style={{\n width: 32,\n height: 32,\n borderRadius: '35%',\n borderColor: variant === 'white' ? '#E7E7E7' : 'transparent',\n borderWidth: 1,\n borderStyle: 'solid',\n background: iconConfig.background,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}>\n <MoneyIcon style={{ color: iconConfig.icon }} />\n </div>\n </Box>\n\n <Box display=\"grid\" gap=\"2\">\n <Box>\n <Text fontSize=\"base\" color=\"neutral-textHigh\">\n {data.title}\n </Text>\n <Text fontSize=\"base\" color=\"neutral-textLow\">\n {data.message}\n </Text>\n </Box>\n\n {/* CTA shown below text on mobile */}\n {isMobile && ctaLink}\n </Box>\n </Box>\n\n {/* Right: cta (desktop only) + close button */}\n {(!isMobile || onClose) && (\n <Box\n display=\"flex\"\n flexDirection={isMobile ? 'column' : 'row'}\n alignItems={isMobile ? 'flex-end' : 'center'}\n gap=\"2\">\n {/* CTA shown on the right side on desktop */}\n {!isMobile && ctaLink}\n\n {onClose && (\n <button\n type=\"button\"\n data-testid=\"live-state-close-button\"\n aria-label=\"Fechar notificação\"\n onClick={handleClose}\n style={{\n background: 'none',\n border: 'none',\n padding: 0,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}>\n <Icon\n source={<CloseIcon width=\"18px\" height=\"18px\" />}\n color=\"neutral-interactive\"\n />\n </button>\n )}\n </Box>\n )}\n </Box>\n </Card>\n );\n}\n","import type { LiveStateRendererProps } from '../types';\nimport { useClosable } from '../hooks/useClosable';\nimport { LiveStateAlert } from './LiveStateAlert';\nimport { LiveStateInfo } from './LiveStateInfo';\n\n/**\n * LiveStateRenderer\n *\n * Main component that validates payload, filters by context, and renders\n * the appropriate visual component (Alert or Info) based on type.\n * Handles closable notifications via useClosable when closable is configured.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateRenderer({\n data,\n loading,\n trackingConfig,\n allowedContexts,\n defaultVariant,\n isMobile,\n onCtaClick,\n}: LiveStateRendererProps) {\n const { isVisible, close } = useClosable({\n context: data?.context ?? '',\n id: data?.campaignId,\n maxCloseTimes: data?.metadata?.maxCloseTimes,\n expiresIn: data?.metadata?.expiresIn,\n });\n\n // Don't render while loading or no data\n if (loading || !data) {\n return null;\n }\n\n // Validate required fields\n if (\n !data.context ||\n !data.type ||\n !data.title ||\n !data.message ||\n !data.cta?.label ||\n !data.cta?.url ||\n !data.cta?.type\n ) {\n console.warn('[LiveState] Invalid payload, missing required fields', data);\n return null;\n }\n\n // Filter by allowed contexts\n if (allowedContexts && !allowedContexts.includes(data.context)) {\n return null;\n }\n\n // Awaiting localStorage check\n if (isVisible === null) {\n return null;\n }\n\n // Hidden — user reached maxCloseTimes\n if (!isVisible) {\n return null;\n }\n\n // Only pass onClose when closable is configured and notification has a campaignId to track\n const onClose = data.closable && data.campaignId ? close : undefined;\n\n // Render appropriate component based on type\n if (data.type === 'alert' || data.type === 'warning') {\n return (\n <LiveStateAlert\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n onCtaClick={onCtaClick}\n />\n );\n }\n\n if (data.type === 'info') {\n return (\n <LiveStateInfo\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n defaultVariant={defaultVariant}\n isMobile={isMobile}\n onCtaClick={onCtaClick}\n />\n );\n }\n\n console.warn(`[LiveState] Unknown type: ${data.type}`);\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/utils/analytics.ts","../src/providers/LiveStateProvider.tsx","../src/hooks/useLiveState.ts","../src/hooks/useTrackEvent.ts","../src/utils/closable-storage.ts","../src/hooks/useClosable.ts","../src/utils/cta.ts","../src/components/LiveStateAlert.tsx","../src/components/LiveStateInfo.tsx","../src/components/LiveStateRenderer.tsx"],"sourcesContent":["import * as amplitude from '@amplitude/analytics-browser';\nimport type { TrackingProperties, TrackingValue } from '../types';\n\n/**\n * Isolated Amplitude instance for the lib — avoids conflicts with the\n * consumer app's own Amplitude instance when both coexist on the same page.\n */\nconst amplitudeInstance = amplitude.createInstance();\n\n/**\n * Initialize Amplitude (fail silently)\n */\nexport function initializeAmplitude(apiKey: string): void {\n try {\n if (!apiKey) {\n console.warn('[LiveState] Amplitude API key not provided');\n return;\n }\n\n amplitudeInstance.init(apiKey, {\n defaultTracking: false,\n });\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Amplitude:', error);\n }\n}\n\n/**\n * Initialize Clarity (fail silently)\n */\nexport async function initializeClarity(projectId?: string): Promise<void> {\n try {\n // Check if Clarity is already loaded by the client\n if (window.clarity) {\n console.log('[LiveState] Clarity already initialized by client');\n return;\n }\n\n // If client provided project ID, use it\n const finalProjectId = projectId || getClientClarityProjectId();\n\n if (!finalProjectId) {\n console.warn('[LiveState] Clarity project ID not provided');\n return;\n }\n\n // Initialize Clarity with project ID\n const Clarity = (await import('@microsoft/clarity')).default;\n Clarity.init(finalProjectId);\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Clarity:', error);\n }\n}\n\n/**\n * Try to extract Clarity project ID from client's installation\n */\nfunction getClientClarityProjectId(): string | undefined {\n try {\n // Check if Clarity script tag exists\n const clarityScript = document.querySelector('script[src*=\"clarity.ms\"]');\n if (clarityScript) {\n const src = clarityScript.getAttribute('src');\n const match = src?.match(/\\/([a-z0-9]+)$/);\n return match?.[1];\n }\n\n // Check global clarity config: shape is clarity.q = [['init', projectId, ...]]\n const projectId = window.clarity?.q?.[0]?.[1];\n if (typeof projectId === 'string') {\n return projectId;\n }\n } catch {\n // Fail silently\n }\n\n return undefined;\n}\n\n/**\n * Track event with Amplitude (fail silently)\n */\nexport function trackAmplitudeEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n amplitudeInstance.track(eventName, properties);\n } catch (error) {\n console.warn('[LiveState] Failed to track Amplitude event:', error);\n }\n}\n\n/**\n * Track event with Clarity (fail silently)\n */\nexport function trackClarityEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n if (window.clarity) {\n window.clarity('event', eventName);\n\n // Set custom tags for properties\n if (properties) {\n Object.entries(properties).forEach(([key, value]) => {\n window.clarity?.('set', key, String(value));\n });\n }\n }\n } catch (error) {\n console.warn('[LiveState] Failed to track Clarity event:', error);\n }\n}\n\n/**\n * Builds a TrackingProperties object from a loose record, dropping entries\n * whose value is undefined so callers don't need to guard optional fields.\n */\nexport function buildTrackingProperties(\n source: Record<string, TrackingValue | undefined>,\n): TrackingProperties {\n return Object.fromEntries(\n Object.entries(source).filter(\n (entry): entry is [string, TrackingValue] => entry[1] !== undefined,\n ),\n );\n}\n\n/**\n * Track event with both Amplitude and Clarity (fail silently)\n */\nexport function trackEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n trackAmplitudeEvent(eventName, properties);\n trackClarityEvent(eventName, properties);\n}\n\n/**\n * Clarity command API shape as documented in the Clarity SDK\n * https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-api\n */\ntype ClarityCommand =\n | 'init'\n | 'event'\n | 'set'\n | 'identify'\n | 'consent'\n | 'upgrade';\n\ndeclare global {\n interface Window {\n clarity?: {\n (command: ClarityCommand, ...args: string[]): void;\n q?: string[][];\n };\n }\n}\n","import React, { createContext, useContext, useEffect } from 'react';\nimport { SWRConfig } from 'swr';\nimport type {\n LiveStateFetcher,\n AnalyticsConfig,\n TrackingProperties,\n} from '../types';\nimport { initializeAmplitude, initializeClarity } from '../utils/analytics';\n\ninterface LiveStateContextValue {\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\nconst LiveStateContext = createContext<LiveStateContextValue | null>(null);\n\nexport interface LiveStateProviderProps {\n children: React.ReactNode;\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\n/**\n * LiveStateProvider\n *\n * Root-level provider that configures fetcher function and analytics.\n * Initializes Amplitude and Clarity on mount.\n *\n * The optional `onEvent` callback is fired on every tracking event before\n * sending to Amplitude/Clarity — useful for simulators and debugging tools.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateProvider({\n children,\n fetcher,\n analytics,\n onEvent,\n}: LiveStateProviderProps) {\n useEffect(() => {\n if (analytics?.amplitudeKey) {\n initializeAmplitude(analytics.amplitudeKey);\n }\n\n if (analytics?.clarityProjectId) {\n initializeClarity(analytics.clarityProjectId);\n }\n }, [analytics]);\n\n return (\n <SWRConfig value={{ provider: () => new Map() }}>\n <LiveStateContext.Provider value={{ fetcher, analytics, onEvent }}>\n {children}\n </LiveStateContext.Provider>\n </SWRConfig>\n );\n}\n\n/**\n * useLiveStateContext\n *\n * Internal hook to access LiveStateContext\n */\nexport function useLiveStateContext() {\n const context = useContext(LiveStateContext);\n\n if (!context) {\n throw new Error('useLiveState must be used within LiveStateProvider');\n }\n\n return context;\n}\n","import useSWR from 'swr';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport type { LiveStateResponse } from '../types';\n\ninterface UseLiveStateReturn {\n /** Live state data */\n liveState: LiveStateResponse | null;\n\n /** Loading state */\n isLoading: boolean;\n\n /** Error state */\n error: Error | null;\n\n /** Manual refresh function */\n refresh: () => Promise<void>;\n}\n\n/**\n * useLiveState hook\n *\n * Fetches and manages live state data using SWR with automatic caching,\n * deduplication, and revalidation.\n *\n * Must be used within LiveStateProvider. See examples/ directory for usage.\n */\nexport function useLiveState(): UseLiveStateReturn {\n const { fetcher } = useLiveStateContext();\n\n const { data, error, isLoading, mutate } = useSWR<LiveStateResponse | null>(\n 'live-state',\n fetcher,\n {\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n dedupingInterval: 60000, // 1 minute\n shouldRetryOnError: false, // Fail silently\n onError: err => {\n console.warn('[LiveState] Failed to fetch live state:', err);\n },\n },\n );\n\n const refresh = async () => {\n try {\n await mutate();\n } catch (err) {\n console.warn('[LiveState] Failed to refresh live state:', err);\n }\n };\n\n return {\n liveState: data ?? null,\n isLoading,\n error: error ?? null,\n refresh,\n };\n}\n","import { useCallback } from 'react';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport { trackEvent } from '../utils/analytics';\nimport type { TrackingProperties } from '../types';\n\n/**\n * useTrackEvent\n *\n * Returns a `track` function that fires both the internal analytics\n * (Amplitude + Clarity) and the optional `onEvent` callback provided\n * to LiveStateProvider — useful for simulators and debugging tools.\n */\nexport function useTrackEvent() {\n const { onEvent } = useLiveStateContext();\n\n const track = useCallback(\n (eventName: string, properties?: TrackingProperties) => {\n onEvent?.(eventName, properties);\n trackEvent(eventName, properties);\n },\n [onEvent],\n );\n\n return track;\n}\n","export const LIVE_STATE_STORAGE_KEY = '@tiendanube/live-state:closable';\n\n/** @internal */\nconst STORAGE_KEY = LIVE_STATE_STORAGE_KEY;\n\nexport interface ClosableState {\n count: number;\n closedAt: number;\n}\n\nexport type ClosableStates = Record<string, Record<string, ClosableState>>;\n\n/**\n * Reads closable states from localStorage.\n * Normalises legacy format (plain number) to the current shape ({ count, closedAt }).\n * Returns an empty object on any error (fail-silent).\n */\nexport function getClosableStates(): ClosableStates {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return {};\n\n const parsed = JSON.parse(raw) as unknown;\n if (typeof parsed !== 'object' || parsed === null) return {};\n\n const normalized: ClosableStates = {};\n\n for (const [ctx, ctxState] of Object.entries(\n parsed as Record<string, unknown>,\n )) {\n if (typeof ctxState !== 'object' || ctxState === null) continue;\n\n normalized[ctx] = {};\n\n for (const [id, entry] of Object.entries(\n ctxState as Record<string, unknown>,\n )) {\n if (typeof entry === 'number') {\n // legacy format: plain close count\n normalized[ctx][id] = { count: entry, closedAt: 0 };\n } else if (typeof entry === 'object' && entry !== null) {\n const candidate = entry as Partial<ClosableState>;\n normalized[ctx][id] = {\n count: typeof candidate.count === 'number' ? candidate.count : 0,\n closedAt:\n typeof candidate.closedAt === 'number' ? candidate.closedAt : 0,\n };\n }\n }\n }\n\n return normalized;\n } catch {\n return {};\n }\n}\n\n/**\n * Persists closable states to localStorage.\n * Fails silently if localStorage is unavailable or full.\n */\nexport function setClosableStates(states: ClosableStates): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(states));\n } catch {\n // localStorage unavailable or quota exceeded — application continues normally\n }\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport {\n getClosableStates,\n setClosableStates,\n} from '../utils/closable-storage';\n\nexport interface UseClosableOptions {\n /** Notification context (e.g. 'awareness', 'charge') */\n context: string;\n /** Unique notification ID (campaignId). If absent, always visible — no close tracking. */\n id: string | undefined;\n /** Maximum number of times the user can close before it is hidden permanently */\n maxCloseTimes?: number;\n /** Milliseconds after which the close counter resets (optional) */\n expiresIn?: number;\n}\n\nexport interface UseClosableReturn {\n /** Whether the notification should be shown. null = initial check in progress. */\n isVisible: boolean | null;\n /** Call this to record a close action */\n close: () => void;\n}\n\n/**\n * Manages the close state of a notification using localStorage.\n *\n * After the user closes a notification `maxCloseTimes` times, it is hidden\n * permanently. Optionally, the counter resets after `expiresIn` milliseconds.\n *\n * Fails silently — errors in localStorage never break the application.\n *\n * @example\n * ```tsx\n * const { isVisible, close } = useClosable({\n * context: 'awareness',\n * id: 'awareness-2026-q1',\n * maxCloseTimes: 3,\n * expiresIn: 86_400_000, // 1 day\n * });\n *\n * if (!isVisible) return null;\n * return <Notification onClose={close} />;\n * ```\n */\nexport function useClosable({\n context,\n id,\n maxCloseTimes = 3,\n expiresIn,\n}: UseClosableOptions): UseClosableReturn {\n const [isVisible, setIsVisible] = useState<boolean | null>(null);\n\n useEffect(() => {\n // No ID means no close tracking — always show\n if (!id) {\n setIsVisible(true);\n return;\n }\n\n const states = getClosableStates();\n const entry = states[context]?.[id];\n\n if (!entry) {\n setIsVisible(true);\n return;\n }\n\n const { count, closedAt } = entry;\n\n // Check expiry — reset counter and show if expired\n if (expiresIn != null && closedAt > 0) {\n const elapsed = Date.now() - closedAt;\n if (elapsed > expiresIn) {\n const updated = { ...states };\n if (updated[context]) {\n delete updated[context][id];\n setClosableStates(updated);\n }\n setIsVisible(true);\n return;\n }\n }\n\n setIsVisible(count < maxCloseTimes);\n }, [context, id, maxCloseTimes, expiresIn]);\n\n const close = useCallback(() => {\n // Always hide visually\n setIsVisible(false);\n\n // Only persist to localStorage if there is an id to track\n if (!id) return;\n\n const states = getClosableStates();\n const currentCount = states[context]?.[id]?.count ?? 0;\n\n const updated: typeof states = {\n ...states,\n [context]: {\n ...(states[context] ?? {}),\n [id]: {\n count: currentCount + 1,\n closedAt: Date.now(),\n },\n },\n };\n\n setClosableStates(updated);\n }, [context, id]);\n\n return { isVisible, close };\n}\n","import type { CtaConfig } from '../types';\n\n/**\n * Handle CTA click based on type\n *\n * @param cta - CTA configuration from LiveStateResponse\n */\nexport function handleCtaClick(cta: CtaConfig): void {\n try {\n switch (cta.type) {\n case 'redirect':\n // Navigate in same window\n window.location.href = cta.url;\n break;\n\n case 'whatsapp': {\n // Open WhatsApp in new tab\n const whatsappUrl = cta.whatsappMessage\n ? `${cta.url}?text=${encodeURIComponent(cta.whatsappMessage)}`\n : cta.url;\n window.open(whatsappUrl, '_blank');\n break;\n }\n\n case 'external':\n // Open in new tab\n window.open(cta.url, '_blank');\n break;\n\n default:\n console.warn(`[LiveState] Unknown CTA type: ${cta.type}`);\n }\n } catch (error) {\n console.warn('[LiveState] Failed to handle CTA click:', error);\n }\n}\n","import { useCallback, useEffect } from 'react';\nimport { Alert, Box, Button, Text } from '@nimbus-ds/components';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateAlertProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n /**\n * Override CTA click behaviour.\n * When provided, replaces default navigation so the caller controls what\n * happens on click (e.g. prevent navigation in a simulator, use a router).\n */\n onCtaClick?: (cta: import('../types').CtaConfig) => void;\n}\n\n/**\n * LiveStateAlert\n *\n * Renders an Alert component (Nimbus) for alert/warning types.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateAlert({\n data,\n trackingConfig,\n onClose,\n onCtaClick,\n}: LiveStateAlertProps) {\n const track = useTrackEvent();\n const appearance = data.type === 'alert' ? 'danger' : 'warning';\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n if (onCtaClick) {\n onCtaClick(data.cta);\n } else {\n handleCtaClick(data.cta);\n }\n }, [data, trackingConfig, buildEventProperties, track, onCtaClick]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <Alert\n appearance={appearance}\n title={data.title}\n onRemove={onClose ? handleClose : undefined}>\n <Box\n display=\"flex\"\n alignItems=\"flex-start\"\n gap=\"3\"\n flexWrap=\"wrap\"\n flexDirection=\"column\">\n <Box flex=\"1 1 auto\" minWidth=\"220px\">\n <Text>{data.message}</Text>\n </Box>\n\n <Box display=\"flex\" justifyContent=\"flex-end\" marginTop=\"2\">\n <Button appearance=\"primary\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Box>\n </Box>\n </Alert>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { Card, Box, Text, Link, Icon } from '@nimbus-ds/components';\nimport { MoneyIcon, CloseIcon } from '@nimbus-ds/icons';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateInfoProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n defaultVariant?: 'blue' | 'white';\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n /**\n * Override mobile layout detection.\n * When provided, bypasses `window.innerWidth < 750` so simulators and\n * testing tools can force a specific layout without resizing the window.\n */\n isMobile?: boolean;\n /**\n * Override CTA click behaviour.\n * When provided, replaces default navigation so the caller controls what\n * happens on click (e.g. prevent navigation in a simulator, use a router).\n */\n onCtaClick?: (cta: import('../types').CtaConfig) => void;\n}\n\nconst ICON_COLOR_MAP = {\n blue: { background: '#0050C3', icon: '#FFFFFF' },\n white: { background: '#FFFFFF', icon: '#0059D5' },\n} as const;\n\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type.\n * Uses MoneyIcon with colored circle background, Text components,\n * and a Link-style CTA — matching the LendingBanner design reference.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateInfo({\n data,\n trackingConfig,\n defaultVariant = 'blue',\n onClose,\n isMobile: isMobileProp,\n onCtaClick,\n}: LiveStateInfoProps) {\n const track = useTrackEvent();\n const variant = data.variant || defaultVariant;\n const iconConfig = ICON_COLOR_MAP[variant];\n\n const [isMobileWindow, setIsMobileWindow] = useState(\n () => window.innerWidth < 750,\n );\n\n useEffect(() => {\n const handler = () => setIsMobileWindow(window.innerWidth < 750);\n window.addEventListener('resize', handler);\n return () => window.removeEventListener('resize', handler);\n }, []);\n\n // Prop overrides window detection — allows simulators/tests to force layout\n const isMobile = isMobileProp ?? isMobileWindow;\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n if (onCtaClick) {\n onCtaClick(data.cta);\n } else {\n handleCtaClick(data.cta);\n }\n }, [data, trackingConfig, buildEventProperties, track, onCtaClick]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const ctaLink = (\n <Link\n as=\"a\"\n textDecoration=\"none\"\n onClick={handleClick}\n data-testid=\"live-state-cta-link\">\n <Text color=\"primary-interactive\" fontSize=\"base\">\n {data.cta.label}\n </Text>\n </Link>\n );\n\n return (\n <Card>\n <Box display=\"flex\" flexDirection=\"row\" justifyContent=\"space-between\">\n {/* Left: icon + text (+ cta on mobile) */}\n <Box\n display=\"flex\"\n gap=\"4\"\n alignItems={isMobile ? 'flex-start' : 'center'}\n paddingRight=\"1-5\">\n <Box minWidth=\"32px\">\n <div\n style={{\n width: 32,\n height: 32,\n borderRadius: '35%',\n borderColor: variant === 'white' ? '#E7E7E7' : 'transparent',\n borderWidth: 1,\n borderStyle: 'solid',\n background: iconConfig.background,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}>\n <MoneyIcon style={{ color: iconConfig.icon }} />\n </div>\n </Box>\n\n <Box display=\"grid\" gap=\"2\">\n <Box>\n <Text fontSize=\"base\" color=\"neutral-textHigh\">\n {data.title}\n </Text>\n <Text fontSize=\"base\" color=\"neutral-textLow\">\n {data.message}\n </Text>\n </Box>\n\n {/* CTA shown below text on mobile */}\n {isMobile && ctaLink}\n </Box>\n </Box>\n\n {/* Right: cta (desktop only) + close button */}\n {(!isMobile || onClose) && (\n <Box\n display=\"flex\"\n flexDirection={isMobile ? 'column' : 'row'}\n alignItems={isMobile ? 'flex-end' : 'center'}\n gap=\"2\">\n {/* CTA shown on the right side on desktop */}\n {!isMobile && ctaLink}\n\n {onClose && (\n <button\n type=\"button\"\n data-testid=\"live-state-close-button\"\n aria-label=\"Fechar notificação\"\n onClick={handleClose}\n style={{\n background: 'none',\n border: 'none',\n padding: 0,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}>\n <Icon\n source={<CloseIcon width=\"18px\" height=\"18px\" />}\n color=\"neutral-interactive\"\n />\n </button>\n )}\n </Box>\n )}\n </Box>\n </Card>\n );\n}\n","import type { LiveStateRendererProps } from '../types';\nimport { useClosable } from '../hooks/useClosable';\nimport { LiveStateAlert } from './LiveStateAlert';\nimport { LiveStateInfo } from './LiveStateInfo';\n\n/**\n * LiveStateRenderer\n *\n * Main component that validates payload, filters by context, and renders\n * the appropriate visual component (Alert or Info) based on type.\n * Handles closable notifications via useClosable when closable is configured.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateRenderer({\n data,\n loading,\n trackingConfig,\n allowedContexts,\n defaultVariant,\n isMobile,\n onCtaClick,\n}: LiveStateRendererProps) {\n const { isVisible, close } = useClosable({\n context: data?.context ?? '',\n id: data?.campaignId,\n maxCloseTimes: data?.metadata?.maxCloseTimes,\n expiresIn: data?.metadata?.expiresIn,\n });\n\n // Don't render while loading or no data\n if (loading || !data) {\n return null;\n }\n\n // Validate required fields\n if (\n !data.context ||\n !data.type ||\n !data.title ||\n !data.message ||\n !data.cta?.label ||\n !data.cta?.url ||\n !data.cta?.type\n ) {\n console.warn('[LiveState] Invalid payload, missing required fields', data);\n return null;\n }\n\n // Filter by allowed contexts\n if (allowedContexts && !allowedContexts.includes(data.context)) {\n return null;\n }\n\n // Awaiting localStorage check\n if (isVisible === null) {\n return null;\n }\n\n // Hidden — user reached maxCloseTimes\n if (!isVisible) {\n return null;\n }\n\n // Pass onClose whenever closable is true.\n // campaignId is optional — useClosable handles id=undefined gracefully\n // (always visible, no localStorage tracking).\n const onClose = data.closable ? close : undefined;\n\n // Render appropriate component based on type\n if (data.type === 'alert' || data.type === 'warning') {\n return (\n <LiveStateAlert\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n onCtaClick={onCtaClick}\n />\n );\n }\n\n if (data.type === 'info') {\n return (\n <LiveStateInfo\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n defaultVariant={defaultVariant}\n isMobile={isMobile}\n onCtaClick={onCtaClick}\n />\n );\n }\n\n console.warn(`[LiveState] Unknown type: ${data.type}`);\n return null;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"LiveStateRenderer.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAKvD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,OAAO,EACP,cAAc,EACd,eAAe,EACf,cAAc,EACd,QAAQ,EACR,UAAU,GACX,EAAE,sBAAsB,kDAwExB"}
1
+ {"version":3,"file":"LiveStateRenderer.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAKvD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,OAAO,EACP,cAAc,EACd,eAAe,EACf,cAAc,EACd,QAAQ,EACR,UAAU,GACX,EAAE,sBAAsB,kDA0ExB"}
@@ -1 +1 @@
1
- {"version":3,"file":"useClosable.d.ts","sourceRoot":"","sources":["../../../src/hooks/useClosable.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,yCAAyC;IACzC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,EAAE,EACF,aAAiB,EACjB,SAAS,GACV,EAAE,kBAAkB,GAAG,iBAAiB,CA2DxC"}
1
+ {"version":3,"file":"useClosable.d.ts","sourceRoot":"","sources":["../../../src/hooks/useClosable.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,yCAAyC;IACzC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,EAAE,EACF,aAAiB,EACjB,SAAS,GACV,EAAE,kBAAkB,GAAG,iBAAiB,CA8DxC"}
@@ -1,4 +1,4 @@
1
- export type { LiveStateResponse, LiveStateFetcher, TrackingConfig, TrackingProperties, TrackingValue, AnalyticsConfig, LiveStateProviderProps, LiveStateRendererProps, } from './types';
1
+ export type { LiveStateResponse, LiveStateFetcher, CtaConfig, TrackingConfig, TrackingProperties, TrackingValue, AnalyticsConfig, LiveStateProviderProps, LiveStateRendererProps, } from './types';
2
2
  export { LiveStateProvider } from './providers/LiveStateProvider';
3
3
  export { useLiveState } from './hooks/useLiveState';
4
4
  export { useTrackEvent } from './hooks/useTrackEvent';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiendanube/live-state",
3
- "version": "1.0.0-beta.10",
3
+ "version": "1.0.0-beta.12",
4
4
  "description": "Generic React library for rendering live state notifications",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",