@shellapps/experience-react 1.10.1 → 1.10.3

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.js CHANGED
@@ -52,30 +52,54 @@ var ExperienceContext = (0, import_react.createContext)(null);
52
52
 
53
53
  // src/ExperienceProvider.tsx
54
54
  var import_jsx_runtime = require("react/jsx-runtime");
55
+ function shouldEnableExperience(appId, apiKey, options) {
56
+ if (!appId || !apiKey) return false;
57
+ const endpoint = options?.endpoint;
58
+ if (!endpoint) return true;
59
+ const looksLocal = /localhost|127\.0\.0\.1/i.test(endpoint);
60
+ if (process.env.NODE_ENV === "production" && looksLocal) {
61
+ console.warn("[ExperienceSDK] Disabled: localhost endpoint configured in production.", { endpoint });
62
+ return false;
63
+ }
64
+ return true;
65
+ }
55
66
  function ExperienceProvider({ appId, apiKey, profileId, options, children }) {
56
67
  const instanceRef = (0, import_react2.useRef)(null);
57
68
  const [, forceUpdate] = (0, import_react2.useState)(0);
58
- if (typeof window !== "undefined" && !instanceRef.current) {
59
- const instance = import_experience.Experience.init({ appId, apiKey, ...options });
60
- if (profileId) instance.identify(profileId);
61
- instanceRef.current = instance;
69
+ const isEnabled = shouldEnableExperience(appId, apiKey, options);
70
+ if (isEnabled && typeof window !== "undefined" && !instanceRef.current) {
71
+ try {
72
+ const instance = import_experience.Experience.init({ appId, apiKey, ...options });
73
+ if (profileId) instance.identify(profileId);
74
+ instanceRef.current = instance;
75
+ } catch (error) {
76
+ console.error("[ExperienceSDK] Initialization failed. Running app without telemetry.", error);
77
+ instanceRef.current = null;
78
+ }
62
79
  }
63
80
  (0, import_react2.useEffect)(() => {
64
- if (!instanceRef.current) {
81
+ if (!isEnabled || instanceRef.current) return;
82
+ try {
65
83
  const instance = import_experience.Experience.init({ appId, apiKey, ...options });
66
84
  if (profileId) instance.identify(profileId);
67
85
  instanceRef.current = instance;
68
86
  forceUpdate((n) => n + 1);
87
+ } catch (error) {
88
+ console.error("[ExperienceSDK] Initialization failed in effect. Running app without telemetry.", error);
89
+ instanceRef.current = null;
69
90
  }
70
- }, []);
91
+ }, [isEnabled, appId, apiKey, options, profileId]);
71
92
  (0, import_react2.useEffect)(() => {
72
93
  if (profileId && instanceRef.current) {
73
94
  instanceRef.current.identify(profileId);
74
95
  }
75
96
  }, [profileId]);
76
97
  (0, import_react2.useEffect)(() => {
98
+ if (!isEnabled) return;
77
99
  const handler = (e) => {
78
- let el = e.target;
100
+ const initialTarget = e.target;
101
+ if (!(initialTarget instanceof Element)) return;
102
+ let el = initialTarget;
79
103
  while (el) {
80
104
  const tid = el.getAttribute?.("data-t");
81
105
  if (tid) {
@@ -87,7 +111,7 @@ function ExperienceProvider({ appId, apiKey, profileId, options, children }) {
87
111
  };
88
112
  document.addEventListener("click", handler, true);
89
113
  return () => document.removeEventListener("click", handler, true);
90
- }, []);
114
+ }, [isEnabled]);
91
115
  (0, import_react2.useEffect)(() => {
92
116
  return () => {
93
117
  instanceRef.current?.shutdown();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/ExperienceProvider.tsx","../src/context.ts","../src/ErrorBoundary.tsx","../src/FeedbackButton.tsx","../src/hooks.ts"],"sourcesContent":["export { ExperienceProvider } from './ExperienceProvider';\nexport type { ExperienceProviderProps } from './ExperienceProvider';\nexport { ErrorBoundary } from './ErrorBoundary';\nexport { FeedbackButton } from './FeedbackButton';\nexport { useExperience, useTrack, useFlag, useTranslation } from './hooks';\nexport { ExperienceContext } from './context';\n","'use client';\n\nimport React, { useEffect, useRef, useState } from 'react';\nimport { Experience } from '@shellapps/experience';\nimport type { ExperienceConfig } from '@shellapps/experience';\nimport { ExperienceContext } from './context';\n\nexport interface ExperienceProviderProps {\n appId: string;\n apiKey: string;\n profileId?: string;\n options?: Partial<Omit<ExperienceConfig, 'appId' | 'apiKey'>>;\n children: any;\n}\n\nexport function ExperienceProvider({ appId, apiKey, profileId, options, children }: ExperienceProviderProps) {\n const instanceRef = useRef<Experience | null>(null);\n const [, forceUpdate] = useState(0);\n\n // Only initialize on the client (browser) — skip during SSR/prerendering\n if (typeof window !== 'undefined' && !instanceRef.current) {\n const instance = Experience.init({ appId, apiKey, ...options });\n if (profileId) instance.identify(profileId);\n instanceRef.current = instance;\n }\n\n useEffect(() => {\n // Handle case where ref wasn't set during SSR render pass\n if (!instanceRef.current) {\n const instance = Experience.init({ appId, apiKey, ...options });\n if (profileId) instance.identify(profileId);\n instanceRef.current = instance;\n forceUpdate((n) => n + 1);\n }\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n if (profileId && instanceRef.current) {\n instanceRef.current.identify(profileId);\n }\n }, [profileId]);\n\n // data-t auto-tracking\n useEffect(() => {\n const handler = (e: MouseEvent) => {\n let el = e.target as HTMLElement | null;\n while (el) {\n const tid = el.getAttribute?.('data-t');\n if (tid) {\n instanceRef.current?.track('element_click', { elementTid: tid });\n break;\n }\n el = el.parentElement;\n }\n };\n document.addEventListener('click', handler, true);\n return () => document.removeEventListener('click', handler, true);\n }, []);\n\n useEffect(() => {\n return () => {\n instanceRef.current?.shutdown();\n };\n }, []);\n\n return (\n <ExperienceContext.Provider value={instanceRef.current}>\n {children}\n </ExperienceContext.Provider>\n );\n}\n","'use client';\nimport { createContext } from 'react';\nimport type { Experience } from '@shellapps/experience';\n\nexport const ExperienceContext = createContext<Experience | null>(null);\n","'use client';\nimport React from 'react';\nimport type { Experience } from '@shellapps/experience';\nimport { ExperienceContext } from './context';\n\ninterface ErrorBoundaryProps {\n fallback?: React.ReactNode;\n showCommentForm?: boolean;\n onError?: (error: Error, errorInfo: React.ErrorInfo) => void;\n children: any;\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n comment: string;\n submitted: boolean;\n}\n\nexport class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n static contextType = ExperienceContext;\n declare context: Experience | null;\n\n state: ErrorBoundaryState = {\n hasError: false,\n error: null,\n comment: '',\n submitted: false,\n };\n\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n this.context?.captureError(error, {\n extra: { componentStack: errorInfo.componentStack || '' },\n severity: 'fatal' as any,\n });\n this.props.onError?.(error, errorInfo);\n }\n\n private handleSubmitComment = () => {\n if (this.state.comment.trim() && this.state.error) {\n this.context?.captureMessage(\n `User feedback: ${this.state.comment}`,\n 'info',\n );\n this.setState({ submitted: true });\n }\n };\n\n render() {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n return (\n <div style={{ padding: 20, textAlign: 'center' }}>\n <h2>Something went wrong</h2>\n <p>{this.state.error?.message}</p>\n {this.props.showCommentForm && !this.state.submitted && (\n <div>\n <textarea\n placeholder=\"Tell us what happened...\"\n value={this.state.comment}\n onChange={(e) => this.setState({ comment: e.target.value })}\n style={{ width: '100%', minHeight: 80, marginTop: 10 }}\n />\n <button onClick={this.handleSubmitComment} style={{ marginTop: 8 }}>\n Submit\n </button>\n </div>\n )}\n {this.state.submitted && <p>Thank you for your feedback!</p>}\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n","'use client';\nimport React, { useState, useEffect, useCallback, useRef, useContext } from 'react';\nimport { ExperienceContext } from './context';\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\ntype FeedbackType = 'bug' | 'feature-request' | 'comment' | 'praise';\ntype FeedbackStatus = 'new' | 'acknowledged' | 'in-progress' | 'resolved' | 'wont-fix';\n\ninterface FeedbackItem {\n _id: string;\n type: FeedbackType;\n title: string;\n content: string;\n status: FeedbackStatus;\n tags: string[];\n vote_count: number;\n reply_count: number;\n created_at: string;\n}\n\ninterface FeedbackReply {\n _id: string;\n author_type: 'user' | 'developer';\n author_name?: string;\n content: string;\n created_at: string;\n}\n\ninterface FeedbackButtonProps {\n /** Position of the floating button */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n /** Custom button label */\n label?: string;\n /** Button colour */\n color?: string;\n /** Hide the floating button (use exp.openFeedback() instead) */\n hidden?: boolean;\n /** API endpoint base URL */\n apiUrl?: string;\n /** Auth token for user endpoints */\n authToken?: string;\n}\n\n// ── Styles ─────────────────────────────────────────────────────────────────\n\nconst TYPE_META: Record<FeedbackType, { icon: string; label: string; color: string }> = {\n 'bug': { icon: '🐛', label: 'Bug Report', color: '#ef4444' },\n 'feature-request': { icon: '💡', label: 'Feature Request', color: '#8b5cf6' },\n 'comment': { icon: '💬', label: 'Comment', color: '#3b82f6' },\n 'praise': { icon: '🎉', label: 'Praise', color: '#10b981' },\n};\n\nconst STATUS_LABELS: Record<FeedbackStatus, string> = {\n 'new': '🆕 New',\n 'acknowledged': '👀 Acknowledged',\n 'in-progress': '🔧 In Progress',\n 'resolved': '✅ Resolved',\n 'wont-fix': '🚫 Won\\'t Fix',\n};\n\n// ── Component ──────────────────────────────────────────────────────────────\n\nexport function FeedbackButton({\n position = 'bottom-right',\n label = 'Feedback',\n color = '#6366f1',\n hidden = false,\n apiUrl,\n authToken,\n}: FeedbackButtonProps) {\n const experience = useContext(ExperienceContext);\n const [isOpen, setIsOpen] = useState(false);\n const [view, setView] = useState<'list' | 'new' | 'detail'>('list');\n const [selectedType, setSelectedType] = useState<FeedbackType>('comment');\n const [title, setTitle] = useState('');\n const [content, setContent] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [items, setItems] = useState<FeedbackItem[]>([]);\n const [selectedItem, setSelectedItem] = useState<FeedbackItem | null>(null);\n const [replies, setReplies] = useState<FeedbackReply[]>([]);\n const [replyText, setReplyText] = useState('');\n const [loading, setLoading] = useState(false);\n const [screenshot, setScreenshot] = useState<string | null>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n\n const baseUrl = apiUrl || (experience as any)?.config?.apiUrl || 'https://experience.shellapps.com';\n const appId = (experience as any)?.config?.appId || '';\n\n const headers = useCallback((): Record<string, string> => {\n const h: Record<string, string> = { 'Content-Type': 'application/json' };\n if (authToken) h['Authorization'] = `Bearer ${authToken}`;\n return h;\n }, [authToken]);\n\n // Expose openFeedback on the experience instance\n useEffect(() => {\n if (experience) {\n (experience as any).openFeedback = () => setIsOpen(true);\n }\n return () => {\n if (experience) delete (experience as any).openFeedback;\n };\n }, [experience]);\n\n // Load feedback list when opening\n useEffect(() => {\n if (isOpen && view === 'list') {\n loadFeedback();\n }\n }, [isOpen, view]);\n\n const loadFeedback = async () => {\n setLoading(true);\n try {\n const res = await fetch(\n `${baseUrl}/api/v1/feedback?appId=${appId}&limit=20`,\n { headers: headers() },\n );\n if (res.ok) {\n const data = await res.json();\n setItems(data.items || []);\n }\n } catch {\n // silently fail\n }\n setLoading(false);\n };\n\n const loadDetail = async (item: FeedbackItem) => {\n setSelectedItem(item);\n setView('detail');\n try {\n const res = await fetch(\n `${baseUrl}/api/v1/feedback/${item._id}`,\n { headers: headers() },\n );\n if (res.ok) {\n const data = await res.json();\n setReplies(data.replies || []);\n }\n } catch {\n // silently fail\n }\n };\n\n const captureScreenshot = async () => {\n try {\n const html2canvas = (window as any).html2canvas;\n if (!html2canvas) return;\n const canvas = await html2canvas(document.body, { scale: 0.5, logging: false });\n setScreenshot(canvas.toDataURL('image/jpeg', 0.6));\n } catch {\n // screenshot not available\n }\n };\n\n const submit = async () => {\n if (!title.trim() || !content.trim()) return;\n setSubmitting(true);\n try {\n const ctx = {\n userAgent: navigator.userAgent,\n url: window.location.href,\n viewport: { width: window.innerWidth, height: window.innerHeight },\n locale: navigator.language,\n referrer: document.referrer || undefined,\n };\n\n const res = await fetch(`${baseUrl}/api/v1/feedback`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({\n appId,\n type: selectedType,\n title: title.trim(),\n content: content.trim(),\n context: ctx,\n screenshot: screenshot || undefined,\n }),\n });\n\n if (res.ok) {\n setTitle('');\n setContent('');\n setScreenshot(null);\n setView('list');\n loadFeedback();\n }\n } catch {\n // silently fail\n }\n setSubmitting(false);\n };\n\n const submitReply = async () => {\n if (!replyText.trim() || !selectedItem) return;\n try {\n const res = await fetch(`${baseUrl}/api/v1/feedback/${selectedItem._id}/reply`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({ content: replyText.trim() }),\n });\n if (res.ok) {\n const reply = await res.json();\n setReplies((prev) => [...prev, reply]);\n setReplyText('');\n }\n } catch {\n // silently fail\n }\n };\n\n const vote = async (id: string) => {\n try {\n await fetch(`${baseUrl}/api/v1/feedback/${id}/vote`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({ type: 'upvote' }),\n });\n loadFeedback();\n } catch {\n // silently fail\n }\n };\n\n // ── Position styles ──────────────────────────────────────────────────────\n\n const posStyles: Record<string, React.CSSProperties> = {\n 'bottom-right': { bottom: 20, right: 20 },\n 'bottom-left': { bottom: 20, left: 20 },\n 'top-right': { top: 20, right: 20 },\n 'top-left': { top: 20, left: 20 },\n };\n\n const panelPos: Record<string, React.CSSProperties> = {\n 'bottom-right': { bottom: 70, right: 20 },\n 'bottom-left': { bottom: 70, left: 20 },\n 'top-right': { top: 70, right: 20 },\n 'top-left': { top: 70, left: 20 },\n };\n\n // ── Render ───────────────────────────────────────────────────────────────\n\n return (\n <>\n {/* Floating button */}\n {!hidden && (\n <button\n onClick={() => setIsOpen(!isOpen)}\n style={{\n position: 'fixed',\n ...posStyles[position],\n zIndex: 99999,\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 28,\n padding: '10px 20px',\n fontSize: 14,\n fontWeight: 600,\n cursor: 'pointer',\n boxShadow: '0 4px 12px rgba(0,0,0,0.15)',\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n }}\n >\n 💬 {label}\n </button>\n )}\n\n {/* Panel */}\n {isOpen && (\n <div\n ref={panelRef}\n style={{\n position: 'fixed',\n ...panelPos[position],\n zIndex: 100000,\n width: 380,\n maxHeight: 520,\n background: '#fff',\n borderRadius: 12,\n boxShadow: '0 8px 32px rgba(0,0,0,0.18)',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n fontSize: 14,\n color: '#1f2937',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: '14px 16px',\n background: color,\n color: '#fff',\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n }}\n >\n <span style={{ fontWeight: 600 }}>\n {view === 'new' ? 'New Feedback' : view === 'detail' ? 'Feedback' : 'Feedback'}\n </span>\n <div style={{ display: 'flex', gap: 8 }}>\n {view !== 'list' && (\n <button\n onClick={() => { setView('list'); setSelectedItem(null); }}\n style={{ background: 'none', border: 'none', color: '#fff', cursor: 'pointer', fontSize: 14 }}\n >\n ← Back\n </button>\n )}\n <button\n onClick={() => setIsOpen(false)}\n style={{ background: 'none', border: 'none', color: '#fff', cursor: 'pointer', fontSize: 18 }}\n >\n ✕\n </button>\n </div>\n </div>\n\n {/* Body */}\n <div style={{ flex: 1, overflow: 'auto', padding: 16 }}>\n {/* LIST VIEW */}\n {view === 'list' && (\n <>\n <button\n onClick={() => setView('new')}\n style={{\n width: '100%',\n padding: '10px',\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: 'pointer',\n fontWeight: 600,\n marginBottom: 12,\n }}\n >\n + New Feedback\n </button>\n {loading ? (\n <p style={{ textAlign: 'center', color: '#9ca3af' }}>Loading…</p>\n ) : items.length === 0 ? (\n <p style={{ textAlign: 'center', color: '#9ca3af' }}>No feedback yet</p>\n ) : (\n items.map((item) => (\n <div\n key={item._id}\n onClick={() => loadDetail(item)}\n style={{\n padding: 10,\n borderRadius: 8,\n border: '1px solid #e5e7eb',\n marginBottom: 8,\n cursor: 'pointer',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>\n <span>\n {TYPE_META[item.type]?.icon} <strong>{item.title}</strong>\n </span>\n {item.type === 'feature-request' && (\n <button\n onClick={(e) => { e.stopPropagation(); vote(item._id); }}\n style={{\n background: 'none',\n border: '1px solid #d1d5db',\n borderRadius: 4,\n padding: '2px 6px',\n cursor: 'pointer',\n fontSize: 12,\n }}\n >\n ▲ {item.vote_count}\n </button>\n )}\n </div>\n <div style={{ fontSize: 12, color: '#6b7280' }}>\n {STATUS_LABELS[item.status]} · {item.reply_count} replies · {new Date(item.created_at).toLocaleDateString()}\n </div>\n </div>\n ))\n )}\n </>\n )}\n\n {/* NEW FEEDBACK VIEW */}\n {view === 'new' && (\n <>\n {/* Type selector */}\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 12 }}>\n {(Object.entries(TYPE_META) as [FeedbackType, typeof TYPE_META['bug']][]).map(\n ([type, meta]) => (\n <button\n key={type}\n onClick={() => setSelectedType(type)}\n style={{\n padding: 8,\n borderRadius: 8,\n border: `2px solid ${selectedType === type ? meta.color : '#e5e7eb'}`,\n background: selectedType === type ? `${meta.color}10` : '#fff',\n cursor: 'pointer',\n fontSize: 13,\n textAlign: 'center',\n }}\n >\n {meta.icon} {meta.label}\n </button>\n ),\n )}\n </div>\n\n <input\n placeholder=\"Title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n style={{\n width: '100%',\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n marginBottom: 8,\n fontSize: 14,\n boxSizing: 'border-box',\n }}\n />\n\n <textarea\n placeholder=\"Describe your feedback…\"\n value={content}\n onChange={(e) => setContent(e.target.value)}\n rows={4}\n style={{\n width: '100%',\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n marginBottom: 8,\n fontSize: 14,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n\n {/* Screenshot button */}\n {(window as any).html2canvas && (\n <button\n onClick={captureScreenshot}\n style={{\n background: 'none',\n border: '1px solid #d1d5db',\n borderRadius: 6,\n padding: '6px 10px',\n cursor: 'pointer',\n fontSize: 12,\n marginBottom: 8,\n color: screenshot ? '#10b981' : '#6b7280',\n }}\n >\n 📷 {screenshot ? 'Screenshot captured ✓' : 'Capture screenshot'}\n </button>\n )}\n\n <button\n onClick={submit}\n disabled={submitting || !title.trim() || !content.trim()}\n style={{\n width: '100%',\n padding: 10,\n background: submitting ? '#9ca3af' : color,\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: submitting ? 'default' : 'pointer',\n fontWeight: 600,\n }}\n >\n {submitting ? 'Submitting…' : 'Submit'}\n </button>\n </>\n )}\n\n {/* DETAIL VIEW */}\n {view === 'detail' && selectedItem && (\n <>\n <div style={{ marginBottom: 12 }}>\n <div style={{ fontSize: 12, color: TYPE_META[selectedItem.type]?.color, fontWeight: 600, marginBottom: 4 }}>\n {TYPE_META[selectedItem.type]?.icon} {TYPE_META[selectedItem.type]?.label}\n </div>\n <h3 style={{ margin: '0 0 4px', fontSize: 16 }}>{selectedItem.title}</h3>\n <div style={{ fontSize: 12, color: '#6b7280', marginBottom: 8 }}>\n {STATUS_LABELS[selectedItem.status]} · {new Date(selectedItem.created_at).toLocaleDateString()}\n </div>\n <p style={{ margin: 0, lineHeight: 1.5 }}>{selectedItem.content}</p>\n </div>\n\n <hr style={{ border: 'none', borderTop: '1px solid #e5e7eb', margin: '12px 0' }} />\n\n {/* Replies */}\n <div style={{ marginBottom: 12 }}>\n <strong style={{ fontSize: 13 }}>Replies ({replies.length})</strong>\n {replies.map((r) => (\n <div\n key={r._id}\n style={{\n padding: 8,\n marginTop: 8,\n borderRadius: 6,\n background: r.author_type === 'developer' ? '#eff6ff' : '#f9fafb',\n borderLeft: `3px solid ${r.author_type === 'developer' ? '#3b82f6' : '#d1d5db'}`,\n }}\n >\n <div style={{ fontSize: 11, color: '#6b7280', marginBottom: 2 }}>\n {r.author_type === 'developer' ? '🛠️ Developer' : '👤 You'}{r.author_name ? ` · ${r.author_name}` : ''} · {new Date(r.created_at).toLocaleDateString()}\n </div>\n <div style={{ fontSize: 13 }}>{r.content}</div>\n </div>\n ))}\n </div>\n\n {/* Reply input */}\n <div style={{ display: 'flex', gap: 6 }}>\n <input\n placeholder=\"Write a reply…\"\n value={replyText}\n onChange={(e) => setReplyText(e.target.value)}\n onKeyDown={(e) => { if (e.key === 'Enter') submitReply(); }}\n style={{\n flex: 1,\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n fontSize: 13,\n }}\n />\n <button\n onClick={submitReply}\n disabled={!replyText.trim()}\n style={{\n padding: '8px 12px',\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 6,\n cursor: 'pointer',\n fontSize: 13,\n }}\n >\n Send\n </button>\n </div>\n </>\n )}\n </div>\n </div>\n )}\n </>\n );\n}\n","'use client';\nimport { useContext, useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport { ExperienceContext } from './context';\n\nexport function useExperience() {\n const ctx = useContext(ExperienceContext);\n if (!ctx) throw new Error('useExperience must be used within ExperienceProvider');\n return ctx;\n}\n\nexport function useTrack() {\n const experience = useExperience();\n return useMemo(() => ({\n track: (eventName: string, metadata?: Record<string, string>) => experience.track(eventName, metadata),\n trackPageView: () => experience.trackPageView(),\n }), [experience]);\n}\n\nexport function useFlag<T>(flagName: string, defaultValue: T): T {\n const experience = useExperience();\n return experience.getFlag(flagName, defaultValue);\n}\n\n// ─── Translation Types ──────────────────────────────────────────\n\ninterface TranslationResult {\n t: (key: string, params?: Record<string, string | number>) => string;\n locale: string;\n setLocale: (locale: string) => void;\n locales: Array<{ code: string; name: string; progress?: number }>;\n isLoading: boolean;\n}\n\ninterface TranslationCache {\n [locale: string]: Record<string, string>;\n}\n\n// Module-level cache shared across hook instances\nconst translationCache: TranslationCache = {};\nconst fetchPromises = new Map<string, Promise<Record<string, string>>>();\n\n/**\n * Translation hook for the Experience Platform.\n *\n * Fetches translations from the Experience API, caches in memory + localStorage,\n * and provides `t()` for interpolation and `setLocale()` for switching.\n *\n * Usage:\n * ```tsx\n * const { t, locale, setLocale, locales } = useTranslation();\n * return <h1>{t('greeting', { name: 'Alex' })}</h1>;\n * ```\n */\nexport function useTranslation(): TranslationResult {\n const experience = useExperience();\n const config = (experience as any).config || {};\n const appId: string = config.appId || '';\n const apiBaseUrl: string = config.apiUrl || config.baseUrl || 'https://experience-api.shellapps.com';\n\n const [locale, setLocaleState] = useState(() => {\n if (typeof window === 'undefined') return 'en';\n // Check localStorage for persisted locale preference\n const saved = localStorage.getItem(`exp_locale_${appId}`);\n if (saved) return saved;\n return navigator.language?.split('-')[0] || 'en';\n });\n\n const [translations, setTranslations] = useState<Record<string, string>>(() => {\n // Try memory cache first\n if (translationCache[locale]) return translationCache[locale]!;\n // Try localStorage\n if (typeof window !== 'undefined') {\n try {\n const cached = localStorage.getItem(`exp_translations_${appId}_${locale}`);\n if (cached) {\n const parsed = JSON.parse(cached);\n translationCache[locale] = parsed;\n return parsed;\n }\n } catch { /* ignore */ }\n }\n return {};\n });\n\n const [locales, setLocales] = useState<Array<{ code: string; name: string; progress?: number }>>([]);\n const [isLoading, setIsLoading] = useState(false);\n\n // Fetch translations for a locale\n const fetchTranslations = useCallback(async (loc: string): Promise<Record<string, string>> => {\n if (!appId) return {};\n\n // Deduplicate in-flight requests\n const cacheKey = `${appId}_${loc}`;\n const existing = fetchPromises.get(cacheKey);\n if (existing) return existing;\n\n const promise = (async () => {\n try {\n const res = await fetch(`${apiBaseUrl}/api/v1/translations/${appId}/${loc}`);\n if (!res.ok) return {};\n const data = await res.json();\n // Cache in memory and localStorage\n translationCache[loc] = data;\n if (typeof window !== 'undefined') {\n try {\n localStorage.setItem(`exp_translations_${appId}_${loc}`, JSON.stringify(data));\n } catch { /* quota exceeded, ignore */ }\n }\n return data as Record<string, string>;\n } catch {\n return {};\n } finally {\n fetchPromises.delete(cacheKey);\n }\n })();\n\n fetchPromises.set(cacheKey, promise);\n return promise;\n }, [appId, apiBaseUrl]);\n\n // Fetch available locales\n useEffect(() => {\n if (!appId) return;\n fetch(`${apiBaseUrl}/api/v1/translations/${appId}/locales`)\n .then(res => res.ok ? res.json() : { locales: [] })\n .then(data => setLocales(data.locales || []))\n .catch(() => {});\n }, [appId, apiBaseUrl]);\n\n // Fetch translations when locale changes\n useEffect(() => {\n if (!appId) return;\n\n // Use cached if available\n if (translationCache[locale]) {\n setTranslations(translationCache[locale]!);\n return;\n }\n\n setIsLoading(true);\n fetchTranslations(locale).then(data => {\n setTranslations(data);\n setIsLoading(false);\n });\n }, [locale, appId, fetchTranslations]);\n\n // t() function with interpolation and plural support\n const t = useCallback((key: string, params?: Record<string, string | number>): string => {\n let result = translations[key] ?? key;\n\n // Handle plurals: \"singular||plural\" with count param\n if (result.includes('||') && params && 'count' in params) {\n const parts = result.split('||');\n const count = Number(params.count);\n result = count === 1 ? (parts[0] ?? result) : (parts[1] ?? result);\n }\n\n // Handle interpolation: {{variable}}\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n result = result.replace(new RegExp(`\\{\\{${k}\\}\\}`, 'g'), String(v));\n }\n }\n\n return result;\n }, [translations]);\n\n // setLocale with persistence\n const setLocale = useCallback((newLocale: string) => {\n setLocaleState(newLocale);\n if (typeof window !== 'undefined') {\n localStorage.setItem(`exp_locale_${appId}`, newLocale);\n }\n }, [appId]);\n\n return { t, locale, setLocale, locales, isLoading };\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","import_react"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/ExperienceProvider.tsx","../src/context.ts","../src/ErrorBoundary.tsx","../src/FeedbackButton.tsx","../src/hooks.ts"],"sourcesContent":["export { ExperienceProvider } from './ExperienceProvider';\nexport type { ExperienceProviderProps } from './ExperienceProvider';\nexport { ErrorBoundary } from './ErrorBoundary';\nexport { FeedbackButton } from './FeedbackButton';\nexport { useExperience, useTrack, useFlag, useTranslation } from './hooks';\nexport { ExperienceContext } from './context';\n","'use client';\n\nimport React, { useEffect, useRef, useState } from 'react';\nimport { Experience } from '@shellapps/experience';\nimport type { ExperienceConfig } from '@shellapps/experience';\nimport { ExperienceContext } from './context';\n\nexport interface ExperienceProviderProps {\n appId: string;\n apiKey: string;\n profileId?: string;\n options?: Partial<Omit<ExperienceConfig, 'appId' | 'apiKey'>>;\n children: any;\n}\n\nfunction shouldEnableExperience(appId: string, apiKey: string, options?: Partial<Omit<ExperienceConfig, 'appId' | 'apiKey'>>): boolean {\n if (!appId || !apiKey) return false;\n\n const endpoint = options?.endpoint;\n if (!endpoint) return true;\n\n const looksLocal = /localhost|127\\.0\\.0\\.1/i.test(endpoint);\n if (process.env.NODE_ENV === 'production' && looksLocal) {\n console.warn('[ExperienceSDK] Disabled: localhost endpoint configured in production.', { endpoint });\n return false;\n }\n\n return true;\n}\n\nexport function ExperienceProvider({ appId, apiKey, profileId, options, children }: ExperienceProviderProps) {\n const instanceRef = useRef<Experience | null>(null);\n const [, forceUpdate] = useState(0);\n const isEnabled = shouldEnableExperience(appId, apiKey, options);\n\n // Only initialize on the client (browser) — skip during SSR/prerendering\n if (isEnabled && typeof window !== 'undefined' && !instanceRef.current) {\n try {\n const instance = Experience.init({ appId, apiKey, ...options });\n if (profileId) instance.identify(profileId);\n instanceRef.current = instance;\n } catch (error) {\n console.error('[ExperienceSDK] Initialization failed. Running app without telemetry.', error);\n instanceRef.current = null;\n }\n }\n\n useEffect(() => {\n if (!isEnabled || instanceRef.current) return;\n\n try {\n const instance = Experience.init({ appId, apiKey, ...options });\n if (profileId) instance.identify(profileId);\n instanceRef.current = instance;\n forceUpdate((n) => n + 1);\n } catch (error) {\n console.error('[ExperienceSDK] Initialization failed in effect. Running app without telemetry.', error);\n instanceRef.current = null;\n }\n }, [isEnabled, appId, apiKey, options, profileId]);\n\n useEffect(() => {\n if (profileId && instanceRef.current) {\n instanceRef.current.identify(profileId);\n }\n }, [profileId]);\n\n // data-t auto-tracking\n useEffect(() => {\n if (!isEnabled) return;\n\n const handler = (e: MouseEvent) => {\n const initialTarget = e.target;\n if (!(initialTarget instanceof Element)) return;\n\n let el: Element | null = initialTarget;\n while (el) {\n const tid = el.getAttribute?.('data-t');\n if (tid) {\n instanceRef.current?.track('element_click', { elementTid: tid });\n break;\n }\n el = el.parentElement;\n }\n };\n\n document.addEventListener('click', handler, true);\n return () => document.removeEventListener('click', handler, true);\n }, [isEnabled]);\n\n useEffect(() => {\n return () => {\n instanceRef.current?.shutdown();\n };\n }, []);\n\n return (\n <ExperienceContext.Provider value={instanceRef.current}>\n {children}\n </ExperienceContext.Provider>\n );\n}\n","'use client';\nimport { createContext } from 'react';\nimport type { Experience } from '@shellapps/experience';\n\nexport const ExperienceContext = createContext<Experience | null>(null);\n","'use client';\nimport React from 'react';\nimport type { Experience } from '@shellapps/experience';\nimport { ExperienceContext } from './context';\n\ninterface ErrorBoundaryProps {\n fallback?: React.ReactNode;\n showCommentForm?: boolean;\n onError?: (error: Error, errorInfo: React.ErrorInfo) => void;\n children: any;\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n comment: string;\n submitted: boolean;\n}\n\nexport class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n static contextType = ExperienceContext;\n declare context: Experience | null;\n\n state: ErrorBoundaryState = {\n hasError: false,\n error: null,\n comment: '',\n submitted: false,\n };\n\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n this.context?.captureError(error, {\n extra: { componentStack: errorInfo.componentStack || '' },\n severity: 'fatal' as any,\n });\n this.props.onError?.(error, errorInfo);\n }\n\n private handleSubmitComment = () => {\n if (this.state.comment.trim() && this.state.error) {\n this.context?.captureMessage(\n `User feedback: ${this.state.comment}`,\n 'info',\n );\n this.setState({ submitted: true });\n }\n };\n\n render() {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n return (\n <div style={{ padding: 20, textAlign: 'center' }}>\n <h2>Something went wrong</h2>\n <p>{this.state.error?.message}</p>\n {this.props.showCommentForm && !this.state.submitted && (\n <div>\n <textarea\n placeholder=\"Tell us what happened...\"\n value={this.state.comment}\n onChange={(e) => this.setState({ comment: e.target.value })}\n style={{ width: '100%', minHeight: 80, marginTop: 10 }}\n />\n <button onClick={this.handleSubmitComment} style={{ marginTop: 8 }}>\n Submit\n </button>\n </div>\n )}\n {this.state.submitted && <p>Thank you for your feedback!</p>}\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n","'use client';\nimport React, { useState, useEffect, useCallback, useRef, useContext } from 'react';\nimport { ExperienceContext } from './context';\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\ntype FeedbackType = 'bug' | 'feature-request' | 'comment' | 'praise';\ntype FeedbackStatus = 'new' | 'acknowledged' | 'in-progress' | 'resolved' | 'wont-fix';\n\ninterface FeedbackItem {\n _id: string;\n type: FeedbackType;\n title: string;\n content: string;\n status: FeedbackStatus;\n tags: string[];\n vote_count: number;\n reply_count: number;\n created_at: string;\n}\n\ninterface FeedbackReply {\n _id: string;\n author_type: 'user' | 'developer';\n author_name?: string;\n content: string;\n created_at: string;\n}\n\ninterface FeedbackButtonProps {\n /** Position of the floating button */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n /** Custom button label */\n label?: string;\n /** Button colour */\n color?: string;\n /** Hide the floating button (use exp.openFeedback() instead) */\n hidden?: boolean;\n /** API endpoint base URL */\n apiUrl?: string;\n /** Auth token for user endpoints */\n authToken?: string;\n}\n\n// ── Styles ─────────────────────────────────────────────────────────────────\n\nconst TYPE_META: Record<FeedbackType, { icon: string; label: string; color: string }> = {\n 'bug': { icon: '🐛', label: 'Bug Report', color: '#ef4444' },\n 'feature-request': { icon: '💡', label: 'Feature Request', color: '#8b5cf6' },\n 'comment': { icon: '💬', label: 'Comment', color: '#3b82f6' },\n 'praise': { icon: '🎉', label: 'Praise', color: '#10b981' },\n};\n\nconst STATUS_LABELS: Record<FeedbackStatus, string> = {\n 'new': '🆕 New',\n 'acknowledged': '👀 Acknowledged',\n 'in-progress': '🔧 In Progress',\n 'resolved': '✅ Resolved',\n 'wont-fix': '🚫 Won\\'t Fix',\n};\n\n// ── Component ──────────────────────────────────────────────────────────────\n\nexport function FeedbackButton({\n position = 'bottom-right',\n label = 'Feedback',\n color = '#6366f1',\n hidden = false,\n apiUrl,\n authToken,\n}: FeedbackButtonProps) {\n const experience = useContext(ExperienceContext);\n const [isOpen, setIsOpen] = useState(false);\n const [view, setView] = useState<'list' | 'new' | 'detail'>('list');\n const [selectedType, setSelectedType] = useState<FeedbackType>('comment');\n const [title, setTitle] = useState('');\n const [content, setContent] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [items, setItems] = useState<FeedbackItem[]>([]);\n const [selectedItem, setSelectedItem] = useState<FeedbackItem | null>(null);\n const [replies, setReplies] = useState<FeedbackReply[]>([]);\n const [replyText, setReplyText] = useState('');\n const [loading, setLoading] = useState(false);\n const [screenshot, setScreenshot] = useState<string | null>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n\n const baseUrl = apiUrl || (experience as any)?.config?.apiUrl || 'https://experience.shellapps.com';\n const appId = (experience as any)?.config?.appId || '';\n\n const headers = useCallback((): Record<string, string> => {\n const h: Record<string, string> = { 'Content-Type': 'application/json' };\n if (authToken) h['Authorization'] = `Bearer ${authToken}`;\n return h;\n }, [authToken]);\n\n // Expose openFeedback on the experience instance\n useEffect(() => {\n if (experience) {\n (experience as any).openFeedback = () => setIsOpen(true);\n }\n return () => {\n if (experience) delete (experience as any).openFeedback;\n };\n }, [experience]);\n\n // Load feedback list when opening\n useEffect(() => {\n if (isOpen && view === 'list') {\n loadFeedback();\n }\n }, [isOpen, view]);\n\n const loadFeedback = async () => {\n setLoading(true);\n try {\n const res = await fetch(\n `${baseUrl}/api/v1/feedback?appId=${appId}&limit=20`,\n { headers: headers() },\n );\n if (res.ok) {\n const data = await res.json();\n setItems(data.items || []);\n }\n } catch {\n // silently fail\n }\n setLoading(false);\n };\n\n const loadDetail = async (item: FeedbackItem) => {\n setSelectedItem(item);\n setView('detail');\n try {\n const res = await fetch(\n `${baseUrl}/api/v1/feedback/${item._id}`,\n { headers: headers() },\n );\n if (res.ok) {\n const data = await res.json();\n setReplies(data.replies || []);\n }\n } catch {\n // silently fail\n }\n };\n\n const captureScreenshot = async () => {\n try {\n const html2canvas = (window as any).html2canvas;\n if (!html2canvas) return;\n const canvas = await html2canvas(document.body, { scale: 0.5, logging: false });\n setScreenshot(canvas.toDataURL('image/jpeg', 0.6));\n } catch {\n // screenshot not available\n }\n };\n\n const submit = async () => {\n if (!title.trim() || !content.trim()) return;\n setSubmitting(true);\n try {\n const ctx = {\n userAgent: navigator.userAgent,\n url: window.location.href,\n viewport: { width: window.innerWidth, height: window.innerHeight },\n locale: navigator.language,\n referrer: document.referrer || undefined,\n };\n\n const res = await fetch(`${baseUrl}/api/v1/feedback`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({\n appId,\n type: selectedType,\n title: title.trim(),\n content: content.trim(),\n context: ctx,\n screenshot: screenshot || undefined,\n }),\n });\n\n if (res.ok) {\n setTitle('');\n setContent('');\n setScreenshot(null);\n setView('list');\n loadFeedback();\n }\n } catch {\n // silently fail\n }\n setSubmitting(false);\n };\n\n const submitReply = async () => {\n if (!replyText.trim() || !selectedItem) return;\n try {\n const res = await fetch(`${baseUrl}/api/v1/feedback/${selectedItem._id}/reply`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({ content: replyText.trim() }),\n });\n if (res.ok) {\n const reply = await res.json();\n setReplies((prev) => [...prev, reply]);\n setReplyText('');\n }\n } catch {\n // silently fail\n }\n };\n\n const vote = async (id: string) => {\n try {\n await fetch(`${baseUrl}/api/v1/feedback/${id}/vote`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({ type: 'upvote' }),\n });\n loadFeedback();\n } catch {\n // silently fail\n }\n };\n\n // ── Position styles ──────────────────────────────────────────────────────\n\n const posStyles: Record<string, React.CSSProperties> = {\n 'bottom-right': { bottom: 20, right: 20 },\n 'bottom-left': { bottom: 20, left: 20 },\n 'top-right': { top: 20, right: 20 },\n 'top-left': { top: 20, left: 20 },\n };\n\n const panelPos: Record<string, React.CSSProperties> = {\n 'bottom-right': { bottom: 70, right: 20 },\n 'bottom-left': { bottom: 70, left: 20 },\n 'top-right': { top: 70, right: 20 },\n 'top-left': { top: 70, left: 20 },\n };\n\n // ── Render ───────────────────────────────────────────────────────────────\n\n return (\n <>\n {/* Floating button */}\n {!hidden && (\n <button\n onClick={() => setIsOpen(!isOpen)}\n style={{\n position: 'fixed',\n ...posStyles[position],\n zIndex: 99999,\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 28,\n padding: '10px 20px',\n fontSize: 14,\n fontWeight: 600,\n cursor: 'pointer',\n boxShadow: '0 4px 12px rgba(0,0,0,0.15)',\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n }}\n >\n 💬 {label}\n </button>\n )}\n\n {/* Panel */}\n {isOpen && (\n <div\n ref={panelRef}\n style={{\n position: 'fixed',\n ...panelPos[position],\n zIndex: 100000,\n width: 380,\n maxHeight: 520,\n background: '#fff',\n borderRadius: 12,\n boxShadow: '0 8px 32px rgba(0,0,0,0.18)',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n fontSize: 14,\n color: '#1f2937',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: '14px 16px',\n background: color,\n color: '#fff',\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n }}\n >\n <span style={{ fontWeight: 600 }}>\n {view === 'new' ? 'New Feedback' : view === 'detail' ? 'Feedback' : 'Feedback'}\n </span>\n <div style={{ display: 'flex', gap: 8 }}>\n {view !== 'list' && (\n <button\n onClick={() => { setView('list'); setSelectedItem(null); }}\n style={{ background: 'none', border: 'none', color: '#fff', cursor: 'pointer', fontSize: 14 }}\n >\n ← Back\n </button>\n )}\n <button\n onClick={() => setIsOpen(false)}\n style={{ background: 'none', border: 'none', color: '#fff', cursor: 'pointer', fontSize: 18 }}\n >\n ✕\n </button>\n </div>\n </div>\n\n {/* Body */}\n <div style={{ flex: 1, overflow: 'auto', padding: 16 }}>\n {/* LIST VIEW */}\n {view === 'list' && (\n <>\n <button\n onClick={() => setView('new')}\n style={{\n width: '100%',\n padding: '10px',\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: 'pointer',\n fontWeight: 600,\n marginBottom: 12,\n }}\n >\n + New Feedback\n </button>\n {loading ? (\n <p style={{ textAlign: 'center', color: '#9ca3af' }}>Loading…</p>\n ) : items.length === 0 ? (\n <p style={{ textAlign: 'center', color: '#9ca3af' }}>No feedback yet</p>\n ) : (\n items.map((item) => (\n <div\n key={item._id}\n onClick={() => loadDetail(item)}\n style={{\n padding: 10,\n borderRadius: 8,\n border: '1px solid #e5e7eb',\n marginBottom: 8,\n cursor: 'pointer',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>\n <span>\n {TYPE_META[item.type]?.icon} <strong>{item.title}</strong>\n </span>\n {item.type === 'feature-request' && (\n <button\n onClick={(e) => { e.stopPropagation(); vote(item._id); }}\n style={{\n background: 'none',\n border: '1px solid #d1d5db',\n borderRadius: 4,\n padding: '2px 6px',\n cursor: 'pointer',\n fontSize: 12,\n }}\n >\n ▲ {item.vote_count}\n </button>\n )}\n </div>\n <div style={{ fontSize: 12, color: '#6b7280' }}>\n {STATUS_LABELS[item.status]} · {item.reply_count} replies · {new Date(item.created_at).toLocaleDateString()}\n </div>\n </div>\n ))\n )}\n </>\n )}\n\n {/* NEW FEEDBACK VIEW */}\n {view === 'new' && (\n <>\n {/* Type selector */}\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 12 }}>\n {(Object.entries(TYPE_META) as [FeedbackType, typeof TYPE_META['bug']][]).map(\n ([type, meta]) => (\n <button\n key={type}\n onClick={() => setSelectedType(type)}\n style={{\n padding: 8,\n borderRadius: 8,\n border: `2px solid ${selectedType === type ? meta.color : '#e5e7eb'}`,\n background: selectedType === type ? `${meta.color}10` : '#fff',\n cursor: 'pointer',\n fontSize: 13,\n textAlign: 'center',\n }}\n >\n {meta.icon} {meta.label}\n </button>\n ),\n )}\n </div>\n\n <input\n placeholder=\"Title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n style={{\n width: '100%',\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n marginBottom: 8,\n fontSize: 14,\n boxSizing: 'border-box',\n }}\n />\n\n <textarea\n placeholder=\"Describe your feedback…\"\n value={content}\n onChange={(e) => setContent(e.target.value)}\n rows={4}\n style={{\n width: '100%',\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n marginBottom: 8,\n fontSize: 14,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n\n {/* Screenshot button */}\n {(window as any).html2canvas && (\n <button\n onClick={captureScreenshot}\n style={{\n background: 'none',\n border: '1px solid #d1d5db',\n borderRadius: 6,\n padding: '6px 10px',\n cursor: 'pointer',\n fontSize: 12,\n marginBottom: 8,\n color: screenshot ? '#10b981' : '#6b7280',\n }}\n >\n 📷 {screenshot ? 'Screenshot captured ✓' : 'Capture screenshot'}\n </button>\n )}\n\n <button\n onClick={submit}\n disabled={submitting || !title.trim() || !content.trim()}\n style={{\n width: '100%',\n padding: 10,\n background: submitting ? '#9ca3af' : color,\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: submitting ? 'default' : 'pointer',\n fontWeight: 600,\n }}\n >\n {submitting ? 'Submitting…' : 'Submit'}\n </button>\n </>\n )}\n\n {/* DETAIL VIEW */}\n {view === 'detail' && selectedItem && (\n <>\n <div style={{ marginBottom: 12 }}>\n <div style={{ fontSize: 12, color: TYPE_META[selectedItem.type]?.color, fontWeight: 600, marginBottom: 4 }}>\n {TYPE_META[selectedItem.type]?.icon} {TYPE_META[selectedItem.type]?.label}\n </div>\n <h3 style={{ margin: '0 0 4px', fontSize: 16 }}>{selectedItem.title}</h3>\n <div style={{ fontSize: 12, color: '#6b7280', marginBottom: 8 }}>\n {STATUS_LABELS[selectedItem.status]} · {new Date(selectedItem.created_at).toLocaleDateString()}\n </div>\n <p style={{ margin: 0, lineHeight: 1.5 }}>{selectedItem.content}</p>\n </div>\n\n <hr style={{ border: 'none', borderTop: '1px solid #e5e7eb', margin: '12px 0' }} />\n\n {/* Replies */}\n <div style={{ marginBottom: 12 }}>\n <strong style={{ fontSize: 13 }}>Replies ({replies.length})</strong>\n {replies.map((r) => (\n <div\n key={r._id}\n style={{\n padding: 8,\n marginTop: 8,\n borderRadius: 6,\n background: r.author_type === 'developer' ? '#eff6ff' : '#f9fafb',\n borderLeft: `3px solid ${r.author_type === 'developer' ? '#3b82f6' : '#d1d5db'}`,\n }}\n >\n <div style={{ fontSize: 11, color: '#6b7280', marginBottom: 2 }}>\n {r.author_type === 'developer' ? '🛠️ Developer' : '👤 You'}{r.author_name ? ` · ${r.author_name}` : ''} · {new Date(r.created_at).toLocaleDateString()}\n </div>\n <div style={{ fontSize: 13 }}>{r.content}</div>\n </div>\n ))}\n </div>\n\n {/* Reply input */}\n <div style={{ display: 'flex', gap: 6 }}>\n <input\n placeholder=\"Write a reply…\"\n value={replyText}\n onChange={(e) => setReplyText(e.target.value)}\n onKeyDown={(e) => { if (e.key === 'Enter') submitReply(); }}\n style={{\n flex: 1,\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n fontSize: 13,\n }}\n />\n <button\n onClick={submitReply}\n disabled={!replyText.trim()}\n style={{\n padding: '8px 12px',\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 6,\n cursor: 'pointer',\n fontSize: 13,\n }}\n >\n Send\n </button>\n </div>\n </>\n )}\n </div>\n </div>\n )}\n </>\n );\n}\n","'use client';\nimport { useContext, useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport { ExperienceContext } from './context';\n\nexport function useExperience() {\n const ctx = useContext(ExperienceContext);\n if (!ctx) throw new Error('useExperience must be used within ExperienceProvider');\n return ctx;\n}\n\nexport function useTrack() {\n const experience = useExperience();\n return useMemo(() => ({\n track: (eventName: string, metadata?: Record<string, string>) => experience.track(eventName, metadata),\n trackPageView: () => experience.trackPageView(),\n }), [experience]);\n}\n\nexport function useFlag<T>(flagName: string, defaultValue: T): T {\n const experience = useExperience();\n return experience.getFlag(flagName, defaultValue);\n}\n\n// ─── Translation Types ──────────────────────────────────────────\n\ninterface TranslationResult {\n t: (key: string, params?: Record<string, string | number>) => string;\n locale: string;\n setLocale: (locale: string) => void;\n locales: Array<{ code: string; name: string; progress?: number }>;\n isLoading: boolean;\n}\n\ninterface TranslationCache {\n [locale: string]: Record<string, string>;\n}\n\n// Module-level cache shared across hook instances\nconst translationCache: TranslationCache = {};\nconst fetchPromises = new Map<string, Promise<Record<string, string>>>();\n\n/**\n * Translation hook for the Experience Platform.\n *\n * Fetches translations from the Experience API, caches in memory + localStorage,\n * and provides `t()` for interpolation and `setLocale()` for switching.\n *\n * Usage:\n * ```tsx\n * const { t, locale, setLocale, locales } = useTranslation();\n * return <h1>{t('greeting', { name: 'Alex' })}</h1>;\n * ```\n */\nexport function useTranslation(): TranslationResult {\n const experience = useExperience();\n const config = (experience as any).config || {};\n const appId: string = config.appId || '';\n const apiBaseUrl: string = config.apiUrl || config.baseUrl || 'https://experience-api.shellapps.com';\n\n const [locale, setLocaleState] = useState(() => {\n if (typeof window === 'undefined') return 'en';\n // Check localStorage for persisted locale preference\n const saved = localStorage.getItem(`exp_locale_${appId}`);\n if (saved) return saved;\n return navigator.language?.split('-')[0] || 'en';\n });\n\n const [translations, setTranslations] = useState<Record<string, string>>(() => {\n // Try memory cache first\n if (translationCache[locale]) return translationCache[locale]!;\n // Try localStorage\n if (typeof window !== 'undefined') {\n try {\n const cached = localStorage.getItem(`exp_translations_${appId}_${locale}`);\n if (cached) {\n const parsed = JSON.parse(cached);\n translationCache[locale] = parsed;\n return parsed;\n }\n } catch { /* ignore */ }\n }\n return {};\n });\n\n const [locales, setLocales] = useState<Array<{ code: string; name: string; progress?: number }>>([]);\n const [isLoading, setIsLoading] = useState(false);\n\n // Fetch translations for a locale\n const fetchTranslations = useCallback(async (loc: string): Promise<Record<string, string>> => {\n if (!appId) return {};\n\n // Deduplicate in-flight requests\n const cacheKey = `${appId}_${loc}`;\n const existing = fetchPromises.get(cacheKey);\n if (existing) return existing;\n\n const promise = (async () => {\n try {\n const res = await fetch(`${apiBaseUrl}/api/v1/translations/${appId}/${loc}`);\n if (!res.ok) return {};\n const data = await res.json();\n // Cache in memory and localStorage\n translationCache[loc] = data;\n if (typeof window !== 'undefined') {\n try {\n localStorage.setItem(`exp_translations_${appId}_${loc}`, JSON.stringify(data));\n } catch { /* quota exceeded, ignore */ }\n }\n return data as Record<string, string>;\n } catch {\n return {};\n } finally {\n fetchPromises.delete(cacheKey);\n }\n })();\n\n fetchPromises.set(cacheKey, promise);\n return promise;\n }, [appId, apiBaseUrl]);\n\n // Fetch available locales\n useEffect(() => {\n if (!appId) return;\n fetch(`${apiBaseUrl}/api/v1/translations/${appId}/locales`)\n .then(res => res.ok ? res.json() : { locales: [] })\n .then(data => setLocales(data.locales || []))\n .catch(() => {});\n }, [appId, apiBaseUrl]);\n\n // Fetch translations when locale changes\n useEffect(() => {\n if (!appId) return;\n\n // Use cached if available\n if (translationCache[locale]) {\n setTranslations(translationCache[locale]!);\n return;\n }\n\n setIsLoading(true);\n fetchTranslations(locale).then(data => {\n setTranslations(data);\n setIsLoading(false);\n });\n }, [locale, appId, fetchTranslations]);\n\n // t() function with interpolation and plural support\n const t = useCallback((key: string, params?: Record<string, string | number>): string => {\n let result = translations[key] ?? key;\n\n // Handle plurals: \"singular||plural\" with count param\n if (result.includes('||') && params && 'count' in params) {\n const parts = result.split('||');\n const count = Number(params.count);\n result = count === 1 ? (parts[0] ?? result) : (parts[1] ?? result);\n }\n\n // Handle interpolation: {{variable}}\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n result = result.replace(new RegExp(`\\{\\{${k}\\}\\}`, 'g'), String(v));\n }\n }\n\n return result;\n }, [translations]);\n\n // setLocale with persistence\n const setLocale = useCallback((newLocale: string) => {\n setLocaleState(newLocale);\n if (typeof window !== 'undefined') {\n localStorage.setItem(`exp_locale_${appId}`, newLocale);\n }\n }, [appId]);\n\n return { t, locale, setLocale, locales, isLoading };\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","import_react"]}
package/dist/index.mjs CHANGED
@@ -10,30 +10,54 @@ var ExperienceContext = createContext(null);
10
10
 
11
11
  // src/ExperienceProvider.tsx
12
12
  import { jsx } from "react/jsx-runtime";
13
+ function shouldEnableExperience(appId, apiKey, options) {
14
+ if (!appId || !apiKey) return false;
15
+ const endpoint = options?.endpoint;
16
+ if (!endpoint) return true;
17
+ const looksLocal = /localhost|127\.0\.0\.1/i.test(endpoint);
18
+ if (process.env.NODE_ENV === "production" && looksLocal) {
19
+ console.warn("[ExperienceSDK] Disabled: localhost endpoint configured in production.", { endpoint });
20
+ return false;
21
+ }
22
+ return true;
23
+ }
13
24
  function ExperienceProvider({ appId, apiKey, profileId, options, children }) {
14
25
  const instanceRef = useRef(null);
15
26
  const [, forceUpdate] = useState(0);
16
- if (typeof window !== "undefined" && !instanceRef.current) {
17
- const instance = Experience.init({ appId, apiKey, ...options });
18
- if (profileId) instance.identify(profileId);
19
- instanceRef.current = instance;
27
+ const isEnabled = shouldEnableExperience(appId, apiKey, options);
28
+ if (isEnabled && typeof window !== "undefined" && !instanceRef.current) {
29
+ try {
30
+ const instance = Experience.init({ appId, apiKey, ...options });
31
+ if (profileId) instance.identify(profileId);
32
+ instanceRef.current = instance;
33
+ } catch (error) {
34
+ console.error("[ExperienceSDK] Initialization failed. Running app without telemetry.", error);
35
+ instanceRef.current = null;
36
+ }
20
37
  }
21
38
  useEffect(() => {
22
- if (!instanceRef.current) {
39
+ if (!isEnabled || instanceRef.current) return;
40
+ try {
23
41
  const instance = Experience.init({ appId, apiKey, ...options });
24
42
  if (profileId) instance.identify(profileId);
25
43
  instanceRef.current = instance;
26
44
  forceUpdate((n) => n + 1);
45
+ } catch (error) {
46
+ console.error("[ExperienceSDK] Initialization failed in effect. Running app without telemetry.", error);
47
+ instanceRef.current = null;
27
48
  }
28
- }, []);
49
+ }, [isEnabled, appId, apiKey, options, profileId]);
29
50
  useEffect(() => {
30
51
  if (profileId && instanceRef.current) {
31
52
  instanceRef.current.identify(profileId);
32
53
  }
33
54
  }, [profileId]);
34
55
  useEffect(() => {
56
+ if (!isEnabled) return;
35
57
  const handler = (e) => {
36
- let el = e.target;
58
+ const initialTarget = e.target;
59
+ if (!(initialTarget instanceof Element)) return;
60
+ let el = initialTarget;
37
61
  while (el) {
38
62
  const tid = el.getAttribute?.("data-t");
39
63
  if (tid) {
@@ -45,7 +69,7 @@ function ExperienceProvider({ appId, apiKey, profileId, options, children }) {
45
69
  };
46
70
  document.addEventListener("click", handler, true);
47
71
  return () => document.removeEventListener("click", handler, true);
48
- }, []);
72
+ }, [isEnabled]);
49
73
  useEffect(() => {
50
74
  return () => {
51
75
  instanceRef.current?.shutdown();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ExperienceProvider.tsx","../src/context.ts","../src/ErrorBoundary.tsx","../src/FeedbackButton.tsx","../src/hooks.ts"],"sourcesContent":["'use client';\n\nimport React, { useEffect, useRef, useState } from 'react';\nimport { Experience } from '@shellapps/experience';\nimport type { ExperienceConfig } from '@shellapps/experience';\nimport { ExperienceContext } from './context';\n\nexport interface ExperienceProviderProps {\n appId: string;\n apiKey: string;\n profileId?: string;\n options?: Partial<Omit<ExperienceConfig, 'appId' | 'apiKey'>>;\n children: any;\n}\n\nexport function ExperienceProvider({ appId, apiKey, profileId, options, children }: ExperienceProviderProps) {\n const instanceRef = useRef<Experience | null>(null);\n const [, forceUpdate] = useState(0);\n\n // Only initialize on the client (browser) — skip during SSR/prerendering\n if (typeof window !== 'undefined' && !instanceRef.current) {\n const instance = Experience.init({ appId, apiKey, ...options });\n if (profileId) instance.identify(profileId);\n instanceRef.current = instance;\n }\n\n useEffect(() => {\n // Handle case where ref wasn't set during SSR render pass\n if (!instanceRef.current) {\n const instance = Experience.init({ appId, apiKey, ...options });\n if (profileId) instance.identify(profileId);\n instanceRef.current = instance;\n forceUpdate((n) => n + 1);\n }\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n if (profileId && instanceRef.current) {\n instanceRef.current.identify(profileId);\n }\n }, [profileId]);\n\n // data-t auto-tracking\n useEffect(() => {\n const handler = (e: MouseEvent) => {\n let el = e.target as HTMLElement | null;\n while (el) {\n const tid = el.getAttribute?.('data-t');\n if (tid) {\n instanceRef.current?.track('element_click', { elementTid: tid });\n break;\n }\n el = el.parentElement;\n }\n };\n document.addEventListener('click', handler, true);\n return () => document.removeEventListener('click', handler, true);\n }, []);\n\n useEffect(() => {\n return () => {\n instanceRef.current?.shutdown();\n };\n }, []);\n\n return (\n <ExperienceContext.Provider value={instanceRef.current}>\n {children}\n </ExperienceContext.Provider>\n );\n}\n","'use client';\nimport { createContext } from 'react';\nimport type { Experience } from '@shellapps/experience';\n\nexport const ExperienceContext = createContext<Experience | null>(null);\n","'use client';\nimport React from 'react';\nimport type { Experience } from '@shellapps/experience';\nimport { ExperienceContext } from './context';\n\ninterface ErrorBoundaryProps {\n fallback?: React.ReactNode;\n showCommentForm?: boolean;\n onError?: (error: Error, errorInfo: React.ErrorInfo) => void;\n children: any;\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n comment: string;\n submitted: boolean;\n}\n\nexport class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n static contextType = ExperienceContext;\n declare context: Experience | null;\n\n state: ErrorBoundaryState = {\n hasError: false,\n error: null,\n comment: '',\n submitted: false,\n };\n\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n this.context?.captureError(error, {\n extra: { componentStack: errorInfo.componentStack || '' },\n severity: 'fatal' as any,\n });\n this.props.onError?.(error, errorInfo);\n }\n\n private handleSubmitComment = () => {\n if (this.state.comment.trim() && this.state.error) {\n this.context?.captureMessage(\n `User feedback: ${this.state.comment}`,\n 'info',\n );\n this.setState({ submitted: true });\n }\n };\n\n render() {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n return (\n <div style={{ padding: 20, textAlign: 'center' }}>\n <h2>Something went wrong</h2>\n <p>{this.state.error?.message}</p>\n {this.props.showCommentForm && !this.state.submitted && (\n <div>\n <textarea\n placeholder=\"Tell us what happened...\"\n value={this.state.comment}\n onChange={(e) => this.setState({ comment: e.target.value })}\n style={{ width: '100%', minHeight: 80, marginTop: 10 }}\n />\n <button onClick={this.handleSubmitComment} style={{ marginTop: 8 }}>\n Submit\n </button>\n </div>\n )}\n {this.state.submitted && <p>Thank you for your feedback!</p>}\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n","'use client';\nimport React, { useState, useEffect, useCallback, useRef, useContext } from 'react';\nimport { ExperienceContext } from './context';\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\ntype FeedbackType = 'bug' | 'feature-request' | 'comment' | 'praise';\ntype FeedbackStatus = 'new' | 'acknowledged' | 'in-progress' | 'resolved' | 'wont-fix';\n\ninterface FeedbackItem {\n _id: string;\n type: FeedbackType;\n title: string;\n content: string;\n status: FeedbackStatus;\n tags: string[];\n vote_count: number;\n reply_count: number;\n created_at: string;\n}\n\ninterface FeedbackReply {\n _id: string;\n author_type: 'user' | 'developer';\n author_name?: string;\n content: string;\n created_at: string;\n}\n\ninterface FeedbackButtonProps {\n /** Position of the floating button */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n /** Custom button label */\n label?: string;\n /** Button colour */\n color?: string;\n /** Hide the floating button (use exp.openFeedback() instead) */\n hidden?: boolean;\n /** API endpoint base URL */\n apiUrl?: string;\n /** Auth token for user endpoints */\n authToken?: string;\n}\n\n// ── Styles ─────────────────────────────────────────────────────────────────\n\nconst TYPE_META: Record<FeedbackType, { icon: string; label: string; color: string }> = {\n 'bug': { icon: '🐛', label: 'Bug Report', color: '#ef4444' },\n 'feature-request': { icon: '💡', label: 'Feature Request', color: '#8b5cf6' },\n 'comment': { icon: '💬', label: 'Comment', color: '#3b82f6' },\n 'praise': { icon: '🎉', label: 'Praise', color: '#10b981' },\n};\n\nconst STATUS_LABELS: Record<FeedbackStatus, string> = {\n 'new': '🆕 New',\n 'acknowledged': '👀 Acknowledged',\n 'in-progress': '🔧 In Progress',\n 'resolved': '✅ Resolved',\n 'wont-fix': '🚫 Won\\'t Fix',\n};\n\n// ── Component ──────────────────────────────────────────────────────────────\n\nexport function FeedbackButton({\n position = 'bottom-right',\n label = 'Feedback',\n color = '#6366f1',\n hidden = false,\n apiUrl,\n authToken,\n}: FeedbackButtonProps) {\n const experience = useContext(ExperienceContext);\n const [isOpen, setIsOpen] = useState(false);\n const [view, setView] = useState<'list' | 'new' | 'detail'>('list');\n const [selectedType, setSelectedType] = useState<FeedbackType>('comment');\n const [title, setTitle] = useState('');\n const [content, setContent] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [items, setItems] = useState<FeedbackItem[]>([]);\n const [selectedItem, setSelectedItem] = useState<FeedbackItem | null>(null);\n const [replies, setReplies] = useState<FeedbackReply[]>([]);\n const [replyText, setReplyText] = useState('');\n const [loading, setLoading] = useState(false);\n const [screenshot, setScreenshot] = useState<string | null>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n\n const baseUrl = apiUrl || (experience as any)?.config?.apiUrl || 'https://experience.shellapps.com';\n const appId = (experience as any)?.config?.appId || '';\n\n const headers = useCallback((): Record<string, string> => {\n const h: Record<string, string> = { 'Content-Type': 'application/json' };\n if (authToken) h['Authorization'] = `Bearer ${authToken}`;\n return h;\n }, [authToken]);\n\n // Expose openFeedback on the experience instance\n useEffect(() => {\n if (experience) {\n (experience as any).openFeedback = () => setIsOpen(true);\n }\n return () => {\n if (experience) delete (experience as any).openFeedback;\n };\n }, [experience]);\n\n // Load feedback list when opening\n useEffect(() => {\n if (isOpen && view === 'list') {\n loadFeedback();\n }\n }, [isOpen, view]);\n\n const loadFeedback = async () => {\n setLoading(true);\n try {\n const res = await fetch(\n `${baseUrl}/api/v1/feedback?appId=${appId}&limit=20`,\n { headers: headers() },\n );\n if (res.ok) {\n const data = await res.json();\n setItems(data.items || []);\n }\n } catch {\n // silently fail\n }\n setLoading(false);\n };\n\n const loadDetail = async (item: FeedbackItem) => {\n setSelectedItem(item);\n setView('detail');\n try {\n const res = await fetch(\n `${baseUrl}/api/v1/feedback/${item._id}`,\n { headers: headers() },\n );\n if (res.ok) {\n const data = await res.json();\n setReplies(data.replies || []);\n }\n } catch {\n // silently fail\n }\n };\n\n const captureScreenshot = async () => {\n try {\n const html2canvas = (window as any).html2canvas;\n if (!html2canvas) return;\n const canvas = await html2canvas(document.body, { scale: 0.5, logging: false });\n setScreenshot(canvas.toDataURL('image/jpeg', 0.6));\n } catch {\n // screenshot not available\n }\n };\n\n const submit = async () => {\n if (!title.trim() || !content.trim()) return;\n setSubmitting(true);\n try {\n const ctx = {\n userAgent: navigator.userAgent,\n url: window.location.href,\n viewport: { width: window.innerWidth, height: window.innerHeight },\n locale: navigator.language,\n referrer: document.referrer || undefined,\n };\n\n const res = await fetch(`${baseUrl}/api/v1/feedback`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({\n appId,\n type: selectedType,\n title: title.trim(),\n content: content.trim(),\n context: ctx,\n screenshot: screenshot || undefined,\n }),\n });\n\n if (res.ok) {\n setTitle('');\n setContent('');\n setScreenshot(null);\n setView('list');\n loadFeedback();\n }\n } catch {\n // silently fail\n }\n setSubmitting(false);\n };\n\n const submitReply = async () => {\n if (!replyText.trim() || !selectedItem) return;\n try {\n const res = await fetch(`${baseUrl}/api/v1/feedback/${selectedItem._id}/reply`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({ content: replyText.trim() }),\n });\n if (res.ok) {\n const reply = await res.json();\n setReplies((prev) => [...prev, reply]);\n setReplyText('');\n }\n } catch {\n // silently fail\n }\n };\n\n const vote = async (id: string) => {\n try {\n await fetch(`${baseUrl}/api/v1/feedback/${id}/vote`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({ type: 'upvote' }),\n });\n loadFeedback();\n } catch {\n // silently fail\n }\n };\n\n // ── Position styles ──────────────────────────────────────────────────────\n\n const posStyles: Record<string, React.CSSProperties> = {\n 'bottom-right': { bottom: 20, right: 20 },\n 'bottom-left': { bottom: 20, left: 20 },\n 'top-right': { top: 20, right: 20 },\n 'top-left': { top: 20, left: 20 },\n };\n\n const panelPos: Record<string, React.CSSProperties> = {\n 'bottom-right': { bottom: 70, right: 20 },\n 'bottom-left': { bottom: 70, left: 20 },\n 'top-right': { top: 70, right: 20 },\n 'top-left': { top: 70, left: 20 },\n };\n\n // ── Render ───────────────────────────────────────────────────────────────\n\n return (\n <>\n {/* Floating button */}\n {!hidden && (\n <button\n onClick={() => setIsOpen(!isOpen)}\n style={{\n position: 'fixed',\n ...posStyles[position],\n zIndex: 99999,\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 28,\n padding: '10px 20px',\n fontSize: 14,\n fontWeight: 600,\n cursor: 'pointer',\n boxShadow: '0 4px 12px rgba(0,0,0,0.15)',\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n }}\n >\n 💬 {label}\n </button>\n )}\n\n {/* Panel */}\n {isOpen && (\n <div\n ref={panelRef}\n style={{\n position: 'fixed',\n ...panelPos[position],\n zIndex: 100000,\n width: 380,\n maxHeight: 520,\n background: '#fff',\n borderRadius: 12,\n boxShadow: '0 8px 32px rgba(0,0,0,0.18)',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n fontSize: 14,\n color: '#1f2937',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: '14px 16px',\n background: color,\n color: '#fff',\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n }}\n >\n <span style={{ fontWeight: 600 }}>\n {view === 'new' ? 'New Feedback' : view === 'detail' ? 'Feedback' : 'Feedback'}\n </span>\n <div style={{ display: 'flex', gap: 8 }}>\n {view !== 'list' && (\n <button\n onClick={() => { setView('list'); setSelectedItem(null); }}\n style={{ background: 'none', border: 'none', color: '#fff', cursor: 'pointer', fontSize: 14 }}\n >\n ← Back\n </button>\n )}\n <button\n onClick={() => setIsOpen(false)}\n style={{ background: 'none', border: 'none', color: '#fff', cursor: 'pointer', fontSize: 18 }}\n >\n ✕\n </button>\n </div>\n </div>\n\n {/* Body */}\n <div style={{ flex: 1, overflow: 'auto', padding: 16 }}>\n {/* LIST VIEW */}\n {view === 'list' && (\n <>\n <button\n onClick={() => setView('new')}\n style={{\n width: '100%',\n padding: '10px',\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: 'pointer',\n fontWeight: 600,\n marginBottom: 12,\n }}\n >\n + New Feedback\n </button>\n {loading ? (\n <p style={{ textAlign: 'center', color: '#9ca3af' }}>Loading…</p>\n ) : items.length === 0 ? (\n <p style={{ textAlign: 'center', color: '#9ca3af' }}>No feedback yet</p>\n ) : (\n items.map((item) => (\n <div\n key={item._id}\n onClick={() => loadDetail(item)}\n style={{\n padding: 10,\n borderRadius: 8,\n border: '1px solid #e5e7eb',\n marginBottom: 8,\n cursor: 'pointer',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>\n <span>\n {TYPE_META[item.type]?.icon} <strong>{item.title}</strong>\n </span>\n {item.type === 'feature-request' && (\n <button\n onClick={(e) => { e.stopPropagation(); vote(item._id); }}\n style={{\n background: 'none',\n border: '1px solid #d1d5db',\n borderRadius: 4,\n padding: '2px 6px',\n cursor: 'pointer',\n fontSize: 12,\n }}\n >\n ▲ {item.vote_count}\n </button>\n )}\n </div>\n <div style={{ fontSize: 12, color: '#6b7280' }}>\n {STATUS_LABELS[item.status]} · {item.reply_count} replies · {new Date(item.created_at).toLocaleDateString()}\n </div>\n </div>\n ))\n )}\n </>\n )}\n\n {/* NEW FEEDBACK VIEW */}\n {view === 'new' && (\n <>\n {/* Type selector */}\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 12 }}>\n {(Object.entries(TYPE_META) as [FeedbackType, typeof TYPE_META['bug']][]).map(\n ([type, meta]) => (\n <button\n key={type}\n onClick={() => setSelectedType(type)}\n style={{\n padding: 8,\n borderRadius: 8,\n border: `2px solid ${selectedType === type ? meta.color : '#e5e7eb'}`,\n background: selectedType === type ? `${meta.color}10` : '#fff',\n cursor: 'pointer',\n fontSize: 13,\n textAlign: 'center',\n }}\n >\n {meta.icon} {meta.label}\n </button>\n ),\n )}\n </div>\n\n <input\n placeholder=\"Title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n style={{\n width: '100%',\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n marginBottom: 8,\n fontSize: 14,\n boxSizing: 'border-box',\n }}\n />\n\n <textarea\n placeholder=\"Describe your feedback…\"\n value={content}\n onChange={(e) => setContent(e.target.value)}\n rows={4}\n style={{\n width: '100%',\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n marginBottom: 8,\n fontSize: 14,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n\n {/* Screenshot button */}\n {(window as any).html2canvas && (\n <button\n onClick={captureScreenshot}\n style={{\n background: 'none',\n border: '1px solid #d1d5db',\n borderRadius: 6,\n padding: '6px 10px',\n cursor: 'pointer',\n fontSize: 12,\n marginBottom: 8,\n color: screenshot ? '#10b981' : '#6b7280',\n }}\n >\n 📷 {screenshot ? 'Screenshot captured ✓' : 'Capture screenshot'}\n </button>\n )}\n\n <button\n onClick={submit}\n disabled={submitting || !title.trim() || !content.trim()}\n style={{\n width: '100%',\n padding: 10,\n background: submitting ? '#9ca3af' : color,\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: submitting ? 'default' : 'pointer',\n fontWeight: 600,\n }}\n >\n {submitting ? 'Submitting…' : 'Submit'}\n </button>\n </>\n )}\n\n {/* DETAIL VIEW */}\n {view === 'detail' && selectedItem && (\n <>\n <div style={{ marginBottom: 12 }}>\n <div style={{ fontSize: 12, color: TYPE_META[selectedItem.type]?.color, fontWeight: 600, marginBottom: 4 }}>\n {TYPE_META[selectedItem.type]?.icon} {TYPE_META[selectedItem.type]?.label}\n </div>\n <h3 style={{ margin: '0 0 4px', fontSize: 16 }}>{selectedItem.title}</h3>\n <div style={{ fontSize: 12, color: '#6b7280', marginBottom: 8 }}>\n {STATUS_LABELS[selectedItem.status]} · {new Date(selectedItem.created_at).toLocaleDateString()}\n </div>\n <p style={{ margin: 0, lineHeight: 1.5 }}>{selectedItem.content}</p>\n </div>\n\n <hr style={{ border: 'none', borderTop: '1px solid #e5e7eb', margin: '12px 0' }} />\n\n {/* Replies */}\n <div style={{ marginBottom: 12 }}>\n <strong style={{ fontSize: 13 }}>Replies ({replies.length})</strong>\n {replies.map((r) => (\n <div\n key={r._id}\n style={{\n padding: 8,\n marginTop: 8,\n borderRadius: 6,\n background: r.author_type === 'developer' ? '#eff6ff' : '#f9fafb',\n borderLeft: `3px solid ${r.author_type === 'developer' ? '#3b82f6' : '#d1d5db'}`,\n }}\n >\n <div style={{ fontSize: 11, color: '#6b7280', marginBottom: 2 }}>\n {r.author_type === 'developer' ? '🛠️ Developer' : '👤 You'}{r.author_name ? ` · ${r.author_name}` : ''} · {new Date(r.created_at).toLocaleDateString()}\n </div>\n <div style={{ fontSize: 13 }}>{r.content}</div>\n </div>\n ))}\n </div>\n\n {/* Reply input */}\n <div style={{ display: 'flex', gap: 6 }}>\n <input\n placeholder=\"Write a reply…\"\n value={replyText}\n onChange={(e) => setReplyText(e.target.value)}\n onKeyDown={(e) => { if (e.key === 'Enter') submitReply(); }}\n style={{\n flex: 1,\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n fontSize: 13,\n }}\n />\n <button\n onClick={submitReply}\n disabled={!replyText.trim()}\n style={{\n padding: '8px 12px',\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 6,\n cursor: 'pointer',\n fontSize: 13,\n }}\n >\n Send\n </button>\n </div>\n </>\n )}\n </div>\n </div>\n )}\n </>\n );\n}\n","'use client';\nimport { useContext, useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport { ExperienceContext } from './context';\n\nexport function useExperience() {\n const ctx = useContext(ExperienceContext);\n if (!ctx) throw new Error('useExperience must be used within ExperienceProvider');\n return ctx;\n}\n\nexport function useTrack() {\n const experience = useExperience();\n return useMemo(() => ({\n track: (eventName: string, metadata?: Record<string, string>) => experience.track(eventName, metadata),\n trackPageView: () => experience.trackPageView(),\n }), [experience]);\n}\n\nexport function useFlag<T>(flagName: string, defaultValue: T): T {\n const experience = useExperience();\n return experience.getFlag(flagName, defaultValue);\n}\n\n// ─── Translation Types ──────────────────────────────────────────\n\ninterface TranslationResult {\n t: (key: string, params?: Record<string, string | number>) => string;\n locale: string;\n setLocale: (locale: string) => void;\n locales: Array<{ code: string; name: string; progress?: number }>;\n isLoading: boolean;\n}\n\ninterface TranslationCache {\n [locale: string]: Record<string, string>;\n}\n\n// Module-level cache shared across hook instances\nconst translationCache: TranslationCache = {};\nconst fetchPromises = new Map<string, Promise<Record<string, string>>>();\n\n/**\n * Translation hook for the Experience Platform.\n *\n * Fetches translations from the Experience API, caches in memory + localStorage,\n * and provides `t()` for interpolation and `setLocale()` for switching.\n *\n * Usage:\n * ```tsx\n * const { t, locale, setLocale, locales } = useTranslation();\n * return <h1>{t('greeting', { name: 'Alex' })}</h1>;\n * ```\n */\nexport function useTranslation(): TranslationResult {\n const experience = useExperience();\n const config = (experience as any).config || {};\n const appId: string = config.appId || '';\n const apiBaseUrl: string = config.apiUrl || config.baseUrl || 'https://experience-api.shellapps.com';\n\n const [locale, setLocaleState] = useState(() => {\n if (typeof window === 'undefined') return 'en';\n // Check localStorage for persisted locale preference\n const saved = localStorage.getItem(`exp_locale_${appId}`);\n if (saved) return saved;\n return navigator.language?.split('-')[0] || 'en';\n });\n\n const [translations, setTranslations] = useState<Record<string, string>>(() => {\n // Try memory cache first\n if (translationCache[locale]) return translationCache[locale]!;\n // Try localStorage\n if (typeof window !== 'undefined') {\n try {\n const cached = localStorage.getItem(`exp_translations_${appId}_${locale}`);\n if (cached) {\n const parsed = JSON.parse(cached);\n translationCache[locale] = parsed;\n return parsed;\n }\n } catch { /* ignore */ }\n }\n return {};\n });\n\n const [locales, setLocales] = useState<Array<{ code: string; name: string; progress?: number }>>([]);\n const [isLoading, setIsLoading] = useState(false);\n\n // Fetch translations for a locale\n const fetchTranslations = useCallback(async (loc: string): Promise<Record<string, string>> => {\n if (!appId) return {};\n\n // Deduplicate in-flight requests\n const cacheKey = `${appId}_${loc}`;\n const existing = fetchPromises.get(cacheKey);\n if (existing) return existing;\n\n const promise = (async () => {\n try {\n const res = await fetch(`${apiBaseUrl}/api/v1/translations/${appId}/${loc}`);\n if (!res.ok) return {};\n const data = await res.json();\n // Cache in memory and localStorage\n translationCache[loc] = data;\n if (typeof window !== 'undefined') {\n try {\n localStorage.setItem(`exp_translations_${appId}_${loc}`, JSON.stringify(data));\n } catch { /* quota exceeded, ignore */ }\n }\n return data as Record<string, string>;\n } catch {\n return {};\n } finally {\n fetchPromises.delete(cacheKey);\n }\n })();\n\n fetchPromises.set(cacheKey, promise);\n return promise;\n }, [appId, apiBaseUrl]);\n\n // Fetch available locales\n useEffect(() => {\n if (!appId) return;\n fetch(`${apiBaseUrl}/api/v1/translations/${appId}/locales`)\n .then(res => res.ok ? res.json() : { locales: [] })\n .then(data => setLocales(data.locales || []))\n .catch(() => {});\n }, [appId, apiBaseUrl]);\n\n // Fetch translations when locale changes\n useEffect(() => {\n if (!appId) return;\n\n // Use cached if available\n if (translationCache[locale]) {\n setTranslations(translationCache[locale]!);\n return;\n }\n\n setIsLoading(true);\n fetchTranslations(locale).then(data => {\n setTranslations(data);\n setIsLoading(false);\n });\n }, [locale, appId, fetchTranslations]);\n\n // t() function with interpolation and plural support\n const t = useCallback((key: string, params?: Record<string, string | number>): string => {\n let result = translations[key] ?? key;\n\n // Handle plurals: \"singular||plural\" with count param\n if (result.includes('||') && params && 'count' in params) {\n const parts = result.split('||');\n const count = Number(params.count);\n result = count === 1 ? (parts[0] ?? result) : (parts[1] ?? result);\n }\n\n // Handle interpolation: {{variable}}\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n result = result.replace(new RegExp(`\\{\\{${k}\\}\\}`, 'g'), String(v));\n }\n }\n\n return result;\n }, [translations]);\n\n // setLocale with persistence\n const setLocale = useCallback((newLocale: string) => {\n setLocaleState(newLocale);\n if (typeof window !== 'undefined') {\n localStorage.setItem(`exp_locale_${appId}`, newLocale);\n }\n }, [appId]);\n\n return { t, locale, setLocale, locales, isLoading };\n}\n"],"mappings":"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","names":["React","jsx","React","useState","useEffect","useRef","jsx","jsxs","useState","useRef","useEffect","useContext","useState","useCallback","useEffect","useContext","useState","useCallback","useEffect"]}
1
+ {"version":3,"sources":["../src/ExperienceProvider.tsx","../src/context.ts","../src/ErrorBoundary.tsx","../src/FeedbackButton.tsx","../src/hooks.ts"],"sourcesContent":["'use client';\n\nimport React, { useEffect, useRef, useState } from 'react';\nimport { Experience } from '@shellapps/experience';\nimport type { ExperienceConfig } from '@shellapps/experience';\nimport { ExperienceContext } from './context';\n\nexport interface ExperienceProviderProps {\n appId: string;\n apiKey: string;\n profileId?: string;\n options?: Partial<Omit<ExperienceConfig, 'appId' | 'apiKey'>>;\n children: any;\n}\n\nfunction shouldEnableExperience(appId: string, apiKey: string, options?: Partial<Omit<ExperienceConfig, 'appId' | 'apiKey'>>): boolean {\n if (!appId || !apiKey) return false;\n\n const endpoint = options?.endpoint;\n if (!endpoint) return true;\n\n const looksLocal = /localhost|127\\.0\\.0\\.1/i.test(endpoint);\n if (process.env.NODE_ENV === 'production' && looksLocal) {\n console.warn('[ExperienceSDK] Disabled: localhost endpoint configured in production.', { endpoint });\n return false;\n }\n\n return true;\n}\n\nexport function ExperienceProvider({ appId, apiKey, profileId, options, children }: ExperienceProviderProps) {\n const instanceRef = useRef<Experience | null>(null);\n const [, forceUpdate] = useState(0);\n const isEnabled = shouldEnableExperience(appId, apiKey, options);\n\n // Only initialize on the client (browser) — skip during SSR/prerendering\n if (isEnabled && typeof window !== 'undefined' && !instanceRef.current) {\n try {\n const instance = Experience.init({ appId, apiKey, ...options });\n if (profileId) instance.identify(profileId);\n instanceRef.current = instance;\n } catch (error) {\n console.error('[ExperienceSDK] Initialization failed. Running app without telemetry.', error);\n instanceRef.current = null;\n }\n }\n\n useEffect(() => {\n if (!isEnabled || instanceRef.current) return;\n\n try {\n const instance = Experience.init({ appId, apiKey, ...options });\n if (profileId) instance.identify(profileId);\n instanceRef.current = instance;\n forceUpdate((n) => n + 1);\n } catch (error) {\n console.error('[ExperienceSDK] Initialization failed in effect. Running app without telemetry.', error);\n instanceRef.current = null;\n }\n }, [isEnabled, appId, apiKey, options, profileId]);\n\n useEffect(() => {\n if (profileId && instanceRef.current) {\n instanceRef.current.identify(profileId);\n }\n }, [profileId]);\n\n // data-t auto-tracking\n useEffect(() => {\n if (!isEnabled) return;\n\n const handler = (e: MouseEvent) => {\n const initialTarget = e.target;\n if (!(initialTarget instanceof Element)) return;\n\n let el: Element | null = initialTarget;\n while (el) {\n const tid = el.getAttribute?.('data-t');\n if (tid) {\n instanceRef.current?.track('element_click', { elementTid: tid });\n break;\n }\n el = el.parentElement;\n }\n };\n\n document.addEventListener('click', handler, true);\n return () => document.removeEventListener('click', handler, true);\n }, [isEnabled]);\n\n useEffect(() => {\n return () => {\n instanceRef.current?.shutdown();\n };\n }, []);\n\n return (\n <ExperienceContext.Provider value={instanceRef.current}>\n {children}\n </ExperienceContext.Provider>\n );\n}\n","'use client';\nimport { createContext } from 'react';\nimport type { Experience } from '@shellapps/experience';\n\nexport const ExperienceContext = createContext<Experience | null>(null);\n","'use client';\nimport React from 'react';\nimport type { Experience } from '@shellapps/experience';\nimport { ExperienceContext } from './context';\n\ninterface ErrorBoundaryProps {\n fallback?: React.ReactNode;\n showCommentForm?: boolean;\n onError?: (error: Error, errorInfo: React.ErrorInfo) => void;\n children: any;\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n comment: string;\n submitted: boolean;\n}\n\nexport class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n static contextType = ExperienceContext;\n declare context: Experience | null;\n\n state: ErrorBoundaryState = {\n hasError: false,\n error: null,\n comment: '',\n submitted: false,\n };\n\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n this.context?.captureError(error, {\n extra: { componentStack: errorInfo.componentStack || '' },\n severity: 'fatal' as any,\n });\n this.props.onError?.(error, errorInfo);\n }\n\n private handleSubmitComment = () => {\n if (this.state.comment.trim() && this.state.error) {\n this.context?.captureMessage(\n `User feedback: ${this.state.comment}`,\n 'info',\n );\n this.setState({ submitted: true });\n }\n };\n\n render() {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n return (\n <div style={{ padding: 20, textAlign: 'center' }}>\n <h2>Something went wrong</h2>\n <p>{this.state.error?.message}</p>\n {this.props.showCommentForm && !this.state.submitted && (\n <div>\n <textarea\n placeholder=\"Tell us what happened...\"\n value={this.state.comment}\n onChange={(e) => this.setState({ comment: e.target.value })}\n style={{ width: '100%', minHeight: 80, marginTop: 10 }}\n />\n <button onClick={this.handleSubmitComment} style={{ marginTop: 8 }}>\n Submit\n </button>\n </div>\n )}\n {this.state.submitted && <p>Thank you for your feedback!</p>}\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n","'use client';\nimport React, { useState, useEffect, useCallback, useRef, useContext } from 'react';\nimport { ExperienceContext } from './context';\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\ntype FeedbackType = 'bug' | 'feature-request' | 'comment' | 'praise';\ntype FeedbackStatus = 'new' | 'acknowledged' | 'in-progress' | 'resolved' | 'wont-fix';\n\ninterface FeedbackItem {\n _id: string;\n type: FeedbackType;\n title: string;\n content: string;\n status: FeedbackStatus;\n tags: string[];\n vote_count: number;\n reply_count: number;\n created_at: string;\n}\n\ninterface FeedbackReply {\n _id: string;\n author_type: 'user' | 'developer';\n author_name?: string;\n content: string;\n created_at: string;\n}\n\ninterface FeedbackButtonProps {\n /** Position of the floating button */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n /** Custom button label */\n label?: string;\n /** Button colour */\n color?: string;\n /** Hide the floating button (use exp.openFeedback() instead) */\n hidden?: boolean;\n /** API endpoint base URL */\n apiUrl?: string;\n /** Auth token for user endpoints */\n authToken?: string;\n}\n\n// ── Styles ─────────────────────────────────────────────────────────────────\n\nconst TYPE_META: Record<FeedbackType, { icon: string; label: string; color: string }> = {\n 'bug': { icon: '🐛', label: 'Bug Report', color: '#ef4444' },\n 'feature-request': { icon: '💡', label: 'Feature Request', color: '#8b5cf6' },\n 'comment': { icon: '💬', label: 'Comment', color: '#3b82f6' },\n 'praise': { icon: '🎉', label: 'Praise', color: '#10b981' },\n};\n\nconst STATUS_LABELS: Record<FeedbackStatus, string> = {\n 'new': '🆕 New',\n 'acknowledged': '👀 Acknowledged',\n 'in-progress': '🔧 In Progress',\n 'resolved': '✅ Resolved',\n 'wont-fix': '🚫 Won\\'t Fix',\n};\n\n// ── Component ──────────────────────────────────────────────────────────────\n\nexport function FeedbackButton({\n position = 'bottom-right',\n label = 'Feedback',\n color = '#6366f1',\n hidden = false,\n apiUrl,\n authToken,\n}: FeedbackButtonProps) {\n const experience = useContext(ExperienceContext);\n const [isOpen, setIsOpen] = useState(false);\n const [view, setView] = useState<'list' | 'new' | 'detail'>('list');\n const [selectedType, setSelectedType] = useState<FeedbackType>('comment');\n const [title, setTitle] = useState('');\n const [content, setContent] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [items, setItems] = useState<FeedbackItem[]>([]);\n const [selectedItem, setSelectedItem] = useState<FeedbackItem | null>(null);\n const [replies, setReplies] = useState<FeedbackReply[]>([]);\n const [replyText, setReplyText] = useState('');\n const [loading, setLoading] = useState(false);\n const [screenshot, setScreenshot] = useState<string | null>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n\n const baseUrl = apiUrl || (experience as any)?.config?.apiUrl || 'https://experience.shellapps.com';\n const appId = (experience as any)?.config?.appId || '';\n\n const headers = useCallback((): Record<string, string> => {\n const h: Record<string, string> = { 'Content-Type': 'application/json' };\n if (authToken) h['Authorization'] = `Bearer ${authToken}`;\n return h;\n }, [authToken]);\n\n // Expose openFeedback on the experience instance\n useEffect(() => {\n if (experience) {\n (experience as any).openFeedback = () => setIsOpen(true);\n }\n return () => {\n if (experience) delete (experience as any).openFeedback;\n };\n }, [experience]);\n\n // Load feedback list when opening\n useEffect(() => {\n if (isOpen && view === 'list') {\n loadFeedback();\n }\n }, [isOpen, view]);\n\n const loadFeedback = async () => {\n setLoading(true);\n try {\n const res = await fetch(\n `${baseUrl}/api/v1/feedback?appId=${appId}&limit=20`,\n { headers: headers() },\n );\n if (res.ok) {\n const data = await res.json();\n setItems(data.items || []);\n }\n } catch {\n // silently fail\n }\n setLoading(false);\n };\n\n const loadDetail = async (item: FeedbackItem) => {\n setSelectedItem(item);\n setView('detail');\n try {\n const res = await fetch(\n `${baseUrl}/api/v1/feedback/${item._id}`,\n { headers: headers() },\n );\n if (res.ok) {\n const data = await res.json();\n setReplies(data.replies || []);\n }\n } catch {\n // silently fail\n }\n };\n\n const captureScreenshot = async () => {\n try {\n const html2canvas = (window as any).html2canvas;\n if (!html2canvas) return;\n const canvas = await html2canvas(document.body, { scale: 0.5, logging: false });\n setScreenshot(canvas.toDataURL('image/jpeg', 0.6));\n } catch {\n // screenshot not available\n }\n };\n\n const submit = async () => {\n if (!title.trim() || !content.trim()) return;\n setSubmitting(true);\n try {\n const ctx = {\n userAgent: navigator.userAgent,\n url: window.location.href,\n viewport: { width: window.innerWidth, height: window.innerHeight },\n locale: navigator.language,\n referrer: document.referrer || undefined,\n };\n\n const res = await fetch(`${baseUrl}/api/v1/feedback`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({\n appId,\n type: selectedType,\n title: title.trim(),\n content: content.trim(),\n context: ctx,\n screenshot: screenshot || undefined,\n }),\n });\n\n if (res.ok) {\n setTitle('');\n setContent('');\n setScreenshot(null);\n setView('list');\n loadFeedback();\n }\n } catch {\n // silently fail\n }\n setSubmitting(false);\n };\n\n const submitReply = async () => {\n if (!replyText.trim() || !selectedItem) return;\n try {\n const res = await fetch(`${baseUrl}/api/v1/feedback/${selectedItem._id}/reply`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({ content: replyText.trim() }),\n });\n if (res.ok) {\n const reply = await res.json();\n setReplies((prev) => [...prev, reply]);\n setReplyText('');\n }\n } catch {\n // silently fail\n }\n };\n\n const vote = async (id: string) => {\n try {\n await fetch(`${baseUrl}/api/v1/feedback/${id}/vote`, {\n method: 'POST',\n headers: headers(),\n body: JSON.stringify({ type: 'upvote' }),\n });\n loadFeedback();\n } catch {\n // silently fail\n }\n };\n\n // ── Position styles ──────────────────────────────────────────────────────\n\n const posStyles: Record<string, React.CSSProperties> = {\n 'bottom-right': { bottom: 20, right: 20 },\n 'bottom-left': { bottom: 20, left: 20 },\n 'top-right': { top: 20, right: 20 },\n 'top-left': { top: 20, left: 20 },\n };\n\n const panelPos: Record<string, React.CSSProperties> = {\n 'bottom-right': { bottom: 70, right: 20 },\n 'bottom-left': { bottom: 70, left: 20 },\n 'top-right': { top: 70, right: 20 },\n 'top-left': { top: 70, left: 20 },\n };\n\n // ── Render ───────────────────────────────────────────────────────────────\n\n return (\n <>\n {/* Floating button */}\n {!hidden && (\n <button\n onClick={() => setIsOpen(!isOpen)}\n style={{\n position: 'fixed',\n ...posStyles[position],\n zIndex: 99999,\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 28,\n padding: '10px 20px',\n fontSize: 14,\n fontWeight: 600,\n cursor: 'pointer',\n boxShadow: '0 4px 12px rgba(0,0,0,0.15)',\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n }}\n >\n 💬 {label}\n </button>\n )}\n\n {/* Panel */}\n {isOpen && (\n <div\n ref={panelRef}\n style={{\n position: 'fixed',\n ...panelPos[position],\n zIndex: 100000,\n width: 380,\n maxHeight: 520,\n background: '#fff',\n borderRadius: 12,\n boxShadow: '0 8px 32px rgba(0,0,0,0.18)',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n fontSize: 14,\n color: '#1f2937',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: '14px 16px',\n background: color,\n color: '#fff',\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n }}\n >\n <span style={{ fontWeight: 600 }}>\n {view === 'new' ? 'New Feedback' : view === 'detail' ? 'Feedback' : 'Feedback'}\n </span>\n <div style={{ display: 'flex', gap: 8 }}>\n {view !== 'list' && (\n <button\n onClick={() => { setView('list'); setSelectedItem(null); }}\n style={{ background: 'none', border: 'none', color: '#fff', cursor: 'pointer', fontSize: 14 }}\n >\n ← Back\n </button>\n )}\n <button\n onClick={() => setIsOpen(false)}\n style={{ background: 'none', border: 'none', color: '#fff', cursor: 'pointer', fontSize: 18 }}\n >\n ✕\n </button>\n </div>\n </div>\n\n {/* Body */}\n <div style={{ flex: 1, overflow: 'auto', padding: 16 }}>\n {/* LIST VIEW */}\n {view === 'list' && (\n <>\n <button\n onClick={() => setView('new')}\n style={{\n width: '100%',\n padding: '10px',\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: 'pointer',\n fontWeight: 600,\n marginBottom: 12,\n }}\n >\n + New Feedback\n </button>\n {loading ? (\n <p style={{ textAlign: 'center', color: '#9ca3af' }}>Loading…</p>\n ) : items.length === 0 ? (\n <p style={{ textAlign: 'center', color: '#9ca3af' }}>No feedback yet</p>\n ) : (\n items.map((item) => (\n <div\n key={item._id}\n onClick={() => loadDetail(item)}\n style={{\n padding: 10,\n borderRadius: 8,\n border: '1px solid #e5e7eb',\n marginBottom: 8,\n cursor: 'pointer',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>\n <span>\n {TYPE_META[item.type]?.icon} <strong>{item.title}</strong>\n </span>\n {item.type === 'feature-request' && (\n <button\n onClick={(e) => { e.stopPropagation(); vote(item._id); }}\n style={{\n background: 'none',\n border: '1px solid #d1d5db',\n borderRadius: 4,\n padding: '2px 6px',\n cursor: 'pointer',\n fontSize: 12,\n }}\n >\n ▲ {item.vote_count}\n </button>\n )}\n </div>\n <div style={{ fontSize: 12, color: '#6b7280' }}>\n {STATUS_LABELS[item.status]} · {item.reply_count} replies · {new Date(item.created_at).toLocaleDateString()}\n </div>\n </div>\n ))\n )}\n </>\n )}\n\n {/* NEW FEEDBACK VIEW */}\n {view === 'new' && (\n <>\n {/* Type selector */}\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 12 }}>\n {(Object.entries(TYPE_META) as [FeedbackType, typeof TYPE_META['bug']][]).map(\n ([type, meta]) => (\n <button\n key={type}\n onClick={() => setSelectedType(type)}\n style={{\n padding: 8,\n borderRadius: 8,\n border: `2px solid ${selectedType === type ? meta.color : '#e5e7eb'}`,\n background: selectedType === type ? `${meta.color}10` : '#fff',\n cursor: 'pointer',\n fontSize: 13,\n textAlign: 'center',\n }}\n >\n {meta.icon} {meta.label}\n </button>\n ),\n )}\n </div>\n\n <input\n placeholder=\"Title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n style={{\n width: '100%',\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n marginBottom: 8,\n fontSize: 14,\n boxSizing: 'border-box',\n }}\n />\n\n <textarea\n placeholder=\"Describe your feedback…\"\n value={content}\n onChange={(e) => setContent(e.target.value)}\n rows={4}\n style={{\n width: '100%',\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n marginBottom: 8,\n fontSize: 14,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n\n {/* Screenshot button */}\n {(window as any).html2canvas && (\n <button\n onClick={captureScreenshot}\n style={{\n background: 'none',\n border: '1px solid #d1d5db',\n borderRadius: 6,\n padding: '6px 10px',\n cursor: 'pointer',\n fontSize: 12,\n marginBottom: 8,\n color: screenshot ? '#10b981' : '#6b7280',\n }}\n >\n 📷 {screenshot ? 'Screenshot captured ✓' : 'Capture screenshot'}\n </button>\n )}\n\n <button\n onClick={submit}\n disabled={submitting || !title.trim() || !content.trim()}\n style={{\n width: '100%',\n padding: 10,\n background: submitting ? '#9ca3af' : color,\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: submitting ? 'default' : 'pointer',\n fontWeight: 600,\n }}\n >\n {submitting ? 'Submitting…' : 'Submit'}\n </button>\n </>\n )}\n\n {/* DETAIL VIEW */}\n {view === 'detail' && selectedItem && (\n <>\n <div style={{ marginBottom: 12 }}>\n <div style={{ fontSize: 12, color: TYPE_META[selectedItem.type]?.color, fontWeight: 600, marginBottom: 4 }}>\n {TYPE_META[selectedItem.type]?.icon} {TYPE_META[selectedItem.type]?.label}\n </div>\n <h3 style={{ margin: '0 0 4px', fontSize: 16 }}>{selectedItem.title}</h3>\n <div style={{ fontSize: 12, color: '#6b7280', marginBottom: 8 }}>\n {STATUS_LABELS[selectedItem.status]} · {new Date(selectedItem.created_at).toLocaleDateString()}\n </div>\n <p style={{ margin: 0, lineHeight: 1.5 }}>{selectedItem.content}</p>\n </div>\n\n <hr style={{ border: 'none', borderTop: '1px solid #e5e7eb', margin: '12px 0' }} />\n\n {/* Replies */}\n <div style={{ marginBottom: 12 }}>\n <strong style={{ fontSize: 13 }}>Replies ({replies.length})</strong>\n {replies.map((r) => (\n <div\n key={r._id}\n style={{\n padding: 8,\n marginTop: 8,\n borderRadius: 6,\n background: r.author_type === 'developer' ? '#eff6ff' : '#f9fafb',\n borderLeft: `3px solid ${r.author_type === 'developer' ? '#3b82f6' : '#d1d5db'}`,\n }}\n >\n <div style={{ fontSize: 11, color: '#6b7280', marginBottom: 2 }}>\n {r.author_type === 'developer' ? '🛠️ Developer' : '👤 You'}{r.author_name ? ` · ${r.author_name}` : ''} · {new Date(r.created_at).toLocaleDateString()}\n </div>\n <div style={{ fontSize: 13 }}>{r.content}</div>\n </div>\n ))}\n </div>\n\n {/* Reply input */}\n <div style={{ display: 'flex', gap: 6 }}>\n <input\n placeholder=\"Write a reply…\"\n value={replyText}\n onChange={(e) => setReplyText(e.target.value)}\n onKeyDown={(e) => { if (e.key === 'Enter') submitReply(); }}\n style={{\n flex: 1,\n padding: 8,\n borderRadius: 6,\n border: '1px solid #d1d5db',\n fontSize: 13,\n }}\n />\n <button\n onClick={submitReply}\n disabled={!replyText.trim()}\n style={{\n padding: '8px 12px',\n background: color,\n color: '#fff',\n border: 'none',\n borderRadius: 6,\n cursor: 'pointer',\n fontSize: 13,\n }}\n >\n Send\n </button>\n </div>\n </>\n )}\n </div>\n </div>\n )}\n </>\n );\n}\n","'use client';\nimport { useContext, useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport { ExperienceContext } from './context';\n\nexport function useExperience() {\n const ctx = useContext(ExperienceContext);\n if (!ctx) throw new Error('useExperience must be used within ExperienceProvider');\n return ctx;\n}\n\nexport function useTrack() {\n const experience = useExperience();\n return useMemo(() => ({\n track: (eventName: string, metadata?: Record<string, string>) => experience.track(eventName, metadata),\n trackPageView: () => experience.trackPageView(),\n }), [experience]);\n}\n\nexport function useFlag<T>(flagName: string, defaultValue: T): T {\n const experience = useExperience();\n return experience.getFlag(flagName, defaultValue);\n}\n\n// ─── Translation Types ──────────────────────────────────────────\n\ninterface TranslationResult {\n t: (key: string, params?: Record<string, string | number>) => string;\n locale: string;\n setLocale: (locale: string) => void;\n locales: Array<{ code: string; name: string; progress?: number }>;\n isLoading: boolean;\n}\n\ninterface TranslationCache {\n [locale: string]: Record<string, string>;\n}\n\n// Module-level cache shared across hook instances\nconst translationCache: TranslationCache = {};\nconst fetchPromises = new Map<string, Promise<Record<string, string>>>();\n\n/**\n * Translation hook for the Experience Platform.\n *\n * Fetches translations from the Experience API, caches in memory + localStorage,\n * and provides `t()` for interpolation and `setLocale()` for switching.\n *\n * Usage:\n * ```tsx\n * const { t, locale, setLocale, locales } = useTranslation();\n * return <h1>{t('greeting', { name: 'Alex' })}</h1>;\n * ```\n */\nexport function useTranslation(): TranslationResult {\n const experience = useExperience();\n const config = (experience as any).config || {};\n const appId: string = config.appId || '';\n const apiBaseUrl: string = config.apiUrl || config.baseUrl || 'https://experience-api.shellapps.com';\n\n const [locale, setLocaleState] = useState(() => {\n if (typeof window === 'undefined') return 'en';\n // Check localStorage for persisted locale preference\n const saved = localStorage.getItem(`exp_locale_${appId}`);\n if (saved) return saved;\n return navigator.language?.split('-')[0] || 'en';\n });\n\n const [translations, setTranslations] = useState<Record<string, string>>(() => {\n // Try memory cache first\n if (translationCache[locale]) return translationCache[locale]!;\n // Try localStorage\n if (typeof window !== 'undefined') {\n try {\n const cached = localStorage.getItem(`exp_translations_${appId}_${locale}`);\n if (cached) {\n const parsed = JSON.parse(cached);\n translationCache[locale] = parsed;\n return parsed;\n }\n } catch { /* ignore */ }\n }\n return {};\n });\n\n const [locales, setLocales] = useState<Array<{ code: string; name: string; progress?: number }>>([]);\n const [isLoading, setIsLoading] = useState(false);\n\n // Fetch translations for a locale\n const fetchTranslations = useCallback(async (loc: string): Promise<Record<string, string>> => {\n if (!appId) return {};\n\n // Deduplicate in-flight requests\n const cacheKey = `${appId}_${loc}`;\n const existing = fetchPromises.get(cacheKey);\n if (existing) return existing;\n\n const promise = (async () => {\n try {\n const res = await fetch(`${apiBaseUrl}/api/v1/translations/${appId}/${loc}`);\n if (!res.ok) return {};\n const data = await res.json();\n // Cache in memory and localStorage\n translationCache[loc] = data;\n if (typeof window !== 'undefined') {\n try {\n localStorage.setItem(`exp_translations_${appId}_${loc}`, JSON.stringify(data));\n } catch { /* quota exceeded, ignore */ }\n }\n return data as Record<string, string>;\n } catch {\n return {};\n } finally {\n fetchPromises.delete(cacheKey);\n }\n })();\n\n fetchPromises.set(cacheKey, promise);\n return promise;\n }, [appId, apiBaseUrl]);\n\n // Fetch available locales\n useEffect(() => {\n if (!appId) return;\n fetch(`${apiBaseUrl}/api/v1/translations/${appId}/locales`)\n .then(res => res.ok ? res.json() : { locales: [] })\n .then(data => setLocales(data.locales || []))\n .catch(() => {});\n }, [appId, apiBaseUrl]);\n\n // Fetch translations when locale changes\n useEffect(() => {\n if (!appId) return;\n\n // Use cached if available\n if (translationCache[locale]) {\n setTranslations(translationCache[locale]!);\n return;\n }\n\n setIsLoading(true);\n fetchTranslations(locale).then(data => {\n setTranslations(data);\n setIsLoading(false);\n });\n }, [locale, appId, fetchTranslations]);\n\n // t() function with interpolation and plural support\n const t = useCallback((key: string, params?: Record<string, string | number>): string => {\n let result = translations[key] ?? key;\n\n // Handle plurals: \"singular||plural\" with count param\n if (result.includes('||') && params && 'count' in params) {\n const parts = result.split('||');\n const count = Number(params.count);\n result = count === 1 ? (parts[0] ?? result) : (parts[1] ?? result);\n }\n\n // Handle interpolation: {{variable}}\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n result = result.replace(new RegExp(`\\{\\{${k}\\}\\}`, 'g'), String(v));\n }\n }\n\n return result;\n }, [translations]);\n\n // setLocale with persistence\n const setLocale = useCallback((newLocale: string) => {\n setLocaleState(newLocale);\n if (typeof window !== 'undefined') {\n localStorage.setItem(`exp_locale_${appId}`, newLocale);\n }\n }, [appId]);\n\n return { t, locale, setLocale, locales, isLoading };\n}\n"],"mappings":"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","names":["React","jsx","React","useState","useEffect","useRef","jsx","jsxs","useState","useRef","useEffect","useContext","useState","useCallback","useEffect","useContext","useState","useCallback","useEffect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shellapps/experience-react",
3
- "version": "1.10.1",
3
+ "version": "1.10.3",
4
4
  "description": "React SDK for @shellapps/experience",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -43,5 +43,5 @@
43
43
  "url": "git+https://github.com/ShellTechnology/shellapps-js.git",
44
44
  "directory": "packages/experience-react"
45
45
  },
46
- "gitHead": "69fb9b35a6226e2c0fb1d9bf68f998b875d1f3d6"
46
+ "gitHead": "cd746a9127afcff3cbec4e794cfeacac89460676"
47
47
  }