@product7/product7-js 0.1.0

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.
Files changed (58) hide show
  1. package/README.md +1025 -0
  2. package/dist/README.md +1025 -0
  3. package/dist/product7-js.js +14658 -0
  4. package/dist/product7-js.js.map +1 -0
  5. package/dist/product7-js.min.js +2 -0
  6. package/dist/product7-js.min.js.map +1 -0
  7. package/package.json +114 -0
  8. package/src/api/mock-data/index.js +360 -0
  9. package/src/api/services/ChangelogService.js +28 -0
  10. package/src/api/services/FeedbackService.js +44 -0
  11. package/src/api/services/HelpService.js +50 -0
  12. package/src/api/services/MessengerService.js +279 -0
  13. package/src/api/services/SurveyService.js +127 -0
  14. package/src/api/utils/helpers.js +30 -0
  15. package/src/core/APIService.js +303 -0
  16. package/src/core/BaseAPIService.js +298 -0
  17. package/src/core/EventBus.js +54 -0
  18. package/src/core/Product7.js +812 -0
  19. package/src/core/WebSocketService.js +275 -0
  20. package/src/docs/api.md +226 -0
  21. package/src/docs/example.md +461 -0
  22. package/src/docs/framework-integrations.md +714 -0
  23. package/src/docs/installation.md +281 -0
  24. package/src/index.js +894 -0
  25. package/src/styles/base.js +50 -0
  26. package/src/styles/changelog.js +665 -0
  27. package/src/styles/components.js +553 -0
  28. package/src/styles/design-tokens.js +124 -0
  29. package/src/styles/feedback.js +325 -0
  30. package/src/styles/messenger-components.js +632 -0
  31. package/src/styles/messenger-core.js +233 -0
  32. package/src/styles/messenger-features.js +169 -0
  33. package/src/styles/messenger-views.js +877 -0
  34. package/src/styles/messenger.js +17 -0
  35. package/src/styles/messengerCustomStyles.js +114 -0
  36. package/src/styles/styles.js +26 -0
  37. package/src/styles/survey.js +894 -0
  38. package/src/utils/errors.js +142 -0
  39. package/src/utils/helpers.js +219 -0
  40. package/src/widgets/BaseWidget.js +548 -0
  41. package/src/widgets/ButtonWidget.js +104 -0
  42. package/src/widgets/ChangelogWidget.js +615 -0
  43. package/src/widgets/InlineWidget.js +148 -0
  44. package/src/widgets/MessengerWidget.js +979 -0
  45. package/src/widgets/SurveyWidget.js +1325 -0
  46. package/src/widgets/TabWidget.js +45 -0
  47. package/src/widgets/WidgetFactory.js +70 -0
  48. package/src/widgets/messenger/MessengerState.js +323 -0
  49. package/src/widgets/messenger/components/MessengerLauncher.js +124 -0
  50. package/src/widgets/messenger/components/MessengerPanel.js +111 -0
  51. package/src/widgets/messenger/components/NavigationTabs.js +130 -0
  52. package/src/widgets/messenger/views/ChangelogView.js +167 -0
  53. package/src/widgets/messenger/views/ChatView.js +592 -0
  54. package/src/widgets/messenger/views/ConversationsView.js +244 -0
  55. package/src/widgets/messenger/views/HelpView.js +239 -0
  56. package/src/widgets/messenger/views/HomeView.js +300 -0
  57. package/src/widgets/messenger/views/PreChatFormView.js +109 -0
  58. package/types/index.d.ts +341 -0
