@tiendanube/live-state 1.0.0-beta.4 → 1.0.0-beta.7
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 +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +246 -101
- package/dist/index.js.map +1 -1
- package/dist/src/components/LiveStateAlert.d.ts +4 -1
- package/dist/src/components/LiveStateAlert.d.ts.map +1 -1
- package/dist/src/components/LiveStateInfo.d.ts +4 -1
- package/dist/src/components/LiveStateInfo.d.ts.map +1 -1
- package/dist/src/components/LiveStateRenderer.d.ts +1 -0
- package/dist/src/components/LiveStateRenderer.d.ts.map +1 -1
- package/dist/src/hooks/useClosable.d.ts +39 -0
- package/dist/src/hooks/useClosable.d.ts.map +1 -0
- package/dist/src/hooks/useTrackEvent.d.ts +10 -0
- package/dist/src/hooks/useTrackEvent.d.ts.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/providers/LiveStateProvider.d.ts +7 -2
- package/dist/src/providers/LiveStateProvider.d.ts.map +1 -1
- package/dist/src/types/index.d.ts +18 -5
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/utils/analytics.d.ts.map +1 -1
- package/dist/src/utils/closable-storage.d.ts +17 -0
- package/dist/src/utils/closable-storage.d.ts.map +1 -0
- package/package.json +10 -11
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`);
|
|
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`;function O(){try{let e=localStorage.getItem(D);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 k(e){try{localStorage.setItem(D,JSON.stringify(e))}catch{}}function A({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=O(),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],k(n)),a(!0);return}a(s<n)},[e,t,n,r]),{isVisible:i,close:(0,c.useCallback)(()=>{if(!t)return;let n=O(),r=n[e]?.[t]?.count??0,i={...n,[e]:{...n[e]??{},[t]:{count:r+1,closedAt:Date.now()}}};a(!1),k(i)},[e,t])}}function j(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 M({data:e,trackingConfig:t,onClose:n}){let r=E(),i=e.type===`alert`?`danger`:`warning`,a=(0,c.useCallback)(()=>b({context:e.context,campaignId:e.campaignId,group:e.group,...e.metadata,...t.properties}),[e,t.properties]),o=(0,c.useCallback)(()=>{r(`${t.prefix}${t.page}_${e.context}_click`,a()),j(e.cta)},[e,t,a,r]),s=(0,c.useCallback)(()=>{r(`${t.prefix}${t.page}_${e.context}_close`,a()),n?.()},[n,e,t,a,r]);return(0,c.useEffect)(()=>{r(`${t.prefix}${t.page}_${e.context}_view`,a())},[]),(0,d.jsxs)(f.Alert,{appearance:i,title:e.title,onRemove:n?s:void 0,children:[(0,d.jsx)(`p`,{dangerouslySetInnerHTML:{__html:e.message}}),(0,d.jsx)(f.Button,{appearance:`neutral`,onClick:o,children:e.cta.label})]})}function N({data:e,trackingConfig:t,defaultVariant:n=`blue`,onClose:r}){let i=E(),a=e.variant||n,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()),j(e.cta)},[e,t,o,i]),l=(0,c.useCallback)(()=>{i(`${t.prefix}${t.page}_${e.context}_close`,o()),r?.()},[r,e,t,o,i]);(0,c.useEffect)(()=>{i(`${t.prefix}${t.page}_${e.context}_view`,o())},[]);let u=a===`blue`?`currentColor`:`primary-interactive`;return(0,d.jsx)(f.Card,{backgroundColor:a===`blue`?`primary-surface`:`neutral-background`,children:(0,d.jsx)(f.Card.Body,{children:(0,d.jsxs)(`div`,{style:{display:`flex`,gap:`16px`,alignItems:`flex-start`},children:[(0,d.jsx)(`div`,{style:{width:`32px`,height:`32px`,borderRadius:`50%`,display:`flex`,alignItems:`center`,justifyContent:`center`,flexShrink:0},children:(0,d.jsx)(f.Icon,{source:(0,d.jsx)(p.ExclamationCircleIcon,{}),color:u})}),(0,d.jsxs)(`div`,{style:{flex:1},children:[(0,d.jsx)(`h3`,{style:{fontSize:`16px`,fontWeight:600,margin:`0 0 8px 0`,lineHeight:`24px`},dangerouslySetInnerHTML:{__html:e.title}}),(0,d.jsx)(`p`,{style:{fontSize:`14px`,margin:`0 0 16px 0`,lineHeight:`20px`},dangerouslySetInnerHTML:{__html:e.message}}),(0,d.jsx)(f.Button,{onClick:s,children:e.cta.label})]}),r&&(0,d.jsx)(`button`,{onClick:l,"aria-label":`Fechar notificação`,"data-testid":`live-state-close-button`,style:{background:`none`,border:`none`,cursor:`pointer`,padding:`4px`,display:`flex`,alignItems:`center`,flexShrink:0},children:(0,d.jsx)(f.Icon,{source:(0,d.jsx)(p.CloseIcon,{size:`small`}),color:`neutral-interactive`})})]})})})}function P({data:e,loading:t,trackingConfig:n,allowedContexts:r,defaultVariant:i}){let{isVisible:a,close:o}=A({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)||a===null||!a)return null;let s=e.closable&&e.campaignId?o:void 0;return e.type===`alert`||e.type===`warning`?(0,d.jsx)(M,{data:e,onClose:s,trackingConfig:n}):e.type===`info`?(0,d.jsx)(N,{data:e,onClose:s,trackingConfig:n,defaultVariant:i}):(console.warn(`[LiveState] Unknown type: ${e.type}`),null)}exports.LiveStateAlert=M,exports.LiveStateInfo=N,exports.LiveStateProvider=C,exports.LiveStateRenderer=P,exports.handleCtaClick=j,exports.trackEvent=x,exports.useLiveState=T,exports.useTrackEvent=E;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/utils/analytics.ts","../src/providers/LiveStateProvider.tsx","../src/hooks/useLiveState.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 * 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 amplitude.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 amplitude.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 { LiveStateFetcher, AnalyticsConfig } from '../types';\nimport { initializeAmplitude, initializeClarity } from '../utils/analytics';\n\ninterface LiveStateContextValue {\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n}\n\nconst LiveStateContext = createContext<LiveStateContextValue | null>(null);\n\nexport interface LiveStateProviderProps {\n children: React.ReactNode;\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\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 * See examples/ directory for usage examples.\n */\nexport function LiveStateProvider({\n children,\n fetcher,\n analytics,\n}: LiveStateProviderProps) {\n // Initialize analytics on mount\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 }}>\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 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 { useEffect } from 'react';\nimport { Alert, Button } from '@nimbus-ds/components';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { trackEvent, buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\n\nexport interface LiveStateAlertProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\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 *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateAlert({ data, trackingConfig }: LiveStateAlertProps) {\n const appearance = data.type === 'alert' ? 'danger' : 'warning';\n\n const buildEventProperties = () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n });\n\n const handleClick = () => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n trackEvent(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n };\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n trackEvent(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={() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n trackEvent(eventName, buildEventProperties());\n }}>\n <p dangerouslySetInnerHTML={{ __html: data.message }} />\n <Button appearance=\"neutral\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Alert>\n );\n}\n","import { useEffect } from 'react';\nimport { Card, Button, Icon } from '@nimbus-ds/components';\nimport { ExclamationCircleIcon } from '@nimbus-ds/icons';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { trackEvent, buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\n\nexport interface LiveStateInfoProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n defaultVariant?: 'blue' | 'white';\n}\n\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type with a circular icon.\n * Automatically tracks view, click, and close events.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateInfo({\n data,\n trackingConfig,\n defaultVariant = 'blue',\n}: LiveStateInfoProps) {\n const variant = data.variant || defaultVariant;\n\n const buildEventProperties = () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n });\n\n const handleClick = () => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n trackEvent(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n };\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n trackEvent(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const iconColor = variant === 'blue' ? 'currentColor' : 'primary-interactive';\n\n return (\n <Card\n backgroundColor={\n variant === 'blue' ? 'primary-surface' : 'neutral-background'\n }>\n <Card.Body>\n <div style={{ display: 'flex', gap: '16px', alignItems: 'flex-start' }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}>\n <Icon source={<ExclamationCircleIcon />} color={iconColor} />\n </div>\n\n <div style={{ flex: 1 }}>\n <h3\n style={{\n fontSize: '16px',\n fontWeight: 600,\n margin: '0 0 8px 0',\n lineHeight: '24px',\n }}\n dangerouslySetInnerHTML={{ __html: data.title }}\n />\n <p\n style={{\n fontSize: '14px',\n margin: '0 0 16px 0',\n lineHeight: '20px',\n }}\n dangerouslySetInnerHTML={{ __html: data.message }}\n />\n <Button onClick={handleClick}>{data.cta.label}</Button>\n </div>\n </div>\n </Card.Body>\n </Card>\n );\n}\n","import type { LiveStateRendererProps } from '../types';\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 *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateRenderer({\n data,\n loading,\n trackingConfig,\n allowedContexts,\n defaultVariant,\n}: LiveStateRendererProps) {\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 // Render appropriate component based on type\n if (data.type === 'alert' || data.type === 'warning') {\n return <LiveStateAlert data={data} trackingConfig={trackingConfig} />;\n }\n\n if (data.type === 'info') {\n return (\n <LiveStateInfo\n data={data}\n trackingConfig={trackingConfig}\n defaultVariant={defaultVariant}\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.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","const STORAGE_KEY = '@tiendanube/live-state:closable';\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, Button } 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\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}: 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 handleCtaClick(data.cta);\n }, [data, trackingConfig, buildEventProperties, track]);\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 <p dangerouslySetInnerHTML={{ __html: data.message }} />\n <Button appearance=\"neutral\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Alert>\n );\n}\n","import { useCallback, useEffect } from 'react';\nimport { Card, Button, Icon } from '@nimbus-ds/components';\nimport { ExclamationCircleIcon, 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\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type with a circular icon.\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}: LiveStateInfoProps) {\n const track = useTrackEvent();\n const variant = data.variant || defaultVariant;\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 handleCtaClick(data.cta);\n }, [data, trackingConfig, buildEventProperties, track]);\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 iconColor = variant === 'blue' ? 'currentColor' : 'primary-interactive';\n\n return (\n <Card\n backgroundColor={\n variant === 'blue' ? 'primary-surface' : 'neutral-background'\n }>\n <Card.Body>\n <div style={{ display: 'flex', gap: '16px', alignItems: 'flex-start' }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}>\n <Icon source={<ExclamationCircleIcon />} color={iconColor} />\n </div>\n\n <div style={{ flex: 1 }}>\n <h3\n style={{\n fontSize: '16px',\n fontWeight: 600,\n margin: '0 0 8px 0',\n lineHeight: '24px',\n }}\n dangerouslySetInnerHTML={{ __html: data.title }}\n />\n <p\n style={{\n fontSize: '14px',\n margin: '0 0 16px 0',\n lineHeight: '20px',\n }}\n dangerouslySetInnerHTML={{ __html: data.message }}\n />\n <Button onClick={handleClick}>{data.cta.label}</Button>\n </div>\n\n {onClose && (\n <button\n onClick={handleClose}\n aria-label=\"Fechar notificação\"\n data-testid=\"live-state-close-button\"\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n display: 'flex',\n alignItems: 'center',\n flexShrink: 0,\n }}>\n <Icon\n source={<CloseIcon size=\"small\" />}\n color=\"neutral-interactive\"\n />\n </button>\n )}\n </div>\n </Card.Body>\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}: 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 />\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 />\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
|
@@ -1,28 +1,29 @@
|
|
|
1
|
-
import { createContext as e,
|
|
2
|
-
import
|
|
3
|
-
import * as
|
|
4
|
-
import { jsx as
|
|
5
|
-
import { Alert as
|
|
6
|
-
import { ExclamationCircleIcon as
|
|
1
|
+
import { createContext as e, useCallback as t, useContext as n, useEffect as r, useState as i } from "react";
|
|
2
|
+
import a, { SWRConfig as o } from "swr";
|
|
3
|
+
import * as s from "@amplitude/analytics-browser";
|
|
4
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
5
|
+
import { Alert as u, Button as d, Card as f, Icon as p } from "@nimbus-ds/components";
|
|
6
|
+
import { CloseIcon as m, ExclamationCircleIcon as h } from "@nimbus-ds/icons";
|
|
7
7
|
//#region src/utils/analytics.ts
|
|
8
|
-
|
|
8
|
+
var g = s.createInstance();
|
|
9
|
+
function _(e) {
|
|
9
10
|
try {
|
|
10
11
|
if (!e) {
|
|
11
12
|
console.warn("[LiveState] Amplitude API key not provided");
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
g.init(e, { defaultTracking: !1 });
|
|
15
16
|
} catch (e) {
|
|
16
17
|
console.warn("[LiveState] Failed to initialize Amplitude:", e);
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
|
-
async function
|
|
20
|
+
async function v(e) {
|
|
20
21
|
try {
|
|
21
22
|
if (window.clarity) {
|
|
22
23
|
console.log("[LiveState] Clarity already initialized by client");
|
|
23
24
|
return;
|
|
24
25
|
}
|
|
25
|
-
let t = e ||
|
|
26
|
+
let t = e || y();
|
|
26
27
|
if (!t) {
|
|
27
28
|
console.warn("[LiveState] Clarity project ID not provided");
|
|
28
29
|
return;
|
|
@@ -32,7 +33,7 @@ async function m(e) {
|
|
|
32
33
|
console.warn("[LiveState] Failed to initialize Clarity:", e);
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
|
-
function
|
|
36
|
+
function y() {
|
|
36
37
|
try {
|
|
37
38
|
let e = document.querySelector("script[src*=\"clarity.ms\"]");
|
|
38
39
|
if (e) return e.getAttribute("src")?.match(/\/([a-z0-9]+)$/)?.[1];
|
|
@@ -40,14 +41,14 @@ function h() {
|
|
|
40
41
|
if (typeof t == "string") return t;
|
|
41
42
|
} catch {}
|
|
42
43
|
}
|
|
43
|
-
function
|
|
44
|
+
function b(e, t) {
|
|
44
45
|
try {
|
|
45
|
-
|
|
46
|
+
g.track(e, t);
|
|
46
47
|
} catch (e) {
|
|
47
48
|
console.warn("[LiveState] Failed to track Amplitude event:", e);
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
|
-
function
|
|
51
|
+
function x(e, t) {
|
|
51
52
|
try {
|
|
52
53
|
window.clarity && (window.clarity("event", e), t && Object.entries(t).forEach(([e, t]) => {
|
|
53
54
|
window.clarity?.("set", e, String(t));
|
|
@@ -56,38 +57,39 @@ function _(e, t) {
|
|
|
56
57
|
console.warn("[LiveState] Failed to track Clarity event:", e);
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
|
-
function
|
|
60
|
+
function S(e) {
|
|
60
61
|
return Object.fromEntries(Object.entries(e).filter((e) => e[1] !== void 0));
|
|
61
62
|
}
|
|
62
|
-
function
|
|
63
|
-
|
|
63
|
+
function C(e, t) {
|
|
64
|
+
b(e, t), x(e, t);
|
|
64
65
|
}
|
|
65
66
|
//#endregion
|
|
66
67
|
//#region src/providers/LiveStateProvider.tsx
|
|
67
|
-
var
|
|
68
|
-
function
|
|
69
|
-
return
|
|
70
|
-
|
|
71
|
-
}, [
|
|
68
|
+
var w = e(null);
|
|
69
|
+
function T({ children: e, fetcher: t, analytics: n, onEvent: i }) {
|
|
70
|
+
return r(() => {
|
|
71
|
+
n?.amplitudeKey && _(n.amplitudeKey), n?.clarityProjectId && v(n.clarityProjectId);
|
|
72
|
+
}, [n]), /* @__PURE__ */ c(o, {
|
|
72
73
|
value: { provider: () => /* @__PURE__ */ new Map() },
|
|
73
|
-
children: /* @__PURE__ */
|
|
74
|
+
children: /* @__PURE__ */ c(w.Provider, {
|
|
74
75
|
value: {
|
|
75
76
|
fetcher: t,
|
|
76
|
-
analytics:
|
|
77
|
+
analytics: n,
|
|
78
|
+
onEvent: i
|
|
77
79
|
},
|
|
78
80
|
children: e
|
|
79
81
|
})
|
|
80
82
|
});
|
|
81
83
|
}
|
|
82
|
-
function
|
|
83
|
-
let e =
|
|
84
|
+
function E() {
|
|
85
|
+
let e = n(w);
|
|
84
86
|
if (!e) throw Error("useLiveState must be used within LiveStateProvider");
|
|
85
87
|
return e;
|
|
86
88
|
}
|
|
87
89
|
//#endregion
|
|
88
90
|
//#region src/hooks/useLiveState.ts
|
|
89
|
-
function
|
|
90
|
-
let { fetcher: e } =
|
|
91
|
+
function D() {
|
|
92
|
+
let { fetcher: e } = E(), { data: t, error: n, isLoading: r, mutate: i } = a("live-state", e, {
|
|
91
93
|
revalidateOnFocus: !1,
|
|
92
94
|
revalidateOnReconnect: !0,
|
|
93
95
|
dedupingInterval: 6e4,
|
|
@@ -98,11 +100,11 @@ function C() {
|
|
|
98
100
|
});
|
|
99
101
|
return {
|
|
100
102
|
liveState: t ?? null,
|
|
101
|
-
isLoading:
|
|
103
|
+
isLoading: r,
|
|
102
104
|
error: n ?? null,
|
|
103
105
|
refresh: async () => {
|
|
104
106
|
try {
|
|
105
|
-
await
|
|
107
|
+
await i();
|
|
106
108
|
} catch (e) {
|
|
107
109
|
console.warn("[LiveState] Failed to refresh live state:", e);
|
|
108
110
|
}
|
|
@@ -110,8 +112,94 @@ function C() {
|
|
|
110
112
|
};
|
|
111
113
|
}
|
|
112
114
|
//#endregion
|
|
115
|
+
//#region src/hooks/useTrackEvent.ts
|
|
116
|
+
function O() {
|
|
117
|
+
let { onEvent: e } = E();
|
|
118
|
+
return t((t, n) => {
|
|
119
|
+
e?.(t, n), C(t, n);
|
|
120
|
+
}, [e]);
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region src/utils/closable-storage.ts
|
|
124
|
+
var k = "@tiendanube/live-state:closable";
|
|
125
|
+
function A() {
|
|
126
|
+
try {
|
|
127
|
+
let e = localStorage.getItem(k);
|
|
128
|
+
if (!e) return {};
|
|
129
|
+
let t = JSON.parse(e);
|
|
130
|
+
if (typeof t != "object" || !t) return {};
|
|
131
|
+
let n = {};
|
|
132
|
+
for (let [e, r] of Object.entries(t)) if (!(typeof r != "object" || !r)) {
|
|
133
|
+
n[e] = {};
|
|
134
|
+
for (let [t, i] of Object.entries(r)) if (typeof i == "number") n[e][t] = {
|
|
135
|
+
count: i,
|
|
136
|
+
closedAt: 0
|
|
137
|
+
};
|
|
138
|
+
else if (typeof i == "object" && i) {
|
|
139
|
+
let r = i;
|
|
140
|
+
n[e][t] = {
|
|
141
|
+
count: typeof r.count == "number" ? r.count : 0,
|
|
142
|
+
closedAt: typeof r.closedAt == "number" ? r.closedAt : 0
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return n;
|
|
147
|
+
} catch {
|
|
148
|
+
return {};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function j(e) {
|
|
152
|
+
try {
|
|
153
|
+
localStorage.setItem(k, JSON.stringify(e));
|
|
154
|
+
} catch {}
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/hooks/useClosable.ts
|
|
158
|
+
function M({ context: e, id: n, maxCloseTimes: a = 3, expiresIn: o }) {
|
|
159
|
+
let [s, c] = i(null);
|
|
160
|
+
return r(() => {
|
|
161
|
+
if (!n) {
|
|
162
|
+
c(!0);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
let t = A(), r = t[e]?.[n];
|
|
166
|
+
if (!r) {
|
|
167
|
+
c(!0);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
let { count: i, closedAt: s } = r;
|
|
171
|
+
if (o != null && s > 0 && Date.now() - s > o) {
|
|
172
|
+
let r = { ...t };
|
|
173
|
+
r[e] && (delete r[e][n], j(r)), c(!0);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
c(i < a);
|
|
177
|
+
}, [
|
|
178
|
+
e,
|
|
179
|
+
n,
|
|
180
|
+
a,
|
|
181
|
+
o
|
|
182
|
+
]), {
|
|
183
|
+
isVisible: s,
|
|
184
|
+
close: t(() => {
|
|
185
|
+
if (!n) return;
|
|
186
|
+
let t = A(), r = t[e]?.[n]?.count ?? 0, i = {
|
|
187
|
+
...t,
|
|
188
|
+
[e]: {
|
|
189
|
+
...t[e] ?? {},
|
|
190
|
+
[n]: {
|
|
191
|
+
count: r + 1,
|
|
192
|
+
closedAt: Date.now()
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
c(!1), j(i);
|
|
197
|
+
}, [e, n])
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
//#endregion
|
|
113
201
|
//#region src/utils/cta.ts
|
|
114
|
-
function
|
|
202
|
+
function N(e) {
|
|
115
203
|
try {
|
|
116
204
|
switch (e.type) {
|
|
117
205
|
case "redirect":
|
|
@@ -133,111 +221,168 @@ function w(e) {
|
|
|
133
221
|
}
|
|
134
222
|
//#endregion
|
|
135
223
|
//#region src/components/LiveStateAlert.tsx
|
|
136
|
-
function
|
|
137
|
-
let
|
|
224
|
+
function P({ data: e, trackingConfig: n, onClose: i }) {
|
|
225
|
+
let a = O(), o = e.type === "alert" ? "danger" : "warning", s = t(() => S({
|
|
138
226
|
context: e.context,
|
|
139
227
|
campaignId: e.campaignId,
|
|
140
228
|
group: e.group,
|
|
141
229
|
...e.metadata,
|
|
142
|
-
...
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
230
|
+
...n.properties
|
|
231
|
+
}), [e, n.properties]), f = t(() => {
|
|
232
|
+
a(`${n.prefix}${n.page}_${e.context}_click`, s()), N(e.cta);
|
|
233
|
+
}, [
|
|
234
|
+
e,
|
|
235
|
+
n,
|
|
236
|
+
s,
|
|
237
|
+
a
|
|
238
|
+
]), p = t(() => {
|
|
239
|
+
a(`${n.prefix}${n.page}_${e.context}_close`, s()), i?.();
|
|
240
|
+
}, [
|
|
241
|
+
i,
|
|
242
|
+
e,
|
|
243
|
+
n,
|
|
244
|
+
s,
|
|
245
|
+
a
|
|
246
|
+
]);
|
|
247
|
+
return r(() => {
|
|
248
|
+
a(`${n.prefix}${n.page}_${e.context}_view`, s());
|
|
249
|
+
}, []), /* @__PURE__ */ l(u, {
|
|
250
|
+
appearance: o,
|
|
148
251
|
title: e.title,
|
|
149
|
-
onRemove:
|
|
150
|
-
|
|
151
|
-
},
|
|
152
|
-
children: [/* @__PURE__ */ o("p", { dangerouslySetInnerHTML: { __html: e.message } }), /* @__PURE__ */ o(l, {
|
|
252
|
+
onRemove: i ? p : void 0,
|
|
253
|
+
children: [/* @__PURE__ */ c("p", { dangerouslySetInnerHTML: { __html: e.message } }), /* @__PURE__ */ c(d, {
|
|
153
254
|
appearance: "neutral",
|
|
154
|
-
onClick:
|
|
155
|
-
y(`${t.prefix}${t.page}_${e.context}_click`, i()), w(e.cta);
|
|
156
|
-
},
|
|
255
|
+
onClick: f,
|
|
157
256
|
children: e.cta.label
|
|
158
257
|
})]
|
|
159
258
|
});
|
|
160
259
|
}
|
|
161
260
|
//#endregion
|
|
162
261
|
//#region src/components/LiveStateInfo.tsx
|
|
163
|
-
function
|
|
164
|
-
let
|
|
262
|
+
function F({ data: e, trackingConfig: n, defaultVariant: i = "blue", onClose: a }) {
|
|
263
|
+
let o = O(), s = e.variant || i, u = t(() => S({
|
|
165
264
|
context: e.context,
|
|
166
265
|
campaignId: e.campaignId,
|
|
167
266
|
group: e.group,
|
|
168
267
|
...e.metadata,
|
|
169
|
-
...
|
|
170
|
-
}),
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
268
|
+
...n.properties
|
|
269
|
+
}), [e, n.properties]), g = t(() => {
|
|
270
|
+
o(`${n.prefix}${n.page}_${e.context}_click`, u()), N(e.cta);
|
|
271
|
+
}, [
|
|
272
|
+
e,
|
|
273
|
+
n,
|
|
274
|
+
u,
|
|
275
|
+
o
|
|
276
|
+
]), _ = t(() => {
|
|
277
|
+
o(`${n.prefix}${n.page}_${e.context}_close`, u()), a?.();
|
|
278
|
+
}, [
|
|
279
|
+
a,
|
|
280
|
+
e,
|
|
281
|
+
n,
|
|
282
|
+
u,
|
|
283
|
+
o
|
|
284
|
+
]);
|
|
285
|
+
r(() => {
|
|
286
|
+
o(`${n.prefix}${n.page}_${e.context}_view`, u());
|
|
175
287
|
}, []);
|
|
176
|
-
let
|
|
177
|
-
return /* @__PURE__ */
|
|
178
|
-
backgroundColor:
|
|
179
|
-
children: /* @__PURE__ */
|
|
288
|
+
let v = s === "blue" ? "currentColor" : "primary-interactive";
|
|
289
|
+
return /* @__PURE__ */ c(f, {
|
|
290
|
+
backgroundColor: s === "blue" ? "primary-surface" : "neutral-background",
|
|
291
|
+
children: /* @__PURE__ */ c(f.Body, { children: /* @__PURE__ */ l("div", {
|
|
180
292
|
style: {
|
|
181
293
|
display: "flex",
|
|
182
294
|
gap: "16px",
|
|
183
295
|
alignItems: "flex-start"
|
|
184
296
|
},
|
|
185
|
-
children: [
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}), /* @__PURE__ */ s("div", {
|
|
200
|
-
style: { flex: 1 },
|
|
201
|
-
children: [
|
|
202
|
-
/* @__PURE__ */ o("h3", {
|
|
203
|
-
style: {
|
|
204
|
-
fontSize: "16px",
|
|
205
|
-
fontWeight: 600,
|
|
206
|
-
margin: "0 0 8px 0",
|
|
207
|
-
lineHeight: "24px"
|
|
208
|
-
},
|
|
209
|
-
dangerouslySetInnerHTML: { __html: e.title }
|
|
210
|
-
}),
|
|
211
|
-
/* @__PURE__ */ o("p", {
|
|
212
|
-
style: {
|
|
213
|
-
fontSize: "14px",
|
|
214
|
-
margin: "0 0 16px 0",
|
|
215
|
-
lineHeight: "20px"
|
|
216
|
-
},
|
|
217
|
-
dangerouslySetInnerHTML: { __html: e.message }
|
|
218
|
-
}),
|
|
219
|
-
/* @__PURE__ */ o(l, {
|
|
220
|
-
onClick: c,
|
|
221
|
-
children: e.cta.label
|
|
297
|
+
children: [
|
|
298
|
+
/* @__PURE__ */ c("div", {
|
|
299
|
+
style: {
|
|
300
|
+
width: "32px",
|
|
301
|
+
height: "32px",
|
|
302
|
+
borderRadius: "50%",
|
|
303
|
+
display: "flex",
|
|
304
|
+
alignItems: "center",
|
|
305
|
+
justifyContent: "center",
|
|
306
|
+
flexShrink: 0
|
|
307
|
+
},
|
|
308
|
+
children: /* @__PURE__ */ c(p, {
|
|
309
|
+
source: /* @__PURE__ */ c(h, {}),
|
|
310
|
+
color: v
|
|
222
311
|
})
|
|
223
|
-
|
|
224
|
-
|
|
312
|
+
}),
|
|
313
|
+
/* @__PURE__ */ l("div", {
|
|
314
|
+
style: { flex: 1 },
|
|
315
|
+
children: [
|
|
316
|
+
/* @__PURE__ */ c("h3", {
|
|
317
|
+
style: {
|
|
318
|
+
fontSize: "16px",
|
|
319
|
+
fontWeight: 600,
|
|
320
|
+
margin: "0 0 8px 0",
|
|
321
|
+
lineHeight: "24px"
|
|
322
|
+
},
|
|
323
|
+
dangerouslySetInnerHTML: { __html: e.title }
|
|
324
|
+
}),
|
|
325
|
+
/* @__PURE__ */ c("p", {
|
|
326
|
+
style: {
|
|
327
|
+
fontSize: "14px",
|
|
328
|
+
margin: "0 0 16px 0",
|
|
329
|
+
lineHeight: "20px"
|
|
330
|
+
},
|
|
331
|
+
dangerouslySetInnerHTML: { __html: e.message }
|
|
332
|
+
}),
|
|
333
|
+
/* @__PURE__ */ c(d, {
|
|
334
|
+
onClick: g,
|
|
335
|
+
children: e.cta.label
|
|
336
|
+
})
|
|
337
|
+
]
|
|
338
|
+
}),
|
|
339
|
+
a && /* @__PURE__ */ c("button", {
|
|
340
|
+
onClick: _,
|
|
341
|
+
"aria-label": "Fechar notificação",
|
|
342
|
+
"data-testid": "live-state-close-button",
|
|
343
|
+
style: {
|
|
344
|
+
background: "none",
|
|
345
|
+
border: "none",
|
|
346
|
+
cursor: "pointer",
|
|
347
|
+
padding: "4px",
|
|
348
|
+
display: "flex",
|
|
349
|
+
alignItems: "center",
|
|
350
|
+
flexShrink: 0
|
|
351
|
+
},
|
|
352
|
+
children: /* @__PURE__ */ c(p, {
|
|
353
|
+
source: /* @__PURE__ */ c(m, { size: "small" }),
|
|
354
|
+
color: "neutral-interactive"
|
|
355
|
+
})
|
|
356
|
+
})
|
|
357
|
+
]
|
|
225
358
|
}) })
|
|
226
359
|
});
|
|
227
360
|
}
|
|
228
361
|
//#endregion
|
|
229
362
|
//#region src/components/LiveStateRenderer.tsx
|
|
230
|
-
function
|
|
231
|
-
|
|
363
|
+
function I({ data: e, loading: t, trackingConfig: n, allowedContexts: r, defaultVariant: i }) {
|
|
364
|
+
let { isVisible: a, close: o } = M({
|
|
365
|
+
context: e?.context ?? "",
|
|
366
|
+
id: e?.campaignId,
|
|
367
|
+
maxCloseTimes: e?.metadata?.maxCloseTimes,
|
|
368
|
+
expiresIn: e?.metadata?.expiresIn
|
|
369
|
+
});
|
|
370
|
+
if (t || !e) return null;
|
|
371
|
+
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;
|
|
372
|
+
if (r && !r.includes(e.context) || a === null || !a) return null;
|
|
373
|
+
let s = e.closable && e.campaignId ? o : void 0;
|
|
374
|
+
return e.type === "alert" || e.type === "warning" ? /* @__PURE__ */ c(P, {
|
|
232
375
|
data: e,
|
|
376
|
+
onClose: s,
|
|
233
377
|
trackingConfig: n
|
|
234
|
-
}) : e.type === "info" ? /* @__PURE__ */
|
|
378
|
+
}) : e.type === "info" ? /* @__PURE__ */ c(F, {
|
|
235
379
|
data: e,
|
|
380
|
+
onClose: s,
|
|
236
381
|
trackingConfig: n,
|
|
237
382
|
defaultVariant: i
|
|
238
383
|
}) : (console.warn(`[LiveState] Unknown type: ${e.type}`), null);
|
|
239
384
|
}
|
|
240
385
|
//#endregion
|
|
241
|
-
export {
|
|
386
|
+
export { P as LiveStateAlert, F as LiveStateInfo, T as LiveStateProvider, I as LiveStateRenderer, N as handleCtaClick, C as trackEvent, D as useLiveState, O as useTrackEvent };
|
|
242
387
|
|
|
243
388
|
//# sourceMappingURL=index.js.map
|
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/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 * 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 amplitude.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 amplitude.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 { LiveStateFetcher, AnalyticsConfig } from '../types';\nimport { initializeAmplitude, initializeClarity } from '../utils/analytics';\n\ninterface LiveStateContextValue {\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n}\n\nconst LiveStateContext = createContext<LiveStateContextValue | null>(null);\n\nexport interface LiveStateProviderProps {\n children: React.ReactNode;\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\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 * See examples/ directory for usage examples.\n */\nexport function LiveStateProvider({\n children,\n fetcher,\n analytics,\n}: LiveStateProviderProps) {\n // Initialize analytics on mount\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 }}>\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 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 { useEffect } from 'react';\nimport { Alert, Button } from '@nimbus-ds/components';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { trackEvent, buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\n\nexport interface LiveStateAlertProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\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 *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateAlert({ data, trackingConfig }: LiveStateAlertProps) {\n const appearance = data.type === 'alert' ? 'danger' : 'warning';\n\n const buildEventProperties = () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n });\n\n const handleClick = () => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n trackEvent(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n };\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n trackEvent(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={() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n trackEvent(eventName, buildEventProperties());\n }}>\n <p dangerouslySetInnerHTML={{ __html: data.message }} />\n <Button appearance=\"neutral\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Alert>\n );\n}\n","import { useEffect } from 'react';\nimport { Card, Button, Icon } from '@nimbus-ds/components';\nimport { ExclamationCircleIcon } from '@nimbus-ds/icons';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { trackEvent, buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\n\nexport interface LiveStateInfoProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n defaultVariant?: 'blue' | 'white';\n}\n\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type with a circular icon.\n * Automatically tracks view, click, and close events.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateInfo({\n data,\n trackingConfig,\n defaultVariant = 'blue',\n}: LiveStateInfoProps) {\n const variant = data.variant || defaultVariant;\n\n const buildEventProperties = () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n });\n\n const handleClick = () => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n trackEvent(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n };\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n trackEvent(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const iconColor = variant === 'blue' ? 'currentColor' : 'primary-interactive';\n\n return (\n <Card\n backgroundColor={\n variant === 'blue' ? 'primary-surface' : 'neutral-background'\n }>\n <Card.Body>\n <div style={{ display: 'flex', gap: '16px', alignItems: 'flex-start' }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}>\n <Icon source={<ExclamationCircleIcon />} color={iconColor} />\n </div>\n\n <div style={{ flex: 1 }}>\n <h3\n style={{\n fontSize: '16px',\n fontWeight: 600,\n margin: '0 0 8px 0',\n lineHeight: '24px',\n }}\n dangerouslySetInnerHTML={{ __html: data.title }}\n />\n <p\n style={{\n fontSize: '14px',\n margin: '0 0 16px 0',\n lineHeight: '20px',\n }}\n dangerouslySetInnerHTML={{ __html: data.message }}\n />\n <Button onClick={handleClick}>{data.cta.label}</Button>\n </div>\n </div>\n </Card.Body>\n </Card>\n );\n}\n","import type { LiveStateRendererProps } from '../types';\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 *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateRenderer({\n data,\n loading,\n trackingConfig,\n allowedContexts,\n defaultVariant,\n}: LiveStateRendererProps) {\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 // Render appropriate component based on type\n if (data.type === 'alert' || data.type === 'warning') {\n return <LiveStateAlert data={data} trackingConfig={trackingConfig} />;\n }\n\n if (data.type === 'info') {\n return (\n <LiveStateInfo\n data={data}\n trackingConfig={trackingConfig}\n defaultVariant={defaultVariant}\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","const STORAGE_KEY = '@tiendanube/live-state:closable';\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, Button } 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\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}: 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 handleCtaClick(data.cta);\n }, [data, trackingConfig, buildEventProperties, track]);\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 <p dangerouslySetInnerHTML={{ __html: data.message }} />\n <Button appearance=\"neutral\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Alert>\n );\n}\n","import { useCallback, useEffect } from 'react';\nimport { Card, Button, Icon } from '@nimbus-ds/components';\nimport { ExclamationCircleIcon, 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\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type with a circular icon.\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}: LiveStateInfoProps) {\n const track = useTrackEvent();\n const variant = data.variant || defaultVariant;\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 handleCtaClick(data.cta);\n }, [data, trackingConfig, buildEventProperties, track]);\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 iconColor = variant === 'blue' ? 'currentColor' : 'primary-interactive';\n\n return (\n <Card\n backgroundColor={\n variant === 'blue' ? 'primary-surface' : 'neutral-background'\n }>\n <Card.Body>\n <div style={{ display: 'flex', gap: '16px', alignItems: 'flex-start' }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}>\n <Icon source={<ExclamationCircleIcon />} color={iconColor} />\n </div>\n\n <div style={{ flex: 1 }}>\n <h3\n style={{\n fontSize: '16px',\n fontWeight: 600,\n margin: '0 0 8px 0',\n lineHeight: '24px',\n }}\n dangerouslySetInnerHTML={{ __html: data.title }}\n />\n <p\n style={{\n fontSize: '14px',\n margin: '0 0 16px 0',\n lineHeight: '20px',\n }}\n dangerouslySetInnerHTML={{ __html: data.message }}\n />\n <Button onClick={handleClick}>{data.cta.label}</Button>\n </div>\n\n {onClose && (\n <button\n onClick={handleClose}\n aria-label=\"Fechar notificação\"\n data-testid=\"live-state-close-button\"\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n display: 'flex',\n alignItems: 'center',\n flexShrink: 0,\n }}>\n <Icon\n source={<CloseIcon size=\"small\" />}\n color=\"neutral-interactive\"\n />\n </button>\n )}\n </div>\n </Card.Body>\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}: 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 />\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 />\n );\n }\n\n console.warn(`[LiveState] Unknown type: ${data.type}`);\n return null;\n}\n"],"mappings":"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"}
|
|
@@ -2,14 +2,17 @@ import { LiveStateResponse, TrackingConfig } from '../types';
|
|
|
2
2
|
export interface LiveStateAlertProps {
|
|
3
3
|
data: LiveStateResponse;
|
|
4
4
|
trackingConfig: TrackingConfig;
|
|
5
|
+
/** When provided, shows a close button and calls this on dismiss */
|
|
6
|
+
onClose?: () => void;
|
|
5
7
|
}
|
|
6
8
|
/**
|
|
7
9
|
* LiveStateAlert
|
|
8
10
|
*
|
|
9
11
|
* Renders an Alert component (Nimbus) for alert/warning types.
|
|
10
12
|
* Automatically tracks view, click, and close events.
|
|
13
|
+
* Shows a close button when onClose is provided.
|
|
11
14
|
*
|
|
12
15
|
* See examples/ directory for usage examples.
|
|
13
16
|
*/
|
|
14
|
-
export declare function LiveStateAlert({ data, trackingConfig }: LiveStateAlertProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export declare function LiveStateAlert({ data, trackingConfig, onClose, }: LiveStateAlertProps): import("react/jsx-runtime").JSX.Element;
|
|
15
18
|
//# sourceMappingURL=LiveStateAlert.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveStateAlert.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateAlert.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"LiveStateAlert.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateAlert.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAKlE,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,cAAc,EAAE,cAAc,CAAC;IAC/B,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,cAAc,EACd,OAAO,GACR,EAAE,mBAAmB,2CA6CrB"}
|
|
@@ -3,14 +3,17 @@ export interface LiveStateInfoProps {
|
|
|
3
3
|
data: LiveStateResponse;
|
|
4
4
|
trackingConfig: TrackingConfig;
|
|
5
5
|
defaultVariant?: 'blue' | 'white';
|
|
6
|
+
/** When provided, shows a close button and calls this on dismiss */
|
|
7
|
+
onClose?: () => void;
|
|
6
8
|
}
|
|
7
9
|
/**
|
|
8
10
|
* LiveStateInfo
|
|
9
11
|
*
|
|
10
12
|
* Renders a Card component (Nimbus) for info type with a circular icon.
|
|
11
13
|
* Automatically tracks view, click, and close events.
|
|
14
|
+
* Shows a close button when onClose is provided.
|
|
12
15
|
*
|
|
13
16
|
* See examples/ directory for usage examples.
|
|
14
17
|
*/
|
|
15
|
-
export declare function LiveStateInfo({ data, trackingConfig, defaultVariant, }: LiveStateInfoProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare function LiveStateInfo({ data, trackingConfig, defaultVariant, onClose, }: LiveStateInfoProps): import("react/jsx-runtime").JSX.Element;
|
|
16
19
|
//# sourceMappingURL=LiveStateInfo.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveStateInfo.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateInfo.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"LiveStateInfo.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateInfo.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAKlE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,iBAAiB,CAAC;IACxB,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,cAAc,EACd,cAAuB,EACvB,OAAO,GACR,EAAE,kBAAkB,2CAqGpB"}
|
|
@@ -4,6 +4,7 @@ import { LiveStateRendererProps } from '../types';
|
|
|
4
4
|
*
|
|
5
5
|
* Main component that validates payload, filters by context, and renders
|
|
6
6
|
* the appropriate visual component (Alert or Info) based on type.
|
|
7
|
+
* Handles closable notifications via useClosable when closable is configured.
|
|
7
8
|
*
|
|
8
9
|
* See examples/ directory for usage examples.
|
|
9
10
|
*/
|
|
@@ -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;
|
|
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,GACf,EAAE,sBAAsB,kDAqExB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface UseClosableOptions {
|
|
2
|
+
/** Notification context (e.g. 'awareness', 'charge') */
|
|
3
|
+
context: string;
|
|
4
|
+
/** Unique notification ID (campaignId). If absent, always visible — no close tracking. */
|
|
5
|
+
id: string | undefined;
|
|
6
|
+
/** Maximum number of times the user can close before it is hidden permanently */
|
|
7
|
+
maxCloseTimes?: number;
|
|
8
|
+
/** Milliseconds after which the close counter resets (optional) */
|
|
9
|
+
expiresIn?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface UseClosableReturn {
|
|
12
|
+
/** Whether the notification should be shown. null = initial check in progress. */
|
|
13
|
+
isVisible: boolean | null;
|
|
14
|
+
/** Call this to record a close action */
|
|
15
|
+
close: () => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Manages the close state of a notification using localStorage.
|
|
19
|
+
*
|
|
20
|
+
* After the user closes a notification `maxCloseTimes` times, it is hidden
|
|
21
|
+
* permanently. Optionally, the counter resets after `expiresIn` milliseconds.
|
|
22
|
+
*
|
|
23
|
+
* Fails silently — errors in localStorage never break the application.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* const { isVisible, close } = useClosable({
|
|
28
|
+
* context: 'awareness',
|
|
29
|
+
* id: 'awareness-2026-q1',
|
|
30
|
+
* maxCloseTimes: 3,
|
|
31
|
+
* expiresIn: 86_400_000, // 1 day
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* if (!isVisible) return null;
|
|
35
|
+
* return <Notification onClose={close} />;
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function useClosable({ context, id, maxCloseTimes, expiresIn, }: UseClosableOptions): UseClosableReturn;
|
|
39
|
+
//# sourceMappingURL=useClosable.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TrackingProperties } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* useTrackEvent
|
|
4
|
+
*
|
|
5
|
+
* Returns a `track` function that fires both the internal analytics
|
|
6
|
+
* (Amplitude + Clarity) and the optional `onEvent` callback provided
|
|
7
|
+
* to LiveStateProvider — useful for simulators and debugging tools.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useTrackEvent(): (eventName: string, properties?: TrackingProperties) => void;
|
|
10
|
+
//# sourceMappingURL=useTrackEvent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTrackEvent.d.ts","sourceRoot":"","sources":["../../../src/hooks/useTrackEvent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,aAAa,gBAIb,MAAM,eAAe,kBAAkB,UAQtD"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type { LiveStateResponse, LiveStateFetcher, TrackingConfig, AnalyticsConfig, LiveStateProviderProps, LiveStateRendererProps, } from './types';
|
|
2
2
|
export { LiveStateProvider } from './providers/LiveStateProvider';
|
|
3
3
|
export { useLiveState } from './hooks/useLiveState';
|
|
4
|
+
export { useTrackEvent } from './hooks/useTrackEvent';
|
|
4
5
|
export { LiveStateRenderer } from './components/LiveStateRenderer';
|
|
5
6
|
export { LiveStateAlert } from './components/LiveStateAlert';
|
|
6
7
|
export { LiveStateInfo } from './components/LiveStateInfo';
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -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,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;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,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"}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { LiveStateFetcher, AnalyticsConfig } from '../types';
|
|
2
|
+
import { LiveStateFetcher, AnalyticsConfig, TrackingProperties } from '../types';
|
|
3
3
|
interface LiveStateContextValue {
|
|
4
4
|
fetcher: LiveStateFetcher;
|
|
5
5
|
analytics?: AnalyticsConfig;
|
|
6
|
+
onEvent?: (eventName: string, properties?: TrackingProperties) => void;
|
|
6
7
|
}
|
|
7
8
|
export interface LiveStateProviderProps {
|
|
8
9
|
children: React.ReactNode;
|
|
9
10
|
fetcher: LiveStateFetcher;
|
|
10
11
|
analytics?: AnalyticsConfig;
|
|
12
|
+
onEvent?: (eventName: string, properties?: TrackingProperties) => void;
|
|
11
13
|
}
|
|
12
14
|
/**
|
|
13
15
|
* LiveStateProvider
|
|
@@ -15,9 +17,12 @@ export interface LiveStateProviderProps {
|
|
|
15
17
|
* Root-level provider that configures fetcher function and analytics.
|
|
16
18
|
* Initializes Amplitude and Clarity on mount.
|
|
17
19
|
*
|
|
20
|
+
* The optional `onEvent` callback is fired on every tracking event before
|
|
21
|
+
* sending to Amplitude/Clarity — useful for simulators and debugging tools.
|
|
22
|
+
*
|
|
18
23
|
* See examples/ directory for usage examples.
|
|
19
24
|
*/
|
|
20
|
-
export declare function LiveStateProvider({ children, fetcher, analytics, }: LiveStateProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
export declare function LiveStateProvider({ children, fetcher, analytics, onEvent, }: LiveStateProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
21
26
|
/**
|
|
22
27
|
* useLiveStateContext
|
|
23
28
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveStateProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/LiveStateProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAEpE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"LiveStateProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/LiveStateProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAEpE,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EACnB,MAAM,UAAU,CAAC;AAGlB,UAAU,qBAAqB;IAC7B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACxE;AAID,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,OAAO,EACP,SAAS,EACT,OAAO,GACR,EAAE,sBAAsB,2CAkBxB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,0BAQlC"}
|
|
@@ -40,13 +40,17 @@ export interface LiveStateResponse {
|
|
|
40
40
|
group?: string;
|
|
41
41
|
/** Visual variant */
|
|
42
42
|
variant?: 'blue' | 'white';
|
|
43
|
-
/**
|
|
44
|
-
closable?:
|
|
45
|
-
|
|
43
|
+
/** Whether the notification can be dismissed by the user */
|
|
44
|
+
closable?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Additional metadata.
|
|
47
|
+
* When closable=true, may contain maxCloseTimes and expiresIn to control
|
|
48
|
+
* how many times the user can close before it disappears permanently.
|
|
49
|
+
*/
|
|
50
|
+
metadata?: TrackingProperties & {
|
|
51
|
+
maxCloseTimes?: number;
|
|
46
52
|
expiresIn?: number;
|
|
47
53
|
};
|
|
48
|
-
/** Additional metadata for tracking */
|
|
49
|
-
metadata?: TrackingProperties;
|
|
50
54
|
}
|
|
51
55
|
/**
|
|
52
56
|
* Fetcher function type
|
|
@@ -82,6 +86,15 @@ export interface LiveStateProviderProps {
|
|
|
82
86
|
fetcher: LiveStateFetcher;
|
|
83
87
|
/** Analytics configuration */
|
|
84
88
|
analytics?: AnalyticsConfig;
|
|
89
|
+
/**
|
|
90
|
+
* Optional observability callback fired on every tracking event
|
|
91
|
+
* (view, click, close) before sending to Amplitude/Clarity.
|
|
92
|
+
* Useful for simulators, debugging tools, and custom analytics pipelines.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* <LiveStateProvider onEvent={(name, props) => console.log(name, props)} />
|
|
96
|
+
*/
|
|
97
|
+
onEvent?: (eventName: string, properties?: TrackingProperties) => void;
|
|
85
98
|
}
|
|
86
99
|
/**
|
|
87
100
|
* LiveStateRenderer props
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IAEd,sBAAsB;IACtB,GAAG,EAAE,MAAM,CAAC;IAEZ,wBAAwB;IACxB,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IAE3C,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAEhB,4BAA4B;IAC5B,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAEnC,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IAEd,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAEhB,mCAAmC;IACnC,GAAG,EAAE,SAAS,CAAC;IAEf,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAE3B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IAEd,sBAAsB;IACtB,GAAG,EAAE,MAAM,CAAC;IAEZ,wBAAwB;IACxB,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IAE3C,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAEhB,4BAA4B;IAC5B,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAEnC,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IAEd,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAEhB,mCAAmC;IACnC,GAAG,EAAE,SAAS,CAAC;IAEf,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAE3B,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,kBAAkB,GAAG;QAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IAEf,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IAEb,qCAAqC;IACrC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,yBAAyB;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,SAAS,CAAC;IAEpB,8CAA8C;IAC9C,OAAO,EAAE,gBAAgB,CAAC;IAE1B,8BAA8B;IAC9B,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACxE;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,sBAAsB;IACtB,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAE/B,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,6BAA6B;IAC7B,cAAc,EAAE,cAAc,CAAC;IAE/B,8BAA8B;IAC9B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B,0CAA0C;IAC1C,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../../src/utils/analytics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../../src/utils/analytics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAQlE;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAaxD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBzE;AA2BD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,kBAAkB,GAC9B,IAAI,CAMN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,kBAAkB,GAC9B,IAAI,CAeN;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAAC,GAChD,kBAAkB,CAMpB;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,kBAAkB,GAC9B,IAAI,CAGN;AAED;;;GAGG;AACH,KAAK,cAAc,GACf,MAAM,GACN,OAAO,GACP,KAAK,GACL,UAAU,GACV,SAAS,GACT,SAAS,CAAC;AAEd,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,OAAO,CAAC,EAAE;YACR,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;YACnD,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;SAChB,CAAC;KACH;CACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface ClosableState {
|
|
2
|
+
count: number;
|
|
3
|
+
closedAt: number;
|
|
4
|
+
}
|
|
5
|
+
export type ClosableStates = Record<string, Record<string, ClosableState>>;
|
|
6
|
+
/**
|
|
7
|
+
* Reads closable states from localStorage.
|
|
8
|
+
* Normalises legacy format (plain number) to the current shape ({ count, closedAt }).
|
|
9
|
+
* Returns an empty object on any error (fail-silent).
|
|
10
|
+
*/
|
|
11
|
+
export declare function getClosableStates(): ClosableStates;
|
|
12
|
+
/**
|
|
13
|
+
* Persists closable states to localStorage.
|
|
14
|
+
* Fails silently if localStorage is unavailable or full.
|
|
15
|
+
*/
|
|
16
|
+
export declare function setClosableStates(states: ClosableStates): void;
|
|
17
|
+
//# sourceMappingURL=closable-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"closable-storage.d.ts","sourceRoot":"","sources":["../../../src/utils/closable-storage.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;AAE3E;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAsClD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAM9D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiendanube/live-state",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.7",
|
|
4
4
|
"description": "Generic React library for rendering live state notifications",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -33,8 +33,6 @@
|
|
|
33
33
|
"verify:build": "./scripts/test-build.sh"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@amplitude/analytics-browser": "^2.0.0",
|
|
37
|
-
"@microsoft/clarity": "^1.0.0",
|
|
38
36
|
"@nimbus-ds/components": "^5.41.0",
|
|
39
37
|
"@nimbus-ds/icons": "^1.14.0",
|
|
40
38
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -42,14 +40,15 @@
|
|
|
42
40
|
"swr": "^2.0.0"
|
|
43
41
|
},
|
|
44
42
|
"peerDependenciesMeta": {
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
"swr": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@amplitude/analytics-browser": "^2.11.1",
|
|
49
|
+
"@microsoft/clarity": "^1.0.0"
|
|
48
50
|
},
|
|
49
|
-
"dependencies": {},
|
|
50
51
|
"devDependencies": {
|
|
51
|
-
"@amplitude/analytics-browser": "^2.39.0",
|
|
52
|
-
"@microsoft/clarity": "^1.0.2",
|
|
53
52
|
"@eslint/js": "^10.0.1",
|
|
54
53
|
"@nimbus-ds/components": "5.41.0",
|
|
55
54
|
"@nimbus-ds/icons": "1.14.0",
|
|
@@ -71,13 +70,13 @@
|
|
|
71
70
|
"eslint-plugin-react": "^7.37.5",
|
|
72
71
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
73
72
|
"globals": "^17.4.0",
|
|
74
|
-
"jsdom": "
|
|
73
|
+
"jsdom": "26.1.0",
|
|
75
74
|
"prettier": "^3.8.2",
|
|
76
75
|
"react": "^19.0.0",
|
|
77
76
|
"react-dom": "^19.0.0",
|
|
77
|
+
"swr": "^2.4.1",
|
|
78
78
|
"typescript": "^6.0.2",
|
|
79
79
|
"vite": "^8.0.8",
|
|
80
|
-
"swr": "^2.4.1",
|
|
81
80
|
"vite-plugin-dts": "^4.5.4",
|
|
82
81
|
"vitest": "^4.1.4"
|
|
83
82
|
},
|