@shellapps/experience-react 1.5.0 → 1.5.1
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.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +32 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import React__default from 'react';
|
|
4
2
|
import * as _shellapps_experience from '@shellapps/experience';
|
|
5
3
|
import { ExperienceConfig, Experience } from '@shellapps/experience';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import React__default from 'react';
|
|
6
6
|
|
|
7
7
|
interface ExperienceProviderProps {
|
|
8
8
|
appId: string;
|
|
9
9
|
apiKey: string;
|
|
10
10
|
profileId?: string;
|
|
11
11
|
options?: Partial<Omit<ExperienceConfig, 'appId' | 'apiKey'>>;
|
|
12
|
-
children:
|
|
12
|
+
children: any;
|
|
13
13
|
}
|
|
14
14
|
declare function ExperienceProvider({ appId, apiKey, profileId, options, children }: ExperienceProviderProps): react_jsx_runtime.JSX.Element;
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ interface ErrorBoundaryProps {
|
|
|
17
17
|
fallback?: React__default.ReactNode;
|
|
18
18
|
showCommentForm?: boolean;
|
|
19
19
|
onError?: (error: Error, errorInfo: React__default.ErrorInfo) => void;
|
|
20
|
-
children:
|
|
20
|
+
children: any;
|
|
21
21
|
}
|
|
22
22
|
interface ErrorBoundaryState {
|
|
23
23
|
hasError: boolean;
|
|
@@ -32,7 +32,7 @@ declare class ErrorBoundary extends React__default.Component<ErrorBoundaryProps,
|
|
|
32
32
|
static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState>;
|
|
33
33
|
componentDidCatch(error: Error, errorInfo: React__default.ErrorInfo): void;
|
|
34
34
|
private handleSubmitComment;
|
|
35
|
-
render():
|
|
35
|
+
render(): any;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
interface FeedbackButtonProps {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import React__default from 'react';
|
|
4
2
|
import * as _shellapps_experience from '@shellapps/experience';
|
|
5
3
|
import { ExperienceConfig, Experience } from '@shellapps/experience';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import React__default from 'react';
|
|
6
6
|
|
|
7
7
|
interface ExperienceProviderProps {
|
|
8
8
|
appId: string;
|
|
9
9
|
apiKey: string;
|
|
10
10
|
profileId?: string;
|
|
11
11
|
options?: Partial<Omit<ExperienceConfig, 'appId' | 'apiKey'>>;
|
|
12
|
-
children:
|
|
12
|
+
children: any;
|
|
13
13
|
}
|
|
14
14
|
declare function ExperienceProvider({ appId, apiKey, profileId, options, children }: ExperienceProviderProps): react_jsx_runtime.JSX.Element;
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ interface ErrorBoundaryProps {
|
|
|
17
17
|
fallback?: React__default.ReactNode;
|
|
18
18
|
showCommentForm?: boolean;
|
|
19
19
|
onError?: (error: Error, errorInfo: React__default.ErrorInfo) => void;
|
|
20
|
-
children:
|
|
20
|
+
children: any;
|
|
21
21
|
}
|
|
22
22
|
interface ErrorBoundaryState {
|
|
23
23
|
hasError: boolean;
|
|
@@ -32,7 +32,7 @@ declare class ErrorBoundary extends React__default.Component<ErrorBoundaryProps,
|
|
|
32
32
|
static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState>;
|
|
33
33
|
componentDidCatch(error: Error, errorInfo: React__default.ErrorInfo): void;
|
|
34
34
|
private handleSubmitComment;
|
|
35
|
-
render():
|
|
35
|
+
render(): any;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
interface FeedbackButtonProps {
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
"use strict";
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
@@ -53,11 +54,20 @@ var ExperienceContext = (0, import_react.createContext)(null);
|
|
|
53
54
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
54
55
|
function ExperienceProvider({ appId, apiKey, profileId, options, children }) {
|
|
55
56
|
const instanceRef = (0, import_react2.useRef)(null);
|
|
56
|
-
|
|
57
|
+
const [, forceUpdate] = (0, import_react2.useState)(0);
|
|
58
|
+
if (typeof window !== "undefined" && !instanceRef.current) {
|
|
57
59
|
const instance = import_experience.Experience.init({ appId, apiKey, ...options });
|
|
58
60
|
if (profileId) instance.identify(profileId);
|
|
59
61
|
instanceRef.current = instance;
|
|
60
62
|
}
|
|
63
|
+
(0, import_react2.useEffect)(() => {
|
|
64
|
+
if (!instanceRef.current) {
|
|
65
|
+
const instance = import_experience.Experience.init({ appId, apiKey, ...options });
|
|
66
|
+
if (profileId) instance.identify(profileId);
|
|
67
|
+
instanceRef.current = instance;
|
|
68
|
+
forceUpdate((n) => n + 1);
|
|
69
|
+
}
|
|
70
|
+
}, []);
|
|
61
71
|
(0, import_react2.useEffect)(() => {
|
|
62
72
|
if (profileId && instanceRef.current) {
|
|
63
73
|
instanceRef.current.identify(profileId);
|
|
@@ -764,7 +774,7 @@ function useTranslation() {
|
|
|
764
774
|
}
|
|
765
775
|
if (params) {
|
|
766
776
|
for (const [k, v] of Object.entries(params)) {
|
|
767
|
-
result = result.replace(new RegExp(
|
|
777
|
+
result = result.replace(new RegExp(`{{${k}}}`, "g"), String(v));
|
|
768
778
|
}
|
|
769
779
|
}
|
|
770
780
|
return result;
|
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","import React, { useEffect, useRef } 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: React.ReactNode;\n}\n\nexport function ExperienceProvider({ appId, apiKey, profileId, options, children }: ExperienceProviderProps) {\n const instanceRef = useRef<Experience | null>(null);\n\n if (!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 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","import { createContext } from 'react';\nimport type { Experience } from '@shellapps/experience';\n\nexport const ExperienceContext = createContext<Experience | null>(null);\n","import 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: React.ReactNode;\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","import 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","import { 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\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"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
// src/ExperienceProvider.tsx
|
|
2
|
-
import { useEffect, useRef } from "react";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
5
|
import { Experience } from "@shellapps/experience";
|
|
4
6
|
|
|
5
7
|
// src/context.ts
|
|
@@ -10,11 +12,20 @@ var ExperienceContext = createContext(null);
|
|
|
10
12
|
import { jsx } from "react/jsx-runtime";
|
|
11
13
|
function ExperienceProvider({ appId, apiKey, profileId, options, children }) {
|
|
12
14
|
const instanceRef = useRef(null);
|
|
13
|
-
|
|
15
|
+
const [, forceUpdate] = useState(0);
|
|
16
|
+
if (typeof window !== "undefined" && !instanceRef.current) {
|
|
14
17
|
const instance = Experience.init({ appId, apiKey, ...options });
|
|
15
18
|
if (profileId) instance.identify(profileId);
|
|
16
19
|
instanceRef.current = instance;
|
|
17
20
|
}
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (!instanceRef.current) {
|
|
23
|
+
const instance = Experience.init({ appId, apiKey, ...options });
|
|
24
|
+
if (profileId) instance.identify(profileId);
|
|
25
|
+
instanceRef.current = instance;
|
|
26
|
+
forceUpdate((n) => n + 1);
|
|
27
|
+
}
|
|
28
|
+
}, []);
|
|
18
29
|
useEffect(() => {
|
|
19
30
|
if (profileId && instanceRef.current) {
|
|
20
31
|
instanceRef.current.identify(profileId);
|
|
@@ -104,7 +115,7 @@ var ErrorBoundary = class extends React2.Component {
|
|
|
104
115
|
ErrorBoundary.contextType = ExperienceContext;
|
|
105
116
|
|
|
106
117
|
// src/FeedbackButton.tsx
|
|
107
|
-
import { useState, useEffect as useEffect2, useCallback, useRef as useRef2, useContext } from "react";
|
|
118
|
+
import { useState as useState2, useEffect as useEffect2, useCallback, useRef as useRef2, useContext } from "react";
|
|
108
119
|
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
109
120
|
var TYPE_META = {
|
|
110
121
|
"bug": { icon: "\u{1F41B}", label: "Bug Report", color: "#ef4444" },
|
|
@@ -128,18 +139,18 @@ function FeedbackButton({
|
|
|
128
139
|
authToken
|
|
129
140
|
}) {
|
|
130
141
|
const experience = useContext(ExperienceContext);
|
|
131
|
-
const [isOpen, setIsOpen] =
|
|
132
|
-
const [view, setView] =
|
|
133
|
-
const [selectedType, setSelectedType] =
|
|
134
|
-
const [title, setTitle] =
|
|
135
|
-
const [content, setContent] =
|
|
136
|
-
const [submitting, setSubmitting] =
|
|
137
|
-
const [items, setItems] =
|
|
138
|
-
const [selectedItem, setSelectedItem] =
|
|
139
|
-
const [replies, setReplies] =
|
|
140
|
-
const [replyText, setReplyText] =
|
|
141
|
-
const [loading, setLoading] =
|
|
142
|
-
const [screenshot, setScreenshot] =
|
|
142
|
+
const [isOpen, setIsOpen] = useState2(false);
|
|
143
|
+
const [view, setView] = useState2("list");
|
|
144
|
+
const [selectedType, setSelectedType] = useState2("comment");
|
|
145
|
+
const [title, setTitle] = useState2("");
|
|
146
|
+
const [content, setContent] = useState2("");
|
|
147
|
+
const [submitting, setSubmitting] = useState2(false);
|
|
148
|
+
const [items, setItems] = useState2([]);
|
|
149
|
+
const [selectedItem, setSelectedItem] = useState2(null);
|
|
150
|
+
const [replies, setReplies] = useState2([]);
|
|
151
|
+
const [replyText, setReplyText] = useState2("");
|
|
152
|
+
const [loading, setLoading] = useState2(false);
|
|
153
|
+
const [screenshot, setScreenshot] = useState2(null);
|
|
143
154
|
const panelRef = useRef2(null);
|
|
144
155
|
const baseUrl = apiUrl || experience?.config?.apiUrl || "https://experience.shellapps.com";
|
|
145
156
|
const appId = experience?.config?.appId || "";
|
|
@@ -621,7 +632,7 @@ function FeedbackButton({
|
|
|
621
632
|
}
|
|
622
633
|
|
|
623
634
|
// src/hooks.ts
|
|
624
|
-
import { useContext as useContext2, useState as
|
|
635
|
+
import { useContext as useContext2, useState as useState3, useCallback as useCallback2, useMemo, useEffect as useEffect3 } from "react";
|
|
625
636
|
function useExperience() {
|
|
626
637
|
const ctx = useContext2(ExperienceContext);
|
|
627
638
|
if (!ctx) throw new Error("useExperience must be used within ExperienceProvider");
|
|
@@ -645,13 +656,13 @@ function useTranslation() {
|
|
|
645
656
|
const config = experience.config || {};
|
|
646
657
|
const appId = config.appId || "";
|
|
647
658
|
const apiBaseUrl = config.apiUrl || config.baseUrl || "https://experience-api.shellapps.com";
|
|
648
|
-
const [locale, setLocaleState] =
|
|
659
|
+
const [locale, setLocaleState] = useState3(() => {
|
|
649
660
|
if (typeof window === "undefined") return "en";
|
|
650
661
|
const saved = localStorage.getItem(`exp_locale_${appId}`);
|
|
651
662
|
if (saved) return saved;
|
|
652
663
|
return navigator.language?.split("-")[0] || "en";
|
|
653
664
|
});
|
|
654
|
-
const [translations, setTranslations] =
|
|
665
|
+
const [translations, setTranslations] = useState3(() => {
|
|
655
666
|
if (translationCache[locale]) return translationCache[locale];
|
|
656
667
|
if (typeof window !== "undefined") {
|
|
657
668
|
try {
|
|
@@ -666,8 +677,8 @@ function useTranslation() {
|
|
|
666
677
|
}
|
|
667
678
|
return {};
|
|
668
679
|
});
|
|
669
|
-
const [locales, setLocales] =
|
|
670
|
-
const [isLoading, setIsLoading] =
|
|
680
|
+
const [locales, setLocales] = useState3([]);
|
|
681
|
+
const [isLoading, setIsLoading] = useState3(false);
|
|
671
682
|
const fetchTranslations = useCallback2(async (loc) => {
|
|
672
683
|
if (!appId) return {};
|
|
673
684
|
const cacheKey = `${appId}_${loc}`;
|
|
@@ -721,7 +732,7 @@ function useTranslation() {
|
|
|
721
732
|
}
|
|
722
733
|
if (params) {
|
|
723
734
|
for (const [k, v] of Object.entries(params)) {
|
|
724
|
-
result = result.replace(new RegExp(
|
|
735
|
+
result = result.replace(new RegExp(`{{${k}}}`, "g"), String(v));
|
|
725
736
|
}
|
|
726
737
|
}
|
|
727
738
|
return result;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ExperienceProvider.tsx","../src/context.ts","../src/ErrorBoundary.tsx","../src/FeedbackButton.tsx","../src/hooks.ts"],"sourcesContent":["import React, { useEffect, useRef } 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: React.ReactNode;\n}\n\nexport function ExperienceProvider({ appId, apiKey, profileId, options, children }: ExperienceProviderProps) {\n const instanceRef = useRef<Experience | null>(null);\n\n if (!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 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","import { createContext } from 'react';\nimport type { Experience } from '@shellapps/experience';\n\nexport const ExperienceContext = createContext<Experience | null>(null);\n","import 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: React.ReactNode;\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","import 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","import { 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","useEffect","useRef","jsx","jsxs","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\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":";;;AAEA,SAAgB,WAAW,QAAQ,gBAAgB;AACnD,SAAS,kBAAkB;;;ACF3B,SAAS,qBAAqB;AAGvB,IAAM,oBAAoB,cAAiC,IAAI;;;AD8DlE;AAnDG,SAAS,mBAAmB,EAAE,OAAO,QAAQ,WAAW,SAAS,SAAS,GAA4B;AAC3G,QAAM,cAAc,OAA0B,IAAI;AAClD,QAAM,CAAC,EAAE,WAAW,IAAI,SAAS,CAAC;AAGlC,MAAI,OAAO,WAAW,eAAe,CAAC,YAAY,SAAS;AACzD,UAAM,WAAW,WAAW,KAAK,EAAE,OAAO,QAAQ,GAAG,QAAQ,CAAC;AAC9D,QAAI,UAAW,UAAS,SAAS,SAAS;AAC1C,gBAAY,UAAU;AAAA,EACxB;AAEA,YAAU,MAAM;AAEd,QAAI,CAAC,YAAY,SAAS;AACxB,YAAM,WAAW,WAAW,KAAK,EAAE,OAAO,QAAQ,GAAG,QAAQ,CAAC;AAC9D,UAAI,UAAW,UAAS,SAAS,SAAS;AAC1C,kBAAY,UAAU;AACtB,kBAAY,CAAC,MAAM,IAAI,CAAC;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,aAAa,YAAY,SAAS;AACpC,kBAAY,QAAQ,SAAS,SAAS;AAAA,IACxC;AAAA,EACF,GAAG,CAAC,SAAS,CAAC;AAGd,YAAU,MAAM;AACd,UAAM,UAAU,CAAC,MAAkB;AACjC,UAAI,KAAK,EAAE;AACX,aAAO,IAAI;AACT,cAAM,MAAM,GAAG,eAAe,QAAQ;AACtC,YAAI,KAAK;AACP,sBAAY,SAAS,MAAM,iBAAiB,EAAE,YAAY,IAAI,CAAC;AAC/D;AAAA,QACF;AACA,aAAK,GAAG;AAAA,MACV;AAAA,IACF;AACA,aAAS,iBAAiB,SAAS,SAAS,IAAI;AAChD,WAAO,MAAM,SAAS,oBAAoB,SAAS,SAAS,IAAI;AAAA,EAClE,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,WAAO,MAAM;AACX,kBAAY,SAAS,SAAS;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SACE,oBAAC,kBAAkB,UAAlB,EAA2B,OAAO,YAAY,SAC5C,UACH;AAEJ;;;AErEA,OAAOA,YAAW;AA2DR,gBAAAC,MAGE,YAHF;AAzCH,IAAM,gBAAN,cAA4BC,OAAM,UAAkD;AAAA,EAApF;AAAA;AAIL,iBAA4B;AAAA,MAC1B,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,IACb;AAcA,SAAQ,sBAAsB,MAAM;AAClC,UAAI,KAAK,MAAM,QAAQ,KAAK,KAAK,KAAK,MAAM,OAAO;AACjD,aAAK,SAAS;AAAA,UACZ,kBAAkB,KAAK,MAAM,OAAO;AAAA,UACpC;AAAA,QACF;AACA,aAAK,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,MACnC;AAAA,IACF;AAAA;AAAA,EApBA,OAAO,yBAAyB,OAA2C;AACzE,WAAO,EAAE,UAAU,MAAM,MAAM;AAAA,EACjC;AAAA,EAEA,kBAAkB,OAAc,WAAkC;AAChE,SAAK,SAAS,aAAa,OAAO;AAAA,MAChC,OAAO,EAAE,gBAAgB,UAAU,kBAAkB,GAAG;AAAA,MACxD,UAAU;AAAA,IACZ,CAAC;AACD,SAAK,MAAM,UAAU,OAAO,SAAS;AAAA,EACvC;AAAA,EAYA,SAAS;AACP,QAAI,KAAK,MAAM,UAAU;AACvB,UAAI,KAAK,MAAM,UAAU;AACvB,eAAO,KAAK,MAAM;AAAA,MACpB;AAEA,aACE,qBAAC,SAAI,OAAO,EAAE,SAAS,IAAI,WAAW,SAAS,GAC7C;AAAA,wBAAAD,KAAC,QAAG,kCAAoB;AAAA,QACxB,gBAAAA,KAAC,OAAG,eAAK,MAAM,OAAO,SAAQ;AAAA,QAC7B,KAAK,MAAM,mBAAmB,CAAC,KAAK,MAAM,aACzC,qBAAC,SACC;AAAA,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,aAAY;AAAA,cACZ,OAAO,KAAK,MAAM;AAAA,cAClB,UAAU,CAAC,MAAM,KAAK,SAAS,EAAE,SAAS,EAAE,OAAO,MAAM,CAAC;AAAA,cAC1D,OAAO,EAAE,OAAO,QAAQ,WAAW,IAAI,WAAW,GAAG;AAAA;AAAA,UACvD;AAAA,UACA,gBAAAA,KAAC,YAAO,SAAS,KAAK,qBAAqB,OAAO,EAAE,WAAW,EAAE,GAAG,oBAEpE;AAAA,WACF;AAAA,QAED,KAAK,MAAM,aAAa,gBAAAA,KAAC,OAAE,0CAA4B;AAAA,SAC1D;AAAA,IAEJ;AAEA,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;AA/Da,cACJ,cAAc;;;ACnBvB,SAAgB,YAAAE,WAAU,aAAAC,YAAW,aAAa,UAAAC,SAAQ,kBAAkB;AAuPpE,SAiFM,UAzBF,OAAAC,MAxDJ,QAAAC,aAAA;AA1MR,IAAM,YAAkF;AAAA,EACtF,OAAO,EAAE,MAAM,aAAM,OAAO,cAAc,OAAO,UAAU;AAAA,EAC3D,mBAAmB,EAAE,MAAM,aAAM,OAAO,mBAAmB,OAAO,UAAU;AAAA,EAC5E,WAAW,EAAE,MAAM,aAAM,OAAO,WAAW,OAAO,UAAU;AAAA,EAC5D,UAAU,EAAE,MAAM,aAAM,OAAO,UAAU,OAAO,UAAU;AAC5D;AAEA,IAAM,gBAAgD;AAAA,EACpD,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,YAAY;AACd;AAIO,SAAS,eAAe;AAAA,EAC7B,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,aAAa,WAAW,iBAAiB;AAC/C,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAS,KAAK;AAC1C,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAoC,MAAM;AAClE,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAuB,SAAS;AACxE,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAS,EAAE;AACrC,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,EAAE;AACzC,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAyB,CAAC,CAAC;AACrD,QAAM,CAAC,cAAc,eAAe,IAAIA,UAA8B,IAAI;AAC1E,QAAM,CAAC,SAAS,UAAU,IAAIA,UAA0B,CAAC,CAAC;AAC1D,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,EAAE;AAC7C,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAwB,IAAI;AAChE,QAAM,WAAWC,QAAuB,IAAI;AAE5C,QAAM,UAAU,UAAW,YAAoB,QAAQ,UAAU;AACjE,QAAM,QAAS,YAAoB,QAAQ,SAAS;AAEpD,QAAM,UAAU,YAAY,MAA8B;AACxD,UAAM,IAA4B,EAAE,gBAAgB,mBAAmB;AACvE,QAAI,UAAW,GAAE,eAAe,IAAI,UAAU,SAAS;AACvD,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,CAAC;AAGd,EAAAC,WAAU,MAAM;AACd,QAAI,YAAY;AACd,MAAC,WAAmB,eAAe,MAAM,UAAU,IAAI;AAAA,IACzD;AACA,WAAO,MAAM;AACX,UAAI,WAAY,QAAQ,WAAmB;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AAGf,EAAAA,WAAU,MAAM;AACd,QAAI,UAAU,SAAS,QAAQ;AAC7B,mBAAa;AAAA,IACf;AAAA,EACF,GAAG,CAAC,QAAQ,IAAI,CAAC;AAEjB,QAAM,eAAe,YAAY;AAC/B,eAAW,IAAI;AACf,QAAI;AACF,YAAM,MAAM,MAAM;AAAA,QAChB,GAAG,OAAO,0BAA0B,KAAK;AAAA,QACzC,EAAE,SAAS,QAAQ,EAAE;AAAA,MACvB;AACA,UAAI,IAAI,IAAI;AACV,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,iBAAS,KAAK,SAAS,CAAC,CAAC;AAAA,MAC3B;AAAA,IACF,QAAQ;AAAA,IAER;AACA,eAAW,KAAK;AAAA,EAClB;AAEA,QAAM,aAAa,OAAO,SAAuB;AAC/C,oBAAgB,IAAI;AACpB,YAAQ,QAAQ;AAChB,QAAI;AACF,YAAM,MAAM,MAAM;AAAA,QAChB,GAAG,OAAO,oBAAoB,KAAK,GAAG;AAAA,QACtC,EAAE,SAAS,QAAQ,EAAE;AAAA,MACvB;AACA,UAAI,IAAI,IAAI;AACV,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,mBAAW,KAAK,WAAW,CAAC,CAAC;AAAA,MAC/B;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,oBAAoB,YAAY;AACpC,QAAI;AACF,YAAM,cAAe,OAAe;AACpC,UAAI,CAAC,YAAa;AAClB,YAAM,SAAS,MAAM,YAAY,SAAS,MAAM,EAAE,OAAO,KAAK,SAAS,MAAM,CAAC;AAC9E,oBAAc,OAAO,UAAU,cAAc,GAAG,CAAC;AAAA,IACnD,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,SAAS,YAAY;AACzB,QAAI,CAAC,MAAM,KAAK,KAAK,CAAC,QAAQ,KAAK,EAAG;AACtC,kBAAc,IAAI;AAClB,QAAI;AACF,YAAM,MAAM;AAAA,QACV,WAAW,UAAU;AAAA,QACrB,KAAK,OAAO,SAAS;AAAA,QACrB,UAAU,EAAE,OAAO,OAAO,YAAY,QAAQ,OAAO,YAAY;AAAA,QACjE,QAAQ,UAAU;AAAA,QAClB,UAAU,SAAS,YAAY;AAAA,MACjC;AAEA,YAAM,MAAM,MAAM,MAAM,GAAG,OAAO,oBAAoB;AAAA,QACpD,QAAQ;AAAA,QACR,SAAS,QAAQ;AAAA,QACjB,MAAM,KAAK,UAAU;AAAA,UACnB;AAAA,UACA,MAAM;AAAA,UACN,OAAO,MAAM,KAAK;AAAA,UAClB,SAAS,QAAQ,KAAK;AAAA,UACtB,SAAS;AAAA,UACT,YAAY,cAAc;AAAA,QAC5B,CAAC;AAAA,MACH,CAAC;AAED,UAAI,IAAI,IAAI;AACV,iBAAS,EAAE;AACX,mBAAW,EAAE;AACb,sBAAc,IAAI;AAClB,gBAAQ,MAAM;AACd,qBAAa;AAAA,MACf;AAAA,IACF,QAAQ;AAAA,IAER;AACA,kBAAc,KAAK;AAAA,EACrB;AAEA,QAAM,cAAc,YAAY;AAC9B,QAAI,CAAC,UAAU,KAAK,KAAK,CAAC,aAAc;AACxC,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,OAAO,oBAAoB,aAAa,GAAG,UAAU;AAAA,QAC9E,QAAQ;AAAA,QACR,SAAS,QAAQ;AAAA,QACjB,MAAM,KAAK,UAAU,EAAE,SAAS,UAAU,KAAK,EAAE,CAAC;AAAA,MACpD,CAAC;AACD,UAAI,IAAI,IAAI;AACV,cAAM,QAAQ,MAAM,IAAI,KAAK;AAC7B,mBAAW,CAAC,SAAS,CAAC,GAAG,MAAM,KAAK,CAAC;AACrC,qBAAa,EAAE;AAAA,MACjB;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,OAAO,OAAO,OAAe;AACjC,QAAI;AACF,YAAM,MAAM,GAAG,OAAO,oBAAoB,EAAE,SAAS;AAAA,QACnD,QAAQ;AAAA,QACR,SAAS,QAAQ;AAAA,QACjB,MAAM,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAAA,MACzC,CAAC;AACD,mBAAa;AAAA,IACf,QAAQ;AAAA,IAER;AAAA,EACF;AAIA,QAAM,YAAiD;AAAA,IACrD,gBAAgB,EAAE,QAAQ,IAAI,OAAO,GAAG;AAAA,IACxC,eAAe,EAAE,QAAQ,IAAI,MAAM,GAAG;AAAA,IACtC,aAAa,EAAE,KAAK,IAAI,OAAO,GAAG;AAAA,IAClC,YAAY,EAAE,KAAK,IAAI,MAAM,GAAG;AAAA,EAClC;AAEA,QAAM,WAAgD;AAAA,IACpD,gBAAgB,EAAE,QAAQ,IAAI,OAAO,GAAG;AAAA,IACxC,eAAe,EAAE,QAAQ,IAAI,MAAM,GAAG;AAAA,IACtC,aAAa,EAAE,KAAK,IAAI,OAAO,GAAG;AAAA,IAClC,YAAY,EAAE,KAAK,IAAI,MAAM,GAAG;AAAA,EAClC;AAIA,SACE,gBAAAH,MAAA,YAEG;AAAA,KAAC,UACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,MAAM,UAAU,CAAC,MAAM;AAAA,QAChC,OAAO;AAAA,UACL,UAAU;AAAA,UACV,GAAG,UAAU,QAAQ;AAAA,UACrB,QAAQ;AAAA,UACR,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,SAAS;AAAA,UACT,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,KAAK;AAAA,QACP;AAAA,QACD;AAAA;AAAA,UACK;AAAA;AAAA;AAAA,IACN;AAAA,IAID,UACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,OAAO;AAAA,UACL,UAAU;AAAA,UACV,GAAG,SAAS,QAAQ;AAAA,UACpB,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,WAAW;AAAA,UACX,YAAY;AAAA,UACZ,cAAc;AAAA,UACd,WAAW;AAAA,UACX,SAAS;AAAA,UACT,eAAe;AAAA,UACf,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,UAAU;AAAA,UACV,OAAO;AAAA,QACT;AAAA,QAGA;AAAA,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,gBAAgB;AAAA,gBAChB,YAAY;AAAA,cACd;AAAA,cAEA;AAAA,gCAAAD,KAAC,UAAK,OAAO,EAAE,YAAY,IAAI,GAC5B,mBAAS,QAAQ,iBAAiB,SAAS,WAAW,aAAa,YACtE;AAAA,gBACA,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,KAAK,EAAE,GACnC;AAAA,2BAAS,UACR,gBAAAD;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAS,MAAM;AAAE,gCAAQ,MAAM;AAAG,wCAAgB,IAAI;AAAA,sBAAG;AAAA,sBACzD,OAAO,EAAE,YAAY,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,WAAW,UAAU,GAAG;AAAA,sBAC7F;AAAA;AAAA,kBAED;AAAA,kBAEF,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAS,MAAM,UAAU,KAAK;AAAA,sBAC9B,OAAO,EAAE,YAAY,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,WAAW,UAAU,GAAG;AAAA,sBAC7F;AAAA;AAAA,kBAED;AAAA,mBACF;AAAA;AAAA;AAAA,UACF;AAAA,UAGA,gBAAAC,MAAC,SAAI,OAAO,EAAE,MAAM,GAAG,UAAU,QAAQ,SAAS,GAAG,GAElD;AAAA,qBAAS,UACR,gBAAAA,MAAA,YACE;AAAA,8BAAAD;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS,MAAM,QAAQ,KAAK;AAAA,kBAC5B,OAAO;AAAA,oBACL,OAAO;AAAA,oBACP,SAAS;AAAA,oBACT,YAAY;AAAA,oBACZ,OAAO;AAAA,oBACP,QAAQ;AAAA,oBACR,cAAc;AAAA,oBACd,QAAQ;AAAA,oBACR,YAAY;AAAA,oBACZ,cAAc;AAAA,kBAChB;AAAA,kBACD;AAAA;AAAA,cAED;AAAA,cACC,UACC,gBAAAA,KAAC,OAAE,OAAO,EAAE,WAAW,UAAU,OAAO,UAAU,GAAG,2BAAQ,IAC3D,MAAM,WAAW,IACnB,gBAAAA,KAAC,OAAE,OAAO,EAAE,WAAW,UAAU,OAAO,UAAU,GAAG,6BAAe,IAEpE,MAAM,IAAI,CAAC,SACT,gBAAAC;AAAA,gBAAC;AAAA;AAAA,kBAEC,SAAS,MAAM,WAAW,IAAI;AAAA,kBAC9B,OAAO;AAAA,oBACL,SAAS;AAAA,oBACT,cAAc;AAAA,oBACd,QAAQ;AAAA,oBACR,cAAc;AAAA,oBACd,QAAQ;AAAA,kBACV;AAAA,kBAEA;AAAA,oCAAAA,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,iBAAiB,cAAc,EAAE,GAC9E;AAAA,sCAAAA,MAAC,UACE;AAAA,kCAAU,KAAK,IAAI,GAAG;AAAA,wBAAK;AAAA,wBAAC,gBAAAD,KAAC,YAAQ,eAAK,OAAM;AAAA,yBACnD;AAAA,sBACC,KAAK,SAAS,qBACb,gBAAAC;AAAA,wBAAC;AAAA;AAAA,0BACC,SAAS,CAAC,MAAM;AAAE,8BAAE,gBAAgB;AAAG,iCAAK,KAAK,GAAG;AAAA,0BAAG;AAAA,0BACvD,OAAO;AAAA,4BACL,YAAY;AAAA,4BACZ,QAAQ;AAAA,4BACR,cAAc;AAAA,4BACd,SAAS;AAAA,4BACT,QAAQ;AAAA,4BACR,UAAU;AAAA,0BACZ;AAAA,0BACD;AAAA;AAAA,4BACI,KAAK;AAAA;AAAA;AAAA,sBACV;AAAA,uBAEJ;AAAA,oBACA,gBAAAA,MAAC,SAAI,OAAO,EAAE,UAAU,IAAI,OAAO,UAAU,GAC1C;AAAA,oCAAc,KAAK,MAAM;AAAA,sBAAE;AAAA,sBAAI,KAAK;AAAA,sBAAY;AAAA,sBAAY,IAAI,KAAK,KAAK,UAAU,EAAE,mBAAmB;AAAA,uBAC5G;AAAA;AAAA;AAAA,gBAhCK,KAAK;AAAA,cAiCZ,CACD;AAAA,eAEL;AAAA,YAID,SAAS,SACR,gBAAAA,MAAA,YAEE;AAAA,8BAAAD,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,qBAAqB,WAAW,KAAK,GAAG,cAAc,GAAG,GACpF,iBAAO,QAAQ,SAAS,EAAgD;AAAA,gBACxE,CAAC,CAAC,MAAM,IAAI,MACV,gBAAAC;AAAA,kBAAC;AAAA;AAAA,oBAEC,SAAS,MAAM,gBAAgB,IAAI;AAAA,oBACnC,OAAO;AAAA,sBACL,SAAS;AAAA,sBACT,cAAc;AAAA,sBACd,QAAQ,aAAa,iBAAiB,OAAO,KAAK,QAAQ,SAAS;AAAA,sBACnE,YAAY,iBAAiB,OAAO,GAAG,KAAK,KAAK,OAAO;AAAA,sBACxD,QAAQ;AAAA,sBACR,UAAU;AAAA,sBACV,WAAW;AAAA,oBACb;AAAA,oBAEC;AAAA,2BAAK;AAAA,sBAAK;AAAA,sBAAE,KAAK;AAAA;AAAA;AAAA,kBAZb;AAAA,gBAaP;AAAA,cAEJ,GACF;AAAA,cAEA,gBAAAD;AAAA,gBAAC;AAAA;AAAA,kBACC,aAAY;AAAA,kBACZ,OAAO;AAAA,kBACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,kBACxC,OAAO;AAAA,oBACL,OAAO;AAAA,oBACP,SAAS;AAAA,oBACT,cAAc;AAAA,oBACd,QAAQ;AAAA,oBACR,cAAc;AAAA,oBACd,UAAU;AAAA,oBACV,WAAW;AAAA,kBACb;AAAA;AAAA,cACF;AAAA,cAEA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,aAAY;AAAA,kBACZ,OAAO;AAAA,kBACP,UAAU,CAAC,MAAM,WAAW,EAAE,OAAO,KAAK;AAAA,kBAC1C,MAAM;AAAA,kBACN,OAAO;AAAA,oBACL,OAAO;AAAA,oBACP,SAAS;AAAA,oBACT,cAAc;AAAA,oBACd,QAAQ;AAAA,oBACR,cAAc;AAAA,oBACd,UAAU;AAAA,oBACV,QAAQ;AAAA,oBACR,WAAW;AAAA,kBACb;AAAA;AAAA,cACF;AAAA,cAGE,OAAe,eACf,gBAAAC;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS;AAAA,kBACT,OAAO;AAAA,oBACL,YAAY;AAAA,oBACZ,QAAQ;AAAA,oBACR,cAAc;AAAA,oBACd,SAAS;AAAA,oBACT,QAAQ;AAAA,oBACR,UAAU;AAAA,oBACV,cAAc;AAAA,oBACd,OAAO,aAAa,YAAY;AAAA,kBAClC;AAAA,kBACD;AAAA;AAAA,oBACK,aAAa,+BAA0B;AAAA;AAAA;AAAA,cAC7C;AAAA,cAGF,gBAAAD;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS;AAAA,kBACT,UAAU,cAAc,CAAC,MAAM,KAAK,KAAK,CAAC,QAAQ,KAAK;AAAA,kBACvD,OAAO;AAAA,oBACL,OAAO;AAAA,oBACP,SAAS;AAAA,oBACT,YAAY,aAAa,YAAY;AAAA,oBACrC,OAAO;AAAA,oBACP,QAAQ;AAAA,oBACR,cAAc;AAAA,oBACd,QAAQ,aAAa,YAAY;AAAA,oBACjC,YAAY;AAAA,kBACd;AAAA,kBAEC,uBAAa,qBAAgB;AAAA;AAAA,cAChC;AAAA,eACF;AAAA,YAID,SAAS,YAAY,gBACpB,gBAAAC,MAAA,YACE;AAAA,8BAAAA,MAAC,SAAI,OAAO,EAAE,cAAc,GAAG,GAC7B;AAAA,gCAAAA,MAAC,SAAI,OAAO,EAAE,UAAU,IAAI,OAAO,UAAU,aAAa,IAAI,GAAG,OAAO,YAAY,KAAK,cAAc,EAAE,GACtG;AAAA,4BAAU,aAAa,IAAI,GAAG;AAAA,kBAAK;AAAA,kBAAE,UAAU,aAAa,IAAI,GAAG;AAAA,mBACtE;AAAA,gBACA,gBAAAD,KAAC,QAAG,OAAO,EAAE,QAAQ,WAAW,UAAU,GAAG,GAAI,uBAAa,OAAM;AAAA,gBACpE,gBAAAC,MAAC,SAAI,OAAO,EAAE,UAAU,IAAI,OAAO,WAAW,cAAc,EAAE,GAC3D;AAAA,gCAAc,aAAa,MAAM;AAAA,kBAAE;AAAA,kBAAI,IAAI,KAAK,aAAa,UAAU,EAAE,mBAAmB;AAAA,mBAC/F;AAAA,gBACA,gBAAAD,KAAC,OAAE,OAAO,EAAE,QAAQ,GAAG,YAAY,IAAI,GAAI,uBAAa,SAAQ;AAAA,iBAClE;AAAA,cAEA,gBAAAA,KAAC,QAAG,OAAO,EAAE,QAAQ,QAAQ,WAAW,qBAAqB,QAAQ,SAAS,GAAG;AAAA,cAGjF,gBAAAC,MAAC,SAAI,OAAO,EAAE,cAAc,GAAG,GAC7B;AAAA,gCAAAA,MAAC,YAAO,OAAO,EAAE,UAAU,GAAG,GAAG;AAAA;AAAA,kBAAU,QAAQ;AAAA,kBAAO;AAAA,mBAAC;AAAA,gBAC1D,QAAQ,IAAI,CAAC,MACZ,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBAEC,OAAO;AAAA,sBACL,SAAS;AAAA,sBACT,WAAW;AAAA,sBACX,cAAc;AAAA,sBACd,YAAY,EAAE,gBAAgB,cAAc,YAAY;AAAA,sBACxD,YAAY,aAAa,EAAE,gBAAgB,cAAc,YAAY,SAAS;AAAA,oBAChF;AAAA,oBAEA;AAAA,sCAAAA,MAAC,SAAI,OAAO,EAAE,UAAU,IAAI,OAAO,WAAW,cAAc,EAAE,GAC3D;AAAA,0BAAE,gBAAgB,cAAc,8BAAkB;AAAA,wBAAU,EAAE,cAAc,SAAM,EAAE,WAAW,KAAK;AAAA,wBAAG;AAAA,wBAAI,IAAI,KAAK,EAAE,UAAU,EAAE,mBAAmB;AAAA,yBACxJ;AAAA,sBACA,gBAAAD,KAAC,SAAI,OAAO,EAAE,UAAU,GAAG,GAAI,YAAE,SAAQ;AAAA;AAAA;AAAA,kBAZpC,EAAE;AAAA,gBAaT,CACD;AAAA,iBACH;AAAA,cAGA,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,KAAK,EAAE,GACpC;AAAA,gCAAAD;AAAA,kBAAC;AAAA;AAAA,oBACC,aAAY;AAAA,oBACZ,OAAO;AAAA,oBACP,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAK;AAAA,oBAC5C,WAAW,CAAC,MAAM;AAAE,0BAAI,EAAE,QAAQ,QAAS,aAAY;AAAA,oBAAG;AAAA,oBAC1D,OAAO;AAAA,sBACL,MAAM;AAAA,sBACN,SAAS;AAAA,sBACT,cAAc;AAAA,sBACd,QAAQ;AAAA,sBACR,UAAU;AAAA,oBACZ;AAAA;AAAA,gBACF;AAAA,gBACA,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAS;AAAA,oBACT,UAAU,CAAC,UAAU,KAAK;AAAA,oBAC1B,OAAO;AAAA,sBACL,SAAS;AAAA,sBACT,YAAY;AAAA,sBACZ,OAAO;AAAA,sBACP,QAAQ;AAAA,sBACR,cAAc;AAAA,sBACd,QAAQ;AAAA,sBACR,UAAU;AAAA,oBACZ;AAAA,oBACD;AAAA;AAAA,gBAED;AAAA,iBACF;AAAA,eACF;AAAA,aAEJ;AAAA;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;;;ACnjBA,SAAS,cAAAK,aAAY,YAAAC,WAAU,eAAAC,cAAa,SAAS,aAAAC,kBAAyB;AAGvE,SAAS,gBAAgB;AAC9B,QAAM,MAAMC,YAAW,iBAAiB;AACxC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,sDAAsD;AAChF,SAAO;AACT;AAEO,SAAS,WAAW;AACzB,QAAM,aAAa,cAAc;AACjC,SAAO,QAAQ,OAAO;AAAA,IACpB,OAAO,CAAC,WAAmB,aAAsC,WAAW,MAAM,WAAW,QAAQ;AAAA,IACrG,eAAe,MAAM,WAAW,cAAc;AAAA,EAChD,IAAI,CAAC,UAAU,CAAC;AAClB;AAEO,SAAS,QAAW,UAAkB,cAAoB;AAC/D,QAAM,aAAa,cAAc;AACjC,SAAO,WAAW,QAAQ,UAAU,YAAY;AAClD;AAiBA,IAAM,mBAAqC,CAAC;AAC5C,IAAM,gBAAgB,oBAAI,IAA6C;AAchE,SAAS,iBAAoC;AAClD,QAAM,aAAa,cAAc;AACjC,QAAM,SAAU,WAAmB,UAAU,CAAC;AAC9C,QAAM,QAAgB,OAAO,SAAS;AACtC,QAAM,aAAqB,OAAO,UAAU,OAAO,WAAW;AAE9D,QAAM,CAAC,QAAQ,cAAc,IAAIC,UAAS,MAAM;AAC9C,QAAI,OAAO,WAAW,YAAa,QAAO;AAE1C,UAAM,QAAQ,aAAa,QAAQ,cAAc,KAAK,EAAE;AACxD,QAAI,MAAO,QAAO;AAClB,WAAO,UAAU,UAAU,MAAM,GAAG,EAAE,CAAC,KAAK;AAAA,EAC9C,CAAC;AAED,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAiC,MAAM;AAE7E,QAAI,iBAAiB,MAAM,EAAG,QAAO,iBAAiB,MAAM;AAE5D,QAAI,OAAO,WAAW,aAAa;AACjC,UAAI;AACF,cAAM,SAAS,aAAa,QAAQ,oBAAoB,KAAK,IAAI,MAAM,EAAE;AACzE,YAAI,QAAQ;AACV,gBAAM,SAAS,KAAK,MAAM,MAAM;AAChC,2BAAiB,MAAM,IAAI;AAC3B,iBAAO;AAAA,QACT;AAAA,MACF,QAAQ;AAAA,MAAe;AAAA,IACzB;AACA,WAAO,CAAC;AAAA,EACV,CAAC;AAED,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAmE,CAAC,CAAC;AACnG,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAGhD,QAAM,oBAAoBC,aAAY,OAAO,QAAiD;AAC5F,QAAI,CAAC,MAAO,QAAO,CAAC;AAGpB,UAAM,WAAW,GAAG,KAAK,IAAI,GAAG;AAChC,UAAM,WAAW,cAAc,IAAI,QAAQ;AAC3C,QAAI,SAAU,QAAO;AAErB,UAAM,WAAW,YAAY;AAC3B,UAAI;AACF,cAAM,MAAM,MAAM,MAAM,GAAG,UAAU,wBAAwB,KAAK,IAAI,GAAG,EAAE;AAC3E,YAAI,CAAC,IAAI,GAAI,QAAO,CAAC;AACrB,cAAM,OAAO,MAAM,IAAI,KAAK;AAE5B,yBAAiB,GAAG,IAAI;AACxB,YAAI,OAAO,WAAW,aAAa;AACjC,cAAI;AACF,yBAAa,QAAQ,oBAAoB,KAAK,IAAI,GAAG,IAAI,KAAK,UAAU,IAAI,CAAC;AAAA,UAC/E,QAAQ;AAAA,UAA+B;AAAA,QACzC;AACA,eAAO;AAAA,MACT,QAAQ;AACN,eAAO,CAAC;AAAA,MACV,UAAE;AACA,sBAAc,OAAO,QAAQ;AAAA,MAC/B;AAAA,IACF,GAAG;AAEH,kBAAc,IAAI,UAAU,OAAO;AACnC,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,UAAU,CAAC;AAGtB,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,MAAO;AACZ,UAAM,GAAG,UAAU,wBAAwB,KAAK,UAAU,EACvD,KAAK,SAAO,IAAI,KAAK,IAAI,KAAK,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC,EACjD,KAAK,UAAQ,WAAW,KAAK,WAAW,CAAC,CAAC,CAAC,EAC3C,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACnB,GAAG,CAAC,OAAO,UAAU,CAAC;AAGtB,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,MAAO;AAGZ,QAAI,iBAAiB,MAAM,GAAG;AAC5B,sBAAgB,iBAAiB,MAAM,CAAE;AACzC;AAAA,IACF;AAEA,iBAAa,IAAI;AACjB,sBAAkB,MAAM,EAAE,KAAK,UAAQ;AACrC,sBAAgB,IAAI;AACpB,mBAAa,KAAK;AAAA,IACpB,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,OAAO,iBAAiB,CAAC;AAGrC,QAAM,IAAID,aAAY,CAAC,KAAa,WAAqD;AACvF,QAAI,SAAS,aAAa,GAAG,KAAK;AAGlC,QAAI,OAAO,SAAS,IAAI,KAAK,UAAU,WAAW,QAAQ;AACxD,YAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,YAAM,QAAQ,OAAO,OAAO,KAAK;AACjC,eAAS,UAAU,IAAK,MAAM,CAAC,KAAK,SAAW,MAAM,CAAC,KAAK;AAAA,IAC7D;AAGA,QAAI,QAAQ;AACV,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,iBAAS,OAAO,QAAQ,IAAI,OAAO,KAAO,CAAC,MAAQ,GAAG,GAAG,OAAO,CAAC,CAAC;AAAA,MACpE;AAAA,IACF;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,YAAY,CAAC;AAGjB,QAAM,YAAYA,aAAY,CAAC,cAAsB;AACnD,mBAAe,SAAS;AACxB,QAAI,OAAO,WAAW,aAAa;AACjC,mBAAa,QAAQ,cAAc,KAAK,IAAI,SAAS;AAAA,IACvD;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO,EAAE,GAAG,QAAQ,WAAW,SAAS,UAAU;AACpD;","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.5.
|
|
3
|
+
"version": "1.5.1",
|
|
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": "
|
|
46
|
+
"gitHead": "7197532df3daa87b53338c610978af3c27800402"
|
|
47
47
|
}
|