@@ -0,0 +1,142 @@
1
+ export class SDKError extends Error {
2
+ constructor(message, cause) {
3
+ super(message);
4
+ this.name = 'SDKError';
5
+ this.cause = cause;
6
+
7
+ if (Error.captureStackTrace) {
8
+ Error.captureStackTrace(this, SDKError);
9
+ }
10
+ }
11
+ }
12
+
13
+ export class APIError extends Error {
14
+ constructor(status, message, response) {
15
+ super(message);
16
+ this.name = 'APIError';
17
+ this.status = status;
18
+ this.response = response;
19
+
20
+ if (Error.captureStackTrace) {
21
+ Error.captureStackTrace(this, APIError);
22
+ }
23
+ }
24
+
25
+ isNetworkError() {
26
+ return this.status === 0;
27
+ }
28
+
29
+ isClientError() {
30
+ return this.status >= 400 && this.status < 500;
31
+ }
32
+
33
+ isServerError() {
34
+ return this.status >= 500 && this.status < 600;
35
+ }
36
+ }
37
+
38
+ export class WidgetError extends Error {
39
+ constructor(message, widgetType, widgetId) {
40
+ super(message);
41
+ this.name = 'WidgetError';
42
+ this.widgetType = widgetType;
43
+ this.widgetId = widgetId;
44
+
45
+ if (Error.captureStackTrace) {
46
+ Error.captureStackTrace(this, WidgetError);
47
+ }
48
+ }
49
+ }
50
+
51
+ export class ConfigError extends Error {
52
+ constructor(message, configKey) {
53
+ super(message);
54
+ this.name = 'ConfigError';
55
+ this.configKey = configKey;
56
+
57
+ if (Error.captureStackTrace) {
58
+ Error.captureStackTrace(this, ConfigError);
59
+ }
60
+ }
61
+ }
62
+
63
+ export class ValidationError extends Error {
64
+ constructor(message, field, value) {
65
+ super(message);
66
+ this.name = 'ValidationError';
67
+ this.field = field;
68
+ this.value = value;
69
+
70
+ if (Error.captureStackTrace) {
71
+ Error.captureStackTrace(this, ValidationError);
72
+ }
73
+ }
74
+ }
75
+
76
+ export class ErrorHandler {
77
+ constructor(debug = false) {
78
+ this.debug = debug;
79
+ }
80
+
81
+ handle(error, context = '') {
82
+ const errorInfo = {
83
+ name: error.name,
84
+ message: error.message,
85
+ context,
86
+ timestamp: new Date().toISOString(),
87
+ };
88
+
89
+ if (error instanceof APIError) {
90
+ errorInfo.status = error.status;
91
+ errorInfo.type = 'api';
92
+ } else if (error instanceof WidgetError) {
93
+ errorInfo.widgetType = error.widgetType;
94
+ errorInfo.widgetId = error.widgetId;
95
+ errorInfo.type = 'widget';
96
+ } else if (error instanceof ConfigError) {
97
+ errorInfo.configKey = error.configKey;
98
+ errorInfo.type = 'config';
99
+ } else if (error instanceof ValidationError) {
100
+ errorInfo.field = error.field;
101
+ errorInfo.value = error.value;
102
+ errorInfo.type = 'validation';
103
+ } else {
104
+ errorInfo.type = 'unknown';
105
+ }
106
+
107
+ if (this.debug) {
108
+ console.error('[Product7 Error]', errorInfo, error);
109
+ } else {
110
+ console.error('[Product7 Error]', error.message);
111
+ }
112
+
113
+ return errorInfo;
114
+ }
115
+
116
+ getUserMessage(error) {
117
+ if (error instanceof APIError) {
118
+ if (error.isNetworkError()) {
119
+ return 'Network error. Please check your connection and try again.';
120
+ } else if (error.isClientError()) {
121
+ return 'Invalid request. Please check your input and try again.';
122
+ } else if (error.isServerError()) {
123
+ return 'Server error. Please try again later.';
124
+ }
125
+ return 'Failed to submit feedback. Please try again.';
126
+ }
127
+
128
+ if (error instanceof ValidationError) {
129
+ return `Please check your ${error.field}: ${error.message}`;
130
+ }
131
+
132
+ if (error instanceof ConfigError) {
133
+ return 'Configuration error. Please check your SDK setup.';
134
+ }
135
+
136
+ if (error instanceof WidgetError) {
137
+ return 'Widget error. Please try refreshing the page.';
138
+ }
139
+
140
+ return 'An unexpected error occurred. Please try again.';
141
+ }
142
+ }
@@ -0,0 +1,219 @@
1
+ export function generateId(prefix = 'feedback') {
2
+ const timestamp = Date.now();
3
+ const random = Math.random().toString(36).substring(2, 9);
4
+ return `${prefix}_${timestamp}_${random}`;
5
+ }
6
+
7
+ export function deepMerge(target, source) {
8
+ const result = { ...target };
9
+
10
+ for (const key in source) {
11
+ if (source.hasOwnProperty(key)) {
12
+ if (
13
+ source[key] &&
14
+ typeof source[key] === 'object' &&
15
+ !Array.isArray(source[key])
16
+ ) {
17
+ result[key] = deepMerge(target[key] || {}, source[key]);
18
+ } else {
19
+ result[key] = source[key];
20
+ }
21
+ }
22
+ }
23
+
24
+ return result;
25
+ }
26
+
27
+ export function debounce(func, wait) {
28
+ let timeout;
29
+ return function executedFunction(...args) {
30
+ const later = () => {
31
+ clearTimeout(timeout);
32
+ func(...args);
33
+ };
34
+ clearTimeout(timeout);
35
+ timeout = setTimeout(later, wait);
36
+ };
37
+ }
38
+
39
+ export function throttle(func, limit) {
40
+ let lastFunc;
41
+ let lastRan;
42
+ return function (...args) {
43
+ if (!lastRan) {
44
+ func(...args);
45
+ lastRan = Date.now();
46
+ } else {
47
+ clearTimeout(lastFunc);
48
+ lastFunc = setTimeout(
49
+ () => {
50
+ if (Date.now() - lastRan >= limit) {
51
+ func(...args);
52
+ lastRan = Date.now();
53
+ }
54
+ },
55
+ limit - (Date.now() - lastRan)
56
+ );
57
+ }
58
+ };
59
+ }
60
+
61
+ export function isValidEmail(email) {
62
+ if (!email || typeof email !== 'string') return false;
63
+
64
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
65
+ return emailRegex.test(email.trim());
66
+ }
67
+
68
+ export function sanitizeHTML(str) {
69
+ if (!str || typeof str !== 'string') return '';
70
+
71
+ const div = document.createElement('div');
72
+ div.textContent = str;
73
+ return div.innerHTML;
74
+ }
75
+
76
+ export function getCSSProperty(element, property, fallback = '') {
77
+ if (!element || !property) return fallback;
78
+
79
+ try {
80
+ const style = window.getComputedStyle(element);
81
+ return style.getPropertyValue(property) || fallback;
82
+ } catch (error) {
83
+ return fallback;
84
+ }
85
+ }
86
+
87
+ export function isInViewport(element) {
88
+ if (!element) return false;
89
+
90
+ const rect = element.getBoundingClientRect();
91
+ return (
92
+ rect.top >= 0 &&
93
+ rect.left >= 0 &&
94
+ rect.bottom <=
95
+ (window.innerHeight || document.documentElement.clientHeight) &&
96
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth)
97
+ );
98
+ }
99
+
100
+ export function scrollToElement(element, options = {}) {
101
+ if (!element) return;
102
+
103
+ const defaultOptions = {
104
+ behavior: 'smooth',
105
+ block: 'center',
106
+ inline: 'nearest',
107
+ };
108
+
109
+ element.scrollIntoView({ ...defaultOptions, ...options });
110
+ }
111
+
112
+ export function getBrowserInfo() {
113
+ const userAgent = navigator.userAgent;
114
+ const platform = navigator.platform;
115
+
116
+ return {
117
+ userAgent,
118
+ platform,
119
+ language: navigator.language || navigator.userLanguage,
120
+ cookieEnabled: navigator.cookieEnabled,
121
+ screenResolution: `${screen.width}x${screen.height}`,
122
+ windowSize: `${window.innerWidth}x${window.innerHeight}`,
123
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
124
+ };
125
+ }
126
+
127
+ export function formatFileSize(bytes) {
128
+ if (bytes === 0) return '0 Bytes';
129
+
130
+ const k = 1024;
131
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
132
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
133
+
134
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
135
+ }
136
+
137
+ export function delay(ms) {
138
+ return new Promise((resolve) => setTimeout(resolve, ms));
139
+ }
140
+
141
+ export function safeJsonParse(str, fallback = null) {
142
+ try {
143
+ return JSON.parse(str);
144
+ } catch (error) {
145
+ return fallback;
146
+ }
147
+ }
148
+
149
+ export function escapeRegex(string) {
150
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
151
+ }
152
+
153
+ export function getNestedProperty(obj, path, defaultValue = undefined) {
154
+ if (!obj || !path) return defaultValue;
155
+
156
+ const keys = path.split('.');
157
+ let current = obj;
158
+
159
+ for (const key of keys) {
160
+ if (current === null || current === undefined || !(key in current)) {
161
+ return defaultValue;
162
+ }
163
+ current = current[key];
164
+ }
165
+
166
+ return current;
167
+ }
168
+
169
+ export function setNestedProperty(obj, path, value) {
170
+ if (!obj || !path) return obj;
171
+
172
+ const keys = path.split('.');
173
+ const lastKey = keys.pop();
174
+ let current = obj;
175
+
176
+ for (const key of keys) {
177
+ if (!(key in current) || typeof current[key] !== 'object') {
178
+ current[key] = {};
179
+ }
180
+ current = current[key];
181
+ }
182
+
183
+ current[lastKey] = value;
184
+ return obj;
185
+ }
186
+
187
+ export function isBrowser() {
188
+ return typeof window !== 'undefined' && typeof document !== 'undefined';
189
+ }
190
+
191
+ export function isMobile() {
192
+ if (!isBrowser()) return false;
193
+
194
+ return (
195
+ /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
196
+ navigator.userAgent
197
+ ) || window.innerWidth <= 768
198
+ );
199
+ }
200
+
201
+ export function getCurrentTimestamp() {
202
+ return new Date().toISOString();
203
+ }
204
+
205
+ export function validateConfig(config, required = []) {
206
+ const missing = [];
207
+
208
+ for (const key of required) {
209
+ if (!config[key]) {
210
+ missing.push(key);
211
+ }
212
+ }
213
+
214
+ if (missing.length > 0) {
215
+ throw new Error(`Missing required configuration: ${missing.join(', ')}`);
216
+ }
217
+
218
+ return true;
219
+ }