@fluid-app/rep-sdk 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.
- package/README.md +413 -0
- package/dist/ContactsScreen-BYXF74BO.js +4 -0
- package/dist/ContactsScreen-BYXF74BO.js.map +1 -0
- package/dist/ContactsScreen-XZOQJVFE.cjs +17 -0
- package/dist/ContactsScreen-XZOQJVFE.cjs.map +1 -0
- package/dist/CustomersScreen-53SXRDDK.cjs +17 -0
- package/dist/CustomersScreen-53SXRDDK.cjs.map +1 -0
- package/dist/CustomersScreen-VS6LGULO.js +4 -0
- package/dist/CustomersScreen-VS6LGULO.js.map +1 -0
- package/dist/MessagingScreen-O42JEJMW.js +4 -0
- package/dist/MessagingScreen-O42JEJMW.js.map +1 -0
- package/dist/MessagingScreen-UCVLYWZB.cjs +17 -0
- package/dist/MessagingScreen-UCVLYWZB.cjs.map +1 -0
- package/dist/OrdersScreen-QQJFTTSS.js +4 -0
- package/dist/OrdersScreen-QQJFTTSS.js.map +1 -0
- package/dist/OrdersScreen-WNT2WDLI.cjs +17 -0
- package/dist/OrdersScreen-WNT2WDLI.cjs.map +1 -0
- package/dist/ProductsScreen-CTIAKS3Z.cjs +17 -0
- package/dist/ProductsScreen-CTIAKS3Z.cjs.map +1 -0
- package/dist/ProductsScreen-TRIT2FE3.js +4 -0
- package/dist/ProductsScreen-TRIT2FE3.js.map +1 -0
- package/dist/chunk-2AWTZV3T.js +16 -0
- package/dist/chunk-2AWTZV3T.js.map +1 -0
- package/dist/chunk-CXRJSGO6.js +16 -0
- package/dist/chunk-CXRJSGO6.js.map +1 -0
- package/dist/chunk-DEQ3PBVX.cjs +29 -0
- package/dist/chunk-DEQ3PBVX.cjs.map +1 -0
- package/dist/chunk-JZRNKSKT.cjs +19 -0
- package/dist/chunk-JZRNKSKT.cjs.map +1 -0
- package/dist/chunk-LO2HDG6C.js +26 -0
- package/dist/chunk-LO2HDG6C.js.map +1 -0
- package/dist/chunk-MBUCXIUN.cjs +19 -0
- package/dist/chunk-MBUCXIUN.cjs.map +1 -0
- package/dist/chunk-MEOOAMH2.cjs +19 -0
- package/dist/chunk-MEOOAMH2.cjs.map +1 -0
- package/dist/chunk-PJWPO4BJ.js +16 -0
- package/dist/chunk-PJWPO4BJ.js.map +1 -0
- package/dist/chunk-PZIHCYDD.js +16 -0
- package/dist/chunk-PZIHCYDD.js.map +1 -0
- package/dist/chunk-QUVJ3R4T.cjs +19 -0
- package/dist/chunk-QUVJ3R4T.cjs.map +1 -0
- package/dist/chunk-WH7WZXT6.js +16 -0
- package/dist/chunk-WH7WZXT6.js.map +1 -0
- package/dist/chunk-YII3IXF4.cjs +19 -0
- package/dist/chunk-YII3IXF4.cjs.map +1 -0
- package/dist/index.cjs +2446 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2164 -0
- package/dist/index.d.ts +2164 -0
- package/dist/index.js +2079 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2079 @@
|
|
|
1
|
+
export { MessagingScreen, messagingScreenPropertySchema } from './chunk-PJWPO4BJ.js';
|
|
2
|
+
export { ContactsScreen, contactsScreenPropertySchema } from './chunk-WH7WZXT6.js';
|
|
3
|
+
export { OrdersScreen, ordersScreenPropertySchema } from './chunk-PZIHCYDD.js';
|
|
4
|
+
export { CustomersScreen, customersScreenPropertySchema } from './chunk-CXRJSGO6.js';
|
|
5
|
+
export { ProductsScreen, productsScreenPropertySchema } from './chunk-2AWTZV3T.js';
|
|
6
|
+
import { __reExport } from './chunk-LO2HDG6C.js';
|
|
7
|
+
import { createContext, useState, useEffect, useCallback, useMemo, useContext, useRef } from 'react';
|
|
8
|
+
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';
|
|
9
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
10
|
+
import { decodeJwt, createRemoteJWKSet, jwtVerify } from 'jose';
|
|
11
|
+
export { WIDGET_TYPE_NAMES, assertDefined, assertNever, isWidgetType, isWidgetTypeName, sectionLayoutConfig } from '@fluid-app/rep-core/types';
|
|
12
|
+
import * as theme_star from '@fluid-app/rep-core/theme';
|
|
13
|
+
export { AlertWidget, CalendarWidget, CarouselWidget, CatchUpWidget, ChartWidget, ContainerWidget, EmbedWidget, ImageWidget, LayoutWidget, ListWidget, MySiteWidget, NestedWidget, QuickShareWidget, RecentActivityWidget, SpacerWidget, TableWidget, TextWidget, ToDoWidget, VideoWidget, alertWidgetPropertySchema, calendarWidgetPropertySchema, carouselWidgetPropertySchema, catchUpWidgetPropertySchema, chartWidgetPropertySchema, containerWidgetPropertySchema, embedWidgetPropertySchema, imageWidgetPropertySchema, layoutWidgetPropertySchema, listWidgetPropertySchema, mySiteWidgetPropertySchema, nestedWidgetPropertySchema, quickShareWidgetPropertySchema, recentActivityWidgetPropertySchema, spacerWidgetPropertySchema, tableWidgetPropertySchema, textWidgetPropertySchema, toDoWidgetPropertySchema, videoWidgetPropertySchema, widgetPropertySchemas } from '@fluid-app/rep-widgets/widgets';
|
|
14
|
+
export { createScreen, createWidgetFromShareable, createWidgetRegistry, groupChildrenByColumn } from '@fluid-app/rep-core/widget-utils';
|
|
15
|
+
export { PROPERTY_FIELD_TYPES, gapValues, isPropertyFieldType } from '@fluid-app/rep-core/registries';
|
|
16
|
+
|
|
17
|
+
// src/client/types.ts
|
|
18
|
+
var HTTP_METHODS = {
|
|
19
|
+
GET: "GET",
|
|
20
|
+
POST: "POST",
|
|
21
|
+
PUT: "PUT",
|
|
22
|
+
PATCH: "PATCH",
|
|
23
|
+
DELETE: "DELETE"
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// src/client/fluid-client.ts
|
|
27
|
+
var ApiError = class _ApiError extends Error {
|
|
28
|
+
status;
|
|
29
|
+
data;
|
|
30
|
+
constructor(message, status, data) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.name = "ApiError";
|
|
33
|
+
this.status = status;
|
|
34
|
+
this.data = data;
|
|
35
|
+
const errorWithCapture = Error;
|
|
36
|
+
if (errorWithCapture.captureStackTrace) {
|
|
37
|
+
errorWithCapture.captureStackTrace(this, _ApiError);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
toJSON() {
|
|
41
|
+
return {
|
|
42
|
+
name: this.name,
|
|
43
|
+
message: this.message,
|
|
44
|
+
status: this.status,
|
|
45
|
+
data: this.data
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
function isApiError(error) {
|
|
50
|
+
return error instanceof ApiError;
|
|
51
|
+
}
|
|
52
|
+
function isString(value) {
|
|
53
|
+
return typeof value === "string";
|
|
54
|
+
}
|
|
55
|
+
function extractErrorMessage(data, fallback) {
|
|
56
|
+
if ("message" in data && isString(data.message)) {
|
|
57
|
+
return data.message;
|
|
58
|
+
}
|
|
59
|
+
if ("error_message" in data && isString(data.error_message)) {
|
|
60
|
+
return data.error_message;
|
|
61
|
+
}
|
|
62
|
+
if ("error" in data && isString(data.error)) {
|
|
63
|
+
return data.error;
|
|
64
|
+
}
|
|
65
|
+
return fallback;
|
|
66
|
+
}
|
|
67
|
+
function createFluidClient(config) {
|
|
68
|
+
const { baseUrl, getAuthToken, onAuthError, defaultHeaders = {} } = config;
|
|
69
|
+
async function buildHeaders(customHeaders) {
|
|
70
|
+
const headers = {
|
|
71
|
+
"Content-Type": "application/json",
|
|
72
|
+
...defaultHeaders,
|
|
73
|
+
...customHeaders
|
|
74
|
+
};
|
|
75
|
+
if (getAuthToken) {
|
|
76
|
+
const token = await getAuthToken();
|
|
77
|
+
if (token) {
|
|
78
|
+
headers.Authorization = `Bearer ${token}`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return headers;
|
|
82
|
+
}
|
|
83
|
+
function buildUrl(endpoint, params) {
|
|
84
|
+
const normalizedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
85
|
+
const normalizedEndpoint = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
|
|
86
|
+
const url = new URL(normalizedBase + normalizedEndpoint);
|
|
87
|
+
if (params) {
|
|
88
|
+
for (const [key, value] of Object.entries(params)) {
|
|
89
|
+
if (value === void 0 || value === null) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (Array.isArray(value)) {
|
|
93
|
+
for (const item of value) {
|
|
94
|
+
url.searchParams.append(`${key}[]`, String(item));
|
|
95
|
+
}
|
|
96
|
+
} else if (typeof value === "object") {
|
|
97
|
+
for (const [subKey, subValue] of Object.entries(
|
|
98
|
+
value
|
|
99
|
+
)) {
|
|
100
|
+
if (subValue === void 0 || subValue === null) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (Array.isArray(subValue)) {
|
|
104
|
+
for (const item of subValue) {
|
|
105
|
+
url.searchParams.append(`${key}[${subKey}][]`, String(item));
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
url.searchParams.append(`${key}[${subKey}]`, String(subValue));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
url.searchParams.append(key, String(value));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return url.toString();
|
|
117
|
+
}
|
|
118
|
+
const defaultRequestOptions = {
|
|
119
|
+
method: HTTP_METHODS.GET
|
|
120
|
+
};
|
|
121
|
+
async function request(endpoint, options = {}) {
|
|
122
|
+
const {
|
|
123
|
+
method = defaultRequestOptions.method,
|
|
124
|
+
headers: customHeaders,
|
|
125
|
+
params,
|
|
126
|
+
body,
|
|
127
|
+
signal
|
|
128
|
+
} = options;
|
|
129
|
+
const url = buildUrl(
|
|
130
|
+
endpoint,
|
|
131
|
+
method === HTTP_METHODS.GET ? params : void 0
|
|
132
|
+
);
|
|
133
|
+
const headers = await buildHeaders(customHeaders);
|
|
134
|
+
let response;
|
|
135
|
+
try {
|
|
136
|
+
const fetchOptions = {
|
|
137
|
+
method,
|
|
138
|
+
headers
|
|
139
|
+
};
|
|
140
|
+
if (signal !== void 0) {
|
|
141
|
+
fetchOptions.signal = signal;
|
|
142
|
+
}
|
|
143
|
+
if (body && method !== HTTP_METHODS.GET) {
|
|
144
|
+
fetchOptions.body = JSON.stringify(body);
|
|
145
|
+
}
|
|
146
|
+
response = await fetch(url, fetchOptions);
|
|
147
|
+
} catch (networkError) {
|
|
148
|
+
throw new ApiError(
|
|
149
|
+
`Network error: ${networkError instanceof Error ? networkError.message : "Unknown network error"}`,
|
|
150
|
+
0,
|
|
151
|
+
null
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (response.status === 401 && onAuthError) {
|
|
155
|
+
onAuthError();
|
|
156
|
+
}
|
|
157
|
+
if (!response.ok) {
|
|
158
|
+
try {
|
|
159
|
+
const contentType = response.headers.get("content-type");
|
|
160
|
+
if (contentType?.includes("application/json")) {
|
|
161
|
+
const data = await response.json();
|
|
162
|
+
const errorMessage = extractErrorMessage(
|
|
163
|
+
data,
|
|
164
|
+
`${method} request failed`
|
|
165
|
+
);
|
|
166
|
+
throw new ApiError(
|
|
167
|
+
errorMessage,
|
|
168
|
+
response.status,
|
|
169
|
+
"errors" in data ? data.errors : data
|
|
170
|
+
);
|
|
171
|
+
} else {
|
|
172
|
+
throw new ApiError(
|
|
173
|
+
`${method} request failed with status ${response.status}`,
|
|
174
|
+
response.status,
|
|
175
|
+
null
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
} catch (error) {
|
|
179
|
+
if (isApiError(error)) {
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
throw new ApiError(
|
|
183
|
+
`${method} request failed with status ${response.status}`,
|
|
184
|
+
response.status,
|
|
185
|
+
null
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (response.status === 204 || response.headers.get("content-length") === "0") {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
const data = await response.json();
|
|
194
|
+
if (data === null || data === void 0) {
|
|
195
|
+
throw new ApiError(
|
|
196
|
+
"Unexpected null/undefined in JSON response",
|
|
197
|
+
response.status,
|
|
198
|
+
null
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
return data;
|
|
202
|
+
} catch (parseError) {
|
|
203
|
+
if (isApiError(parseError)) {
|
|
204
|
+
throw parseError;
|
|
205
|
+
}
|
|
206
|
+
throw new ApiError(
|
|
207
|
+
"Failed to parse response as JSON",
|
|
208
|
+
response.status,
|
|
209
|
+
null
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function requestNullable(endpoint, options = {}) {
|
|
214
|
+
return request(endpoint, options);
|
|
215
|
+
}
|
|
216
|
+
async function safeRequest(endpoint, options = {}) {
|
|
217
|
+
try {
|
|
218
|
+
const data = await request(endpoint, options);
|
|
219
|
+
return { success: true, data };
|
|
220
|
+
} catch (error) {
|
|
221
|
+
if (isApiError(error)) {
|
|
222
|
+
return { success: false, error };
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
success: false,
|
|
226
|
+
error: new ApiError(
|
|
227
|
+
error instanceof Error ? error.message : "Unknown error",
|
|
228
|
+
0,
|
|
229
|
+
null
|
|
230
|
+
)
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function toParams(params) {
|
|
235
|
+
return params;
|
|
236
|
+
}
|
|
237
|
+
const get = (endpoint, params, options) => {
|
|
238
|
+
const baseOptions = {
|
|
239
|
+
...options,
|
|
240
|
+
method: HTTP_METHODS.GET
|
|
241
|
+
};
|
|
242
|
+
const convertedParams = toParams(params);
|
|
243
|
+
const requestOptions = convertedParams !== void 0 ? { ...baseOptions, params: convertedParams } : baseOptions;
|
|
244
|
+
return request(endpoint, requestOptions);
|
|
245
|
+
};
|
|
246
|
+
const post = (endpoint, body, options) => request(endpoint, {
|
|
247
|
+
...options,
|
|
248
|
+
method: HTTP_METHODS.POST,
|
|
249
|
+
body
|
|
250
|
+
});
|
|
251
|
+
const put = (endpoint, body, options) => request(endpoint, {
|
|
252
|
+
...options,
|
|
253
|
+
method: HTTP_METHODS.PUT,
|
|
254
|
+
body
|
|
255
|
+
});
|
|
256
|
+
const patch = (endpoint, body, options) => request(endpoint, {
|
|
257
|
+
...options,
|
|
258
|
+
method: HTTP_METHODS.PATCH,
|
|
259
|
+
body
|
|
260
|
+
});
|
|
261
|
+
const del = (endpoint, options) => request(endpoint, {
|
|
262
|
+
...options,
|
|
263
|
+
method: HTTP_METHODS.DELETE
|
|
264
|
+
});
|
|
265
|
+
return {
|
|
266
|
+
// Low-level methods for custom endpoints
|
|
267
|
+
request,
|
|
268
|
+
requestNullable,
|
|
269
|
+
safeRequest,
|
|
270
|
+
get,
|
|
271
|
+
post,
|
|
272
|
+
put,
|
|
273
|
+
patch,
|
|
274
|
+
delete: del,
|
|
275
|
+
// Products API - matches fluid-admin's /company/v1/products
|
|
276
|
+
products: {
|
|
277
|
+
list: (params) => get(
|
|
278
|
+
"/company/v1/products",
|
|
279
|
+
params
|
|
280
|
+
),
|
|
281
|
+
get: (id) => get(`/company/v1/products/${id}`),
|
|
282
|
+
search: (query, params) => get("/company/v1/products", {
|
|
283
|
+
search_query: query,
|
|
284
|
+
...params
|
|
285
|
+
})
|
|
286
|
+
},
|
|
287
|
+
// Orders API
|
|
288
|
+
orders: {
|
|
289
|
+
list: (params) => get("/orders", params),
|
|
290
|
+
get: (id) => get(`/orders/${id}`),
|
|
291
|
+
create: (data) => post("/orders", data)
|
|
292
|
+
},
|
|
293
|
+
// Reps API
|
|
294
|
+
reps: {
|
|
295
|
+
current: () => get("/reps/me"),
|
|
296
|
+
updateProfile: (data) => patch("/reps/me", data)
|
|
297
|
+
},
|
|
298
|
+
// Profile API (themes, navigation, screens)
|
|
299
|
+
profile: {
|
|
300
|
+
get: () => get("/rep_app/manifest")
|
|
301
|
+
},
|
|
302
|
+
// Permissions API
|
|
303
|
+
permissions: {
|
|
304
|
+
get: () => get("/company/roles/my_permissions")
|
|
305
|
+
},
|
|
306
|
+
// Analytics API
|
|
307
|
+
analytics: {
|
|
308
|
+
dashboard: () => get("/analytics/dashboard"),
|
|
309
|
+
sales: (params) => get("/analytics/sales", params)
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
var ThemeContext = createContext(null);
|
|
314
|
+
function applyThemeVariables(theme, container) {
|
|
315
|
+
const target = container ?? document.documentElement;
|
|
316
|
+
for (const [key, value] of Object.entries(theme.config)) {
|
|
317
|
+
target.style.setProperty(`--fluid-${key}`, value);
|
|
318
|
+
}
|
|
319
|
+
if (theme.mode) {
|
|
320
|
+
target.dataset.fluidThemeMode = theme.mode;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function FluidThemeProvider({
|
|
324
|
+
children,
|
|
325
|
+
initialTheme,
|
|
326
|
+
container
|
|
327
|
+
}) {
|
|
328
|
+
const [currentTheme, setCurrentTheme] = useState(
|
|
329
|
+
initialTheme ?? null
|
|
330
|
+
);
|
|
331
|
+
useEffect(() => {
|
|
332
|
+
if (currentTheme) {
|
|
333
|
+
applyThemeVariables(currentTheme, container ?? null);
|
|
334
|
+
}
|
|
335
|
+
}, [currentTheme, container]);
|
|
336
|
+
const setTheme = useCallback((theme) => {
|
|
337
|
+
setCurrentTheme(theme);
|
|
338
|
+
}, []);
|
|
339
|
+
const setThemeMode = useCallback((mode) => {
|
|
340
|
+
setCurrentTheme((prev) => prev ? { ...prev, mode } : null);
|
|
341
|
+
}, []);
|
|
342
|
+
const value = useMemo(
|
|
343
|
+
() => ({
|
|
344
|
+
currentTheme,
|
|
345
|
+
setTheme,
|
|
346
|
+
setThemeMode
|
|
347
|
+
}),
|
|
348
|
+
[currentTheme, setTheme, setThemeMode]
|
|
349
|
+
);
|
|
350
|
+
return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children });
|
|
351
|
+
}
|
|
352
|
+
function useThemeContext() {
|
|
353
|
+
const context = useContext(ThemeContext);
|
|
354
|
+
if (!context) {
|
|
355
|
+
throw new Error("useThemeContext must be used within a FluidThemeProvider");
|
|
356
|
+
}
|
|
357
|
+
return context;
|
|
358
|
+
}
|
|
359
|
+
var FluidContext = createContext(null);
|
|
360
|
+
function FluidProvider({
|
|
361
|
+
config,
|
|
362
|
+
children,
|
|
363
|
+
queryClient,
|
|
364
|
+
initialTheme,
|
|
365
|
+
themeContainer
|
|
366
|
+
}) {
|
|
367
|
+
const defaultQueryClient = useMemo(
|
|
368
|
+
() => new QueryClient({
|
|
369
|
+
defaultOptions: {
|
|
370
|
+
queries: {
|
|
371
|
+
staleTime: 1e3 * 60,
|
|
372
|
+
// 1 minute
|
|
373
|
+
retry: 1
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}),
|
|
377
|
+
[]
|
|
378
|
+
);
|
|
379
|
+
const configRef = useRef(config);
|
|
380
|
+
configRef.current = config;
|
|
381
|
+
const client = useMemo(
|
|
382
|
+
() => createFluidClient(configRef.current),
|
|
383
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
384
|
+
[config.baseUrl]
|
|
385
|
+
);
|
|
386
|
+
const contextValue = useMemo(
|
|
387
|
+
() => ({ client, config: configRef.current }),
|
|
388
|
+
[client]
|
|
389
|
+
);
|
|
390
|
+
const themeProviderProps = {
|
|
391
|
+
...initialTheme !== void 0 && { initialTheme },
|
|
392
|
+
...themeContainer !== void 0 && { container: themeContainer }
|
|
393
|
+
};
|
|
394
|
+
return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient ?? defaultQueryClient, children: /* @__PURE__ */ jsx(FluidContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(FluidThemeProvider, { ...themeProviderProps, children }) }) });
|
|
395
|
+
}
|
|
396
|
+
function useFluidContext() {
|
|
397
|
+
const context = useContext(FluidContext);
|
|
398
|
+
if (!context) {
|
|
399
|
+
throw new Error("useFluidContext must be used within a FluidProvider");
|
|
400
|
+
}
|
|
401
|
+
return context;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// src/auth/constants.ts
|
|
405
|
+
var AUTH_CONSTANTS = {
|
|
406
|
+
/**
|
|
407
|
+
* Grace period in milliseconds to account for clock skew
|
|
408
|
+
* when checking token expiration. Tokens are considered valid
|
|
409
|
+
* if they expire within this period.
|
|
410
|
+
*/
|
|
411
|
+
TOKEN_GRACE_PERIOD_MS: 30 * 1e3,
|
|
412
|
+
// 30 seconds
|
|
413
|
+
/**
|
|
414
|
+
* Default cookie max age in seconds (9 days).
|
|
415
|
+
* This matches the typical JWT token lifetime from the Fluid API.
|
|
416
|
+
*/
|
|
417
|
+
COOKIE_MAX_AGE: 9 * 24 * 60 * 60
|
|
418
|
+
// 9 days = 777600 seconds
|
|
419
|
+
};
|
|
420
|
+
var STORAGE_KEYS = {
|
|
421
|
+
/** localStorage key for user token */
|
|
422
|
+
USER_TOKEN: "fluidUserToken",
|
|
423
|
+
/** localStorage key for company token (legacy) */
|
|
424
|
+
COMPANY_TOKEN: "fluidCompanyToken",
|
|
425
|
+
/** Cookie name for auth token */
|
|
426
|
+
AUTH_COOKIE: "auth_token"
|
|
427
|
+
};
|
|
428
|
+
var URL_PARAMS = {
|
|
429
|
+
/** URL parameter name for user token */
|
|
430
|
+
USER_TOKEN: "fluidUserToken",
|
|
431
|
+
/** URL parameter name for company token (legacy) */
|
|
432
|
+
COMPANY_TOKEN: "fluidCompanyToken"
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
// src/auth/url-token.ts
|
|
436
|
+
function isBrowser() {
|
|
437
|
+
return typeof window !== "undefined";
|
|
438
|
+
}
|
|
439
|
+
function extractTokenFromUrl(tokenKey = URL_PARAMS.USER_TOKEN) {
|
|
440
|
+
if (!isBrowser()) {
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
try {
|
|
444
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
445
|
+
return searchParams.get(tokenKey);
|
|
446
|
+
} catch {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
function extractCompanyTokenFromUrl(tokenKey = URL_PARAMS.COMPANY_TOKEN) {
|
|
451
|
+
if (!isBrowser()) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
456
|
+
return searchParams.get(tokenKey);
|
|
457
|
+
} catch {
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
function cleanTokenFromUrl(tokenKey = URL_PARAMS.USER_TOKEN) {
|
|
462
|
+
if (!isBrowser()) {
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
try {
|
|
466
|
+
const url = new URL(window.location.href);
|
|
467
|
+
const hadToken = url.searchParams.has(tokenKey);
|
|
468
|
+
const hadCompanyToken = url.searchParams.has(URL_PARAMS.COMPANY_TOKEN);
|
|
469
|
+
url.searchParams.delete(tokenKey);
|
|
470
|
+
url.searchParams.delete(URL_PARAMS.COMPANY_TOKEN);
|
|
471
|
+
if (hadToken || hadCompanyToken) {
|
|
472
|
+
window.history.replaceState(
|
|
473
|
+
window.history.state,
|
|
474
|
+
document.title,
|
|
475
|
+
url.toString()
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
} catch (error) {
|
|
479
|
+
console.warn("[FluidAuth] Failed to clean token from URL:", error);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
function hasTokenInUrl(tokenKey = URL_PARAMS.USER_TOKEN) {
|
|
483
|
+
if (!isBrowser()) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
try {
|
|
487
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
488
|
+
return searchParams.has(tokenKey);
|
|
489
|
+
} catch {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
function extractAllTokensFromUrl(userTokenKey = URL_PARAMS.USER_TOKEN, companyTokenKey = URL_PARAMS.COMPANY_TOKEN) {
|
|
494
|
+
if (!isBrowser()) {
|
|
495
|
+
return { userToken: null, companyToken: null };
|
|
496
|
+
}
|
|
497
|
+
try {
|
|
498
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
499
|
+
return {
|
|
500
|
+
userToken: searchParams.get(userTokenKey),
|
|
501
|
+
companyToken: searchParams.get(companyTokenKey)
|
|
502
|
+
};
|
|
503
|
+
} catch {
|
|
504
|
+
return { userToken: null, companyToken: null };
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/auth/token-storage.ts
|
|
509
|
+
function isBrowser2() {
|
|
510
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
511
|
+
}
|
|
512
|
+
function parseCookies() {
|
|
513
|
+
if (!isBrowser2()) {
|
|
514
|
+
return {};
|
|
515
|
+
}
|
|
516
|
+
const cookies = {};
|
|
517
|
+
const cookieString = document.cookie;
|
|
518
|
+
if (!cookieString) {
|
|
519
|
+
return cookies;
|
|
520
|
+
}
|
|
521
|
+
cookieString.split(";").forEach((cookie) => {
|
|
522
|
+
const [name, ...valueParts] = cookie.trim().split("=");
|
|
523
|
+
if (name) {
|
|
524
|
+
cookies[name] = decodeURIComponent(valueParts.join("="));
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
return cookies;
|
|
528
|
+
}
|
|
529
|
+
function setCookie(name, value, options = {}) {
|
|
530
|
+
if (!isBrowser2()) {
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
const {
|
|
534
|
+
maxAge = AUTH_CONSTANTS.COOKIE_MAX_AGE,
|
|
535
|
+
path = "/",
|
|
536
|
+
sameSite = "lax",
|
|
537
|
+
secure = window.location.protocol === "https:"
|
|
538
|
+
} = options;
|
|
539
|
+
let cookieString = `${name}=${encodeURIComponent(value)}`;
|
|
540
|
+
cookieString += `; path=${path}`;
|
|
541
|
+
cookieString += `; max-age=${maxAge}`;
|
|
542
|
+
cookieString += `; samesite=${sameSite}`;
|
|
543
|
+
if (secure) {
|
|
544
|
+
cookieString += "; secure";
|
|
545
|
+
}
|
|
546
|
+
document.cookie = cookieString;
|
|
547
|
+
}
|
|
548
|
+
function deleteCookie(name, path = "/") {
|
|
549
|
+
if (!isBrowser2()) {
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
document.cookie = `${name}=; path=${path}; max-age=0`;
|
|
553
|
+
}
|
|
554
|
+
function getStoredToken(config) {
|
|
555
|
+
if (!isBrowser2()) {
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
const cookieKey = config?.cookieKey ?? STORAGE_KEYS.AUTH_COOKIE;
|
|
559
|
+
const localStorageKey = STORAGE_KEYS.USER_TOKEN;
|
|
560
|
+
const cookies = parseCookies();
|
|
561
|
+
const cookieToken = cookies[cookieKey];
|
|
562
|
+
if (cookieToken) {
|
|
563
|
+
return cookieToken;
|
|
564
|
+
}
|
|
565
|
+
try {
|
|
566
|
+
return localStorage.getItem(localStorageKey);
|
|
567
|
+
} catch {
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
function storeToken(token, config) {
|
|
572
|
+
if (!isBrowser2()) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
const cookieKey = config?.cookieKey ?? STORAGE_KEYS.AUTH_COOKIE;
|
|
576
|
+
const maxAge = config?.cookieMaxAge ?? AUTH_CONSTANTS.COOKIE_MAX_AGE;
|
|
577
|
+
try {
|
|
578
|
+
setCookie(cookieKey, token, {
|
|
579
|
+
maxAge,
|
|
580
|
+
path: "/",
|
|
581
|
+
// Use 'none' with secure for cross-origin iframe scenarios
|
|
582
|
+
sameSite: window.self !== window.top ? "none" : "lax",
|
|
583
|
+
secure: window.location.protocol === "https:"
|
|
584
|
+
});
|
|
585
|
+
} catch (error) {
|
|
586
|
+
console.warn("[FluidAuth] Failed to store token in cookie:", error);
|
|
587
|
+
}
|
|
588
|
+
try {
|
|
589
|
+
localStorage.setItem(STORAGE_KEYS.USER_TOKEN, token);
|
|
590
|
+
} catch (error) {
|
|
591
|
+
console.warn("[FluidAuth] Failed to store token in localStorage:", error);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
function clearTokens(config) {
|
|
595
|
+
if (!isBrowser2()) {
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
const cookieKey = config?.cookieKey ?? STORAGE_KEYS.AUTH_COOKIE;
|
|
599
|
+
try {
|
|
600
|
+
deleteCookie(cookieKey);
|
|
601
|
+
} catch {
|
|
602
|
+
}
|
|
603
|
+
try {
|
|
604
|
+
localStorage.removeItem(STORAGE_KEYS.USER_TOKEN);
|
|
605
|
+
localStorage.removeItem(STORAGE_KEYS.COMPANY_TOKEN);
|
|
606
|
+
} catch {
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
function hasStoredToken(config) {
|
|
610
|
+
return getStoredToken(config) !== null;
|
|
611
|
+
}
|
|
612
|
+
function extractPayloadFromJose(decoded) {
|
|
613
|
+
return {
|
|
614
|
+
id: decoded.id,
|
|
615
|
+
email: decoded.email,
|
|
616
|
+
full_name: decoded.full_name,
|
|
617
|
+
user_type: decoded.user_type ?? "rep",
|
|
618
|
+
og_user_type: decoded.og_user_type,
|
|
619
|
+
company_id: decoded.company_id,
|
|
620
|
+
exp: decoded.exp,
|
|
621
|
+
auth_type: decoded.auth_type
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
function decodeToken(token) {
|
|
625
|
+
try {
|
|
626
|
+
const decoded = decodeJwt(token);
|
|
627
|
+
return extractPayloadFromJose(decoded);
|
|
628
|
+
} catch (error) {
|
|
629
|
+
console.error("[FluidAuth] Failed to decode JWT token:", error);
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
function isTokenExpired(token, gracePeriodMs = AUTH_CONSTANTS.TOKEN_GRACE_PERIOD_MS) {
|
|
634
|
+
try {
|
|
635
|
+
const decoded = decodeJwt(token);
|
|
636
|
+
if (!decoded.exp) {
|
|
637
|
+
return false;
|
|
638
|
+
}
|
|
639
|
+
const expirationTime = decoded.exp * 1e3;
|
|
640
|
+
const currentTime = Date.now();
|
|
641
|
+
return currentTime > expirationTime + gracePeriodMs;
|
|
642
|
+
} catch {
|
|
643
|
+
return true;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
function validateToken(token, gracePeriodMs = AUTH_CONSTANTS.TOKEN_GRACE_PERIOD_MS) {
|
|
647
|
+
if (!token || token.trim() === "") {
|
|
648
|
+
return {
|
|
649
|
+
isValid: false,
|
|
650
|
+
error: "Token is empty or not provided"
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
const payload = decodeToken(token);
|
|
654
|
+
if (!payload) {
|
|
655
|
+
return {
|
|
656
|
+
isValid: false,
|
|
657
|
+
error: "Token has invalid format"
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
if (isTokenExpired(token, gracePeriodMs)) {
|
|
661
|
+
return {
|
|
662
|
+
isValid: false,
|
|
663
|
+
payload,
|
|
664
|
+
error: "Token has expired"
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
return {
|
|
668
|
+
isValid: true,
|
|
669
|
+
payload
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
function isValidToken(result) {
|
|
673
|
+
return result.isValid === true;
|
|
674
|
+
}
|
|
675
|
+
function getTokenExpiration(token) {
|
|
676
|
+
try {
|
|
677
|
+
const decoded = decodeJwt(token);
|
|
678
|
+
if (!decoded.exp) {
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
return new Date(decoded.exp * 1e3);
|
|
682
|
+
} catch {
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
function getTokenTimeRemaining(token) {
|
|
687
|
+
try {
|
|
688
|
+
const decoded = decodeJwt(token);
|
|
689
|
+
if (!decoded.exp) {
|
|
690
|
+
return Infinity;
|
|
691
|
+
}
|
|
692
|
+
const expirationTime = decoded.exp * 1e3;
|
|
693
|
+
const remaining = expirationTime - Date.now();
|
|
694
|
+
return Math.max(0, remaining);
|
|
695
|
+
} catch {
|
|
696
|
+
return 0;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
async function verifyToken(token, jwksUrl) {
|
|
700
|
+
try {
|
|
701
|
+
const JWKS = createRemoteJWKSet(new URL(jwksUrl));
|
|
702
|
+
const { payload } = await jwtVerify(token, JWKS);
|
|
703
|
+
const decoded = payload;
|
|
704
|
+
return extractPayloadFromJose(decoded);
|
|
705
|
+
} catch (error) {
|
|
706
|
+
console.error("[FluidAuth] JWT signature verification failed:", error);
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// src/auth/types.ts
|
|
712
|
+
var USER_TYPES = {
|
|
713
|
+
admin: "admin",
|
|
714
|
+
rep: "rep",
|
|
715
|
+
root_admin: "root_admin",
|
|
716
|
+
customer: "customer"
|
|
717
|
+
};
|
|
718
|
+
function isUserType(value) {
|
|
719
|
+
return Object.values(USER_TYPES).includes(value);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// src/auth/dev-utils.ts
|
|
723
|
+
function isDevBypassActive(devBypass) {
|
|
724
|
+
if (!devBypass) return false;
|
|
725
|
+
try {
|
|
726
|
+
return import.meta.env.DEV === true;
|
|
727
|
+
} catch {
|
|
728
|
+
return false;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
function createDevUser() {
|
|
732
|
+
return {
|
|
733
|
+
id: 0,
|
|
734
|
+
email: "dev@localhost",
|
|
735
|
+
full_name: "Dev User",
|
|
736
|
+
user_type: USER_TYPES.rep,
|
|
737
|
+
og_user_type: void 0,
|
|
738
|
+
company_id: 0,
|
|
739
|
+
exp: void 0,
|
|
740
|
+
// Never expires
|
|
741
|
+
auth_type: "dev_bypass"
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
var FluidAuthContext = createContext(null);
|
|
745
|
+
function FluidAuthProvider({
|
|
746
|
+
children,
|
|
747
|
+
config
|
|
748
|
+
}) {
|
|
749
|
+
const configRef = useRef(config);
|
|
750
|
+
configRef.current = config;
|
|
751
|
+
const [isLoading2, setIsLoading] = useState(true);
|
|
752
|
+
const [token, setToken] = useState(null);
|
|
753
|
+
const [user, setUser] = useState(null);
|
|
754
|
+
const [error, setError] = useState(null);
|
|
755
|
+
useEffect(() => {
|
|
756
|
+
const initializeAuth = async () => {
|
|
757
|
+
try {
|
|
758
|
+
if (isDevBypassActive(config?.devBypass)) {
|
|
759
|
+
const envToken = import.meta.env.VITE_DEV_TOKEN;
|
|
760
|
+
if (envToken) {
|
|
761
|
+
const validation = validateToken(envToken, config?.gracePeriodMs);
|
|
762
|
+
if (validation.isValid && validation.payload) {
|
|
763
|
+
storeToken(envToken, config);
|
|
764
|
+
setToken(envToken);
|
|
765
|
+
setUser(validation.payload);
|
|
766
|
+
setError(null);
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
console.warn(
|
|
770
|
+
"[FluidAuth] VITE_DEV_TOKEN is invalid or expired, falling back to mock user"
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
console.warn(
|
|
774
|
+
"[FluidAuth] Dev bypass active - using mock user. API calls will fail without a real token."
|
|
775
|
+
);
|
|
776
|
+
const devUser = createDevUser();
|
|
777
|
+
setToken(null);
|
|
778
|
+
setUser(devUser);
|
|
779
|
+
setError(null);
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
const tokenKey = config?.tokenKey ?? "fluidUserToken";
|
|
783
|
+
let candidateToken = extractTokenFromUrl(tokenKey);
|
|
784
|
+
cleanTokenFromUrl(tokenKey);
|
|
785
|
+
if (!candidateToken) {
|
|
786
|
+
candidateToken = getStoredToken(config);
|
|
787
|
+
}
|
|
788
|
+
if (candidateToken) {
|
|
789
|
+
let payload = null;
|
|
790
|
+
if (config?.jwksUrl) {
|
|
791
|
+
payload = await verifyToken(candidateToken, config.jwksUrl);
|
|
792
|
+
if (!payload) {
|
|
793
|
+
clearTokens(config);
|
|
794
|
+
setToken(null);
|
|
795
|
+
setUser(null);
|
|
796
|
+
setError(new Error("JWT signature verification failed"));
|
|
797
|
+
config?.onAuthFailure?.();
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
if (isTokenExpired(candidateToken, config?.gracePeriodMs)) {
|
|
801
|
+
clearTokens(config);
|
|
802
|
+
setToken(null);
|
|
803
|
+
setUser(null);
|
|
804
|
+
setError(new Error("Token has expired"));
|
|
805
|
+
config?.onAuthFailure?.();
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
} else {
|
|
809
|
+
const validation = validateToken(
|
|
810
|
+
candidateToken,
|
|
811
|
+
config?.gracePeriodMs
|
|
812
|
+
);
|
|
813
|
+
if (validation.isValid && validation.payload) {
|
|
814
|
+
payload = validation.payload;
|
|
815
|
+
} else {
|
|
816
|
+
clearTokens(config);
|
|
817
|
+
setToken(null);
|
|
818
|
+
setUser(null);
|
|
819
|
+
setError(new Error(validation.error ?? "Invalid token"));
|
|
820
|
+
config?.onAuthFailure?.();
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
storeToken(candidateToken, config);
|
|
825
|
+
setToken(candidateToken);
|
|
826
|
+
setUser(payload);
|
|
827
|
+
setError(null);
|
|
828
|
+
} else {
|
|
829
|
+
setToken(null);
|
|
830
|
+
setUser(null);
|
|
831
|
+
setError(new Error("No authentication token found"));
|
|
832
|
+
config?.onAuthFailure?.();
|
|
833
|
+
}
|
|
834
|
+
} catch (err) {
|
|
835
|
+
const error2 = err instanceof Error ? err : new Error("Authentication error");
|
|
836
|
+
setError(error2);
|
|
837
|
+
setToken(null);
|
|
838
|
+
setUser(null);
|
|
839
|
+
config?.onAuthFailure?.();
|
|
840
|
+
} finally {
|
|
841
|
+
setIsLoading(false);
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
void initializeAuth();
|
|
845
|
+
}, []);
|
|
846
|
+
const clearAuth = useCallback(() => {
|
|
847
|
+
clearTokens(configRef.current);
|
|
848
|
+
setToken(null);
|
|
849
|
+
setUser(null);
|
|
850
|
+
setError(null);
|
|
851
|
+
}, []);
|
|
852
|
+
const contextValue = useMemo(
|
|
853
|
+
() => ({
|
|
854
|
+
isAuthenticated: user !== null,
|
|
855
|
+
isLoading: isLoading2,
|
|
856
|
+
user,
|
|
857
|
+
token,
|
|
858
|
+
clearAuth,
|
|
859
|
+
error
|
|
860
|
+
}),
|
|
861
|
+
[token, isLoading2, user, clearAuth, error]
|
|
862
|
+
);
|
|
863
|
+
return /* @__PURE__ */ jsx(FluidAuthContext.Provider, { value: contextValue, children });
|
|
864
|
+
}
|
|
865
|
+
function useFluidAuthContext() {
|
|
866
|
+
const context = useContext(FluidAuthContext);
|
|
867
|
+
if (!context) {
|
|
868
|
+
throw new Error(
|
|
869
|
+
"useFluidAuthContext must be used within a FluidAuthProvider. Wrap your app with <FluidAuthProvider> to use authentication features."
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
return context;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// src/types/page-template.ts
|
|
876
|
+
var PAGE_CATEGORIES = {
|
|
877
|
+
CORE: "core",
|
|
878
|
+
COMMERCE: "commerce",
|
|
879
|
+
COMMUNICATION: "communication",
|
|
880
|
+
DATA: "data",
|
|
881
|
+
CUSTOM: "custom"
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
// src/registries/page-template-registry.ts
|
|
885
|
+
var PageTemplateRegistryImpl = class {
|
|
886
|
+
templates = /* @__PURE__ */ new Map();
|
|
887
|
+
categories = [];
|
|
888
|
+
constructor() {
|
|
889
|
+
this.categories = [
|
|
890
|
+
{ id: PAGE_CATEGORIES.CORE, label: "Core Features", icon: "star" },
|
|
891
|
+
{
|
|
892
|
+
id: PAGE_CATEGORIES.COMMERCE,
|
|
893
|
+
label: "Commerce",
|
|
894
|
+
icon: "shopping-cart"
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
id: PAGE_CATEGORIES.COMMUNICATION,
|
|
898
|
+
label: "Communication",
|
|
899
|
+
icon: "message-circle"
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
id: PAGE_CATEGORIES.DATA,
|
|
903
|
+
label: "Data & Analytics",
|
|
904
|
+
icon: "bar-chart"
|
|
905
|
+
},
|
|
906
|
+
{ id: PAGE_CATEGORIES.CUSTOM, label: "Custom", icon: "puzzle" }
|
|
907
|
+
];
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Register a new page template.
|
|
911
|
+
* @throws Error if a template with the same ID already exists
|
|
912
|
+
*/
|
|
913
|
+
register(template) {
|
|
914
|
+
if (this.templates.has(template.id)) {
|
|
915
|
+
throw new Error(
|
|
916
|
+
`Page template with ID "${template.id}" is already registered`
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
this.templates.set(template.id, template);
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Unregister a page template by ID.
|
|
923
|
+
* Core templates cannot be unregistered.
|
|
924
|
+
* @returns true if the template was removed, false if it didn't exist or is a core template
|
|
925
|
+
*/
|
|
926
|
+
unregister(id) {
|
|
927
|
+
const template = this.templates.get(id);
|
|
928
|
+
if (!template) {
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
if (template.isCore) {
|
|
932
|
+
console.warn(
|
|
933
|
+
`Cannot unregister core page template "${id}". Core templates are required.`
|
|
934
|
+
);
|
|
935
|
+
return false;
|
|
936
|
+
}
|
|
937
|
+
return this.templates.delete(id);
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Get a page template by ID.
|
|
941
|
+
*/
|
|
942
|
+
get(id) {
|
|
943
|
+
return this.templates.get(id);
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Get all page templates in a specific category.
|
|
947
|
+
*/
|
|
948
|
+
getByCategory(category) {
|
|
949
|
+
return Array.from(this.templates.values()).filter(
|
|
950
|
+
(t) => t.category === category
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* List all registered page templates.
|
|
955
|
+
*/
|
|
956
|
+
listAll() {
|
|
957
|
+
return Array.from(this.templates.values());
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* List all core page templates (isCore: true).
|
|
961
|
+
*/
|
|
962
|
+
listCore() {
|
|
963
|
+
return Array.from(this.templates.values()).filter((t) => t.isCore);
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* List all non-core page templates.
|
|
967
|
+
*/
|
|
968
|
+
listOptional() {
|
|
969
|
+
return Array.from(this.templates.values()).filter((t) => !t.isCore);
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* List all registered categories.
|
|
973
|
+
*/
|
|
974
|
+
listCategories() {
|
|
975
|
+
return [...this.categories];
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Add a custom category.
|
|
979
|
+
*/
|
|
980
|
+
addCategory(category) {
|
|
981
|
+
if (this.categories.some((c) => c.id === category.id)) {
|
|
982
|
+
console.warn(`Category with ID "${category.id}" already exists`);
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
this.categories.push(category);
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Check if a template exists by ID.
|
|
989
|
+
*/
|
|
990
|
+
has(id) {
|
|
991
|
+
return this.templates.has(id);
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Get the count of registered templates.
|
|
995
|
+
*/
|
|
996
|
+
get size() {
|
|
997
|
+
return this.templates.size;
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Clear all non-core templates.
|
|
1001
|
+
* Useful for testing or resetting the registry.
|
|
1002
|
+
*/
|
|
1003
|
+
clearNonCore() {
|
|
1004
|
+
for (const [id, template] of this.templates) {
|
|
1005
|
+
if (!template.isCore) {
|
|
1006
|
+
this.templates.delete(id);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
var PageTemplateRegistry = new PageTemplateRegistryImpl();
|
|
1012
|
+
|
|
1013
|
+
// src/core/resolve-pages.ts
|
|
1014
|
+
function applyOverrides(componentTree, overrides) {
|
|
1015
|
+
if (!overrides.length) {
|
|
1016
|
+
return [...componentTree];
|
|
1017
|
+
}
|
|
1018
|
+
const overrideMap = new Map(overrides.map((o) => [o.widget_id, o.props]));
|
|
1019
|
+
return componentTree.map(
|
|
1020
|
+
(widget) => applyWidgetOverrides(widget, overrideMap)
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1023
|
+
function applyWidgetOverrides(widget, overrideMap) {
|
|
1024
|
+
const override = widget.id ? overrideMap.get(widget.id) : void 0;
|
|
1025
|
+
const children = widget.props.children;
|
|
1026
|
+
const hasChildren = Array.isArray(children) && children.length > 0;
|
|
1027
|
+
if (!override && !hasChildren) {
|
|
1028
|
+
return widget;
|
|
1029
|
+
}
|
|
1030
|
+
const newProps = override ? { ...widget.props, ...override } : { ...widget.props };
|
|
1031
|
+
if (hasChildren) {
|
|
1032
|
+
newProps.children = children.map(
|
|
1033
|
+
(child) => applyWidgetOverrides(child, overrideMap)
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
return { ...widget, props: newProps };
|
|
1037
|
+
}
|
|
1038
|
+
function resolvePageReference(ref) {
|
|
1039
|
+
const template = PageTemplateRegistry.get(ref.page_template_id);
|
|
1040
|
+
if (!template) {
|
|
1041
|
+
console.warn(
|
|
1042
|
+
`Page template "${ref.page_template_id}" not found in registry`
|
|
1043
|
+
);
|
|
1044
|
+
return void 0;
|
|
1045
|
+
}
|
|
1046
|
+
const componentTree = ref.overrides ? applyOverrides(template.component_tree, ref.overrides) : [...template.component_tree];
|
|
1047
|
+
return {
|
|
1048
|
+
id: ref.screen_id,
|
|
1049
|
+
slug: template.slug,
|
|
1050
|
+
name: template.name,
|
|
1051
|
+
component_tree: componentTree
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
function resolveNavigationPages(navigation) {
|
|
1055
|
+
const localScreenIds = new Set(navigation.screens.map((s) => s.id));
|
|
1056
|
+
const result = [...navigation.screens];
|
|
1057
|
+
if (navigation.page_refs) {
|
|
1058
|
+
for (const ref of navigation.page_refs) {
|
|
1059
|
+
if (localScreenIds.has(ref.screen_id)) {
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1062
|
+
const screen = resolvePageReference(ref);
|
|
1063
|
+
if (screen) {
|
|
1064
|
+
result.push(screen);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
return result;
|
|
1069
|
+
}
|
|
1070
|
+
function getAvailablePageTemplates() {
|
|
1071
|
+
return PageTemplateRegistry.listAll();
|
|
1072
|
+
}
|
|
1073
|
+
function getCorePageTemplates() {
|
|
1074
|
+
return PageTemplateRegistry.listCore();
|
|
1075
|
+
}
|
|
1076
|
+
function getOptionalPageTemplates() {
|
|
1077
|
+
return PageTemplateRegistry.listOptional();
|
|
1078
|
+
}
|
|
1079
|
+
function validateNavigationPages(navigation) {
|
|
1080
|
+
const corePages = PageTemplateRegistry.listCore();
|
|
1081
|
+
const referencedTemplateIds = new Set(
|
|
1082
|
+
navigation.page_refs?.map((ref) => ref.page_template_id) ?? []
|
|
1083
|
+
);
|
|
1084
|
+
const missingCorePages = corePages.filter((page) => !referencedTemplateIds.has(page.id)).map((page) => page.id);
|
|
1085
|
+
return {
|
|
1086
|
+
valid: missingCorePages.length === 0,
|
|
1087
|
+
missingCorePages
|
|
1088
|
+
};
|
|
1089
|
+
}
|
|
1090
|
+
var EMPTY_TEMPLATES = [];
|
|
1091
|
+
var PageTemplateContext = createContext(
|
|
1092
|
+
null
|
|
1093
|
+
);
|
|
1094
|
+
function PageTemplateProvider({
|
|
1095
|
+
children,
|
|
1096
|
+
templates = EMPTY_TEMPLATES
|
|
1097
|
+
}) {
|
|
1098
|
+
const registeredIds = useRef([]);
|
|
1099
|
+
const templateKey = templates.map((t) => t.id).join(",");
|
|
1100
|
+
useEffect(() => {
|
|
1101
|
+
const registered = [];
|
|
1102
|
+
for (const template of templates) {
|
|
1103
|
+
if (!PageTemplateRegistry.has(template.id)) {
|
|
1104
|
+
try {
|
|
1105
|
+
PageTemplateRegistry.register(template);
|
|
1106
|
+
registered.push(template.id);
|
|
1107
|
+
} catch (error) {
|
|
1108
|
+
console.warn(
|
|
1109
|
+
`Failed to register page template "${template.id}":`,
|
|
1110
|
+
error
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
registeredIds.current = registered;
|
|
1116
|
+
return () => {
|
|
1117
|
+
for (const id of registeredIds.current) {
|
|
1118
|
+
PageTemplateRegistry.unregister(id);
|
|
1119
|
+
}
|
|
1120
|
+
registeredIds.current = [];
|
|
1121
|
+
};
|
|
1122
|
+
}, [templateKey]);
|
|
1123
|
+
const contextValue = useMemo(
|
|
1124
|
+
() => ({
|
|
1125
|
+
resolvePages: resolveNavigationPages,
|
|
1126
|
+
listTemplates: () => PageTemplateRegistry.listAll(),
|
|
1127
|
+
getTemplate: (id) => PageTemplateRegistry.get(id),
|
|
1128
|
+
hasTemplate: (id) => PageTemplateRegistry.has(id)
|
|
1129
|
+
}),
|
|
1130
|
+
[]
|
|
1131
|
+
);
|
|
1132
|
+
return /* @__PURE__ */ jsx(PageTemplateContext.Provider, { value: contextValue, children });
|
|
1133
|
+
}
|
|
1134
|
+
function usePageTemplates() {
|
|
1135
|
+
const context = useContext(PageTemplateContext);
|
|
1136
|
+
if (!context) {
|
|
1137
|
+
throw new Error(
|
|
1138
|
+
"usePageTemplates must be used within a PageTemplateProvider"
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
return context;
|
|
1142
|
+
}
|
|
1143
|
+
function useResolvedPages(navigation) {
|
|
1144
|
+
const { resolvePages } = usePageTemplates();
|
|
1145
|
+
return useMemo(() => resolvePages(navigation), [resolvePages, navigation]);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// src/hooks/use-fluid-api.ts
|
|
1149
|
+
function useFluidApi() {
|
|
1150
|
+
const { client } = useFluidContext();
|
|
1151
|
+
return client;
|
|
1152
|
+
}
|
|
1153
|
+
var PROFILE_QUERY_KEY = ["fluid", "profile"];
|
|
1154
|
+
function useFluidProfile() {
|
|
1155
|
+
const api = useFluidApi();
|
|
1156
|
+
return useQuery({
|
|
1157
|
+
queryKey: PROFILE_QUERY_KEY,
|
|
1158
|
+
queryFn: () => api.profile.get()
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
var PERMISSIONS_QUERY_KEY = ["fluid", "permissions"];
|
|
1162
|
+
function useFluidPermissions() {
|
|
1163
|
+
const api = useFluidApi();
|
|
1164
|
+
const query = useQuery({
|
|
1165
|
+
queryKey: PERMISSIONS_QUERY_KEY,
|
|
1166
|
+
queryFn: () => api.permissions.get()
|
|
1167
|
+
});
|
|
1168
|
+
const permissions = query.data;
|
|
1169
|
+
const can = useMemo(() => {
|
|
1170
|
+
return (resource, action = "view") => {
|
|
1171
|
+
if (!permissions) {
|
|
1172
|
+
return false;
|
|
1173
|
+
}
|
|
1174
|
+
if (permissions.is_super_admin) {
|
|
1175
|
+
return true;
|
|
1176
|
+
}
|
|
1177
|
+
const resourcePermissions = permissions.permissions[resource];
|
|
1178
|
+
if (!resourcePermissions) {
|
|
1179
|
+
return false;
|
|
1180
|
+
}
|
|
1181
|
+
return resourcePermissions[action] ?? false;
|
|
1182
|
+
};
|
|
1183
|
+
}, [permissions]);
|
|
1184
|
+
const isSuperAdmin = permissions?.is_super_admin ?? false;
|
|
1185
|
+
return {
|
|
1186
|
+
query,
|
|
1187
|
+
permissions,
|
|
1188
|
+
can,
|
|
1189
|
+
isSuperAdmin
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// src/hooks/use-fluid-theme.ts
|
|
1194
|
+
function useFluidTheme() {
|
|
1195
|
+
const { currentTheme, setTheme, setThemeMode } = useThemeContext();
|
|
1196
|
+
return {
|
|
1197
|
+
currentTheme,
|
|
1198
|
+
setTheme,
|
|
1199
|
+
setThemeMode,
|
|
1200
|
+
mode: currentTheme?.mode
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
var CURRENT_REP_QUERY_KEY = ["fluid", "currentRep"];
|
|
1204
|
+
function useCurrentRep() {
|
|
1205
|
+
const api = useFluidApi();
|
|
1206
|
+
return useQuery({
|
|
1207
|
+
queryKey: CURRENT_REP_QUERY_KEY,
|
|
1208
|
+
queryFn: () => api.reps.current()
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// src/hooks/use-fluid-auth.ts
|
|
1213
|
+
function useFluidAuth() {
|
|
1214
|
+
return useFluidAuthContext();
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// src/hooks/demo-data/calendar-events.ts
|
|
1218
|
+
var now = /* @__PURE__ */ new Date();
|
|
1219
|
+
function daysFromNow(days, hour, minute = 0) {
|
|
1220
|
+
const d = new Date(now);
|
|
1221
|
+
d.setDate(d.getDate() + days);
|
|
1222
|
+
d.setHours(hour, minute, 0, 0);
|
|
1223
|
+
return d;
|
|
1224
|
+
}
|
|
1225
|
+
var DEMO_CALENDAR_EVENTS = [
|
|
1226
|
+
{
|
|
1227
|
+
id: 1,
|
|
1228
|
+
title: "Team Standup",
|
|
1229
|
+
description: { body: "Daily sync with the sales team" },
|
|
1230
|
+
color: "#4f46e5",
|
|
1231
|
+
start: daysFromNow(0, 9, 0).toISOString(),
|
|
1232
|
+
end: daysFromNow(0, 9, 30).toISOString(),
|
|
1233
|
+
active: true,
|
|
1234
|
+
status: "confirmed"
|
|
1235
|
+
},
|
|
1236
|
+
{
|
|
1237
|
+
id: 2,
|
|
1238
|
+
title: "Client Review - Acme Corp",
|
|
1239
|
+
description: { body: "Quarterly business review with key accounts" },
|
|
1240
|
+
color: "#059669",
|
|
1241
|
+
start: daysFromNow(2, 14, 0).toISOString(),
|
|
1242
|
+
end: daysFromNow(2, 15, 0).toISOString(),
|
|
1243
|
+
active: true,
|
|
1244
|
+
status: "confirmed",
|
|
1245
|
+
venue: "Conference Room B"
|
|
1246
|
+
},
|
|
1247
|
+
{
|
|
1248
|
+
id: 3,
|
|
1249
|
+
title: "Product Training Webinar",
|
|
1250
|
+
description: { body: "New product line training for the field" },
|
|
1251
|
+
color: "#d97706",
|
|
1252
|
+
start: daysFromNow(4, 11, 0).toISOString(),
|
|
1253
|
+
end: daysFromNow(4, 12, 30).toISOString(),
|
|
1254
|
+
active: true,
|
|
1255
|
+
status: "confirmed",
|
|
1256
|
+
url: "https://example.com/webinar"
|
|
1257
|
+
},
|
|
1258
|
+
{
|
|
1259
|
+
id: 4,
|
|
1260
|
+
title: "Regional Conference",
|
|
1261
|
+
description: { body: "Annual West Coast regional conference" },
|
|
1262
|
+
color: "#dc2626",
|
|
1263
|
+
start: daysFromNow(10, 8, 0).toISOString(),
|
|
1264
|
+
end: daysFromNow(12, 17, 0).toISOString(),
|
|
1265
|
+
active: true,
|
|
1266
|
+
status: "confirmed",
|
|
1267
|
+
venue: "San Diego Convention Center",
|
|
1268
|
+
isAllDay: true
|
|
1269
|
+
}
|
|
1270
|
+
];
|
|
1271
|
+
|
|
1272
|
+
// src/hooks/use-calendar-events.ts
|
|
1273
|
+
function useCalendarEvents() {
|
|
1274
|
+
return {
|
|
1275
|
+
data: [...DEMO_CALENDAR_EVENTS],
|
|
1276
|
+
isLoading: false,
|
|
1277
|
+
isError: false
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// src/hooks/demo-data/todos.ts
|
|
1282
|
+
var now2 = /* @__PURE__ */ new Date();
|
|
1283
|
+
function daysFromNow2(days) {
|
|
1284
|
+
const d = new Date(now2);
|
|
1285
|
+
d.setDate(d.getDate() + days);
|
|
1286
|
+
return d.toISOString();
|
|
1287
|
+
}
|
|
1288
|
+
var DEMO_TODOS = [
|
|
1289
|
+
{
|
|
1290
|
+
id: 1,
|
|
1291
|
+
body: "Follow up with Sarah about Q2 order",
|
|
1292
|
+
dueAt: daysFromNow2(1),
|
|
1293
|
+
completedAt: null,
|
|
1294
|
+
createdAt: daysFromNow2(-2),
|
|
1295
|
+
contactName: "Sarah Johnson"
|
|
1296
|
+
},
|
|
1297
|
+
{
|
|
1298
|
+
id: 2,
|
|
1299
|
+
body: "Send pricing proposal to Acme Corp",
|
|
1300
|
+
dueAt: daysFromNow2(7),
|
|
1301
|
+
completedAt: null,
|
|
1302
|
+
createdAt: daysFromNow2(-1),
|
|
1303
|
+
contactName: "Mike Chen"
|
|
1304
|
+
},
|
|
1305
|
+
{
|
|
1306
|
+
id: 3,
|
|
1307
|
+
body: "Schedule onboarding call with new team member",
|
|
1308
|
+
dueAt: daysFromNow2(3),
|
|
1309
|
+
completedAt: null,
|
|
1310
|
+
createdAt: daysFromNow2(0),
|
|
1311
|
+
contactName: "Emily Rodriguez"
|
|
1312
|
+
},
|
|
1313
|
+
{
|
|
1314
|
+
id: 4,
|
|
1315
|
+
body: "Review and approve Q1 expense report",
|
|
1316
|
+
dueAt: daysFromNow2(-1),
|
|
1317
|
+
completedAt: daysFromNow2(-1),
|
|
1318
|
+
createdAt: daysFromNow2(-5),
|
|
1319
|
+
contactName: null
|
|
1320
|
+
},
|
|
1321
|
+
{
|
|
1322
|
+
id: 5,
|
|
1323
|
+
body: "Prepare presentation for Friday team meeting",
|
|
1324
|
+
dueAt: daysFromNow2(4),
|
|
1325
|
+
completedAt: daysFromNow2(0),
|
|
1326
|
+
createdAt: daysFromNow2(-3),
|
|
1327
|
+
contactName: null
|
|
1328
|
+
}
|
|
1329
|
+
];
|
|
1330
|
+
|
|
1331
|
+
// src/hooks/use-todos.ts
|
|
1332
|
+
function useTodos() {
|
|
1333
|
+
return {
|
|
1334
|
+
data: [...DEMO_TODOS],
|
|
1335
|
+
isLoading: false,
|
|
1336
|
+
isError: false
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// src/hooks/hook-types.ts
|
|
1341
|
+
function hasData(result) {
|
|
1342
|
+
return result.data != null && !result.isLoading && !result.isError;
|
|
1343
|
+
}
|
|
1344
|
+
function isLoading(result) {
|
|
1345
|
+
return result.isLoading;
|
|
1346
|
+
}
|
|
1347
|
+
function isErrorResult(result) {
|
|
1348
|
+
return result.isError && result.error !== void 0;
|
|
1349
|
+
}
|
|
1350
|
+
function isIdle(result) {
|
|
1351
|
+
return !result.isLoading && !result.isError;
|
|
1352
|
+
}
|
|
1353
|
+
function selectProperty(items, key) {
|
|
1354
|
+
return items.map((item) => item[key]);
|
|
1355
|
+
}
|
|
1356
|
+
function getProperty(item, key) {
|
|
1357
|
+
return item?.[key];
|
|
1358
|
+
}
|
|
1359
|
+
var ACTIVITY_SLUGS = {
|
|
1360
|
+
abandonedCart: "abandoned_cart",
|
|
1361
|
+
announcements: "announcements",
|
|
1362
|
+
cartItemsAdded: "cart_items_added",
|
|
1363
|
+
commentReply: "comment_reply",
|
|
1364
|
+
directMessage: "direct_message",
|
|
1365
|
+
fantasyPoint: "fantasy_point",
|
|
1366
|
+
newLead: "new_lead",
|
|
1367
|
+
orderPlaced: "order_placed",
|
|
1368
|
+
pageViews: "page_views",
|
|
1369
|
+
pageViewsContact: "page_views_contact",
|
|
1370
|
+
tasks: "tasks",
|
|
1371
|
+
upcomingEvent: "upcoming_event",
|
|
1372
|
+
video: "video",
|
|
1373
|
+
videoComplete: "video_complete",
|
|
1374
|
+
videoCompleteContact: "video_complete_contact",
|
|
1375
|
+
videoContact: "video_contact",
|
|
1376
|
+
messageReceived: "message_received",
|
|
1377
|
+
messageSent: "message_sent",
|
|
1378
|
+
newCartItemsAdded: "new_cart_items_added",
|
|
1379
|
+
smartLinkClicked: "smart_link_clicked",
|
|
1380
|
+
reviewLeft: "review_left"
|
|
1381
|
+
};
|
|
1382
|
+
function isActivitySlug(value) {
|
|
1383
|
+
return Object.values(ACTIVITY_SLUGS).includes(value);
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
// src/hooks/demo-data/activities.ts
|
|
1387
|
+
var now3 = /* @__PURE__ */ new Date();
|
|
1388
|
+
function hoursAgo(hours) {
|
|
1389
|
+
const d = new Date(now3);
|
|
1390
|
+
d.setHours(d.getHours() - hours);
|
|
1391
|
+
return d.toISOString();
|
|
1392
|
+
}
|
|
1393
|
+
var DEMO_ACTIVITIES = [
|
|
1394
|
+
{
|
|
1395
|
+
id: 1,
|
|
1396
|
+
userName: "Sarah Johnson",
|
|
1397
|
+
avatarUrl: null,
|
|
1398
|
+
activityType: "New Order",
|
|
1399
|
+
targetName: "Wellness Starter Kit",
|
|
1400
|
+
timestamp: hoursAgo(1),
|
|
1401
|
+
slug: "order_placed"
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
id: 2,
|
|
1405
|
+
userName: "Mike Chen",
|
|
1406
|
+
avatarUrl: null,
|
|
1407
|
+
activityType: "New Lead",
|
|
1408
|
+
targetName: "Referral from LinkedIn campaign",
|
|
1409
|
+
timestamp: hoursAgo(3),
|
|
1410
|
+
slug: "new_lead"
|
|
1411
|
+
},
|
|
1412
|
+
{
|
|
1413
|
+
id: 3,
|
|
1414
|
+
userName: "Emily Rodriguez",
|
|
1415
|
+
avatarUrl: null,
|
|
1416
|
+
activityType: "Page View",
|
|
1417
|
+
targetName: "Product Catalog",
|
|
1418
|
+
timestamp: hoursAgo(5),
|
|
1419
|
+
slug: "page_views"
|
|
1420
|
+
},
|
|
1421
|
+
{
|
|
1422
|
+
id: 4,
|
|
1423
|
+
userName: "David Park",
|
|
1424
|
+
avatarUrl: null,
|
|
1425
|
+
activityType: "Cart Items Added",
|
|
1426
|
+
targetName: "Premium Bundle (3 items)",
|
|
1427
|
+
timestamp: hoursAgo(8),
|
|
1428
|
+
slug: "cart_items_added"
|
|
1429
|
+
},
|
|
1430
|
+
{
|
|
1431
|
+
id: 5,
|
|
1432
|
+
userName: "Lisa Thompson",
|
|
1433
|
+
avatarUrl: null,
|
|
1434
|
+
activityType: "Video Watched",
|
|
1435
|
+
targetName: "Getting Started Tutorial",
|
|
1436
|
+
timestamp: hoursAgo(12),
|
|
1437
|
+
slug: "video_complete"
|
|
1438
|
+
},
|
|
1439
|
+
{
|
|
1440
|
+
id: 6,
|
|
1441
|
+
userName: "James Wilson",
|
|
1442
|
+
avatarUrl: null,
|
|
1443
|
+
activityType: "Message Received",
|
|
1444
|
+
targetName: "Question about shipping",
|
|
1445
|
+
timestamp: hoursAgo(18),
|
|
1446
|
+
slug: "message_received"
|
|
1447
|
+
},
|
|
1448
|
+
{
|
|
1449
|
+
id: 7,
|
|
1450
|
+
userName: "Rachel Kim",
|
|
1451
|
+
avatarUrl: null,
|
|
1452
|
+
activityType: "Smart Link Clicked",
|
|
1453
|
+
targetName: "Holiday Promo Link",
|
|
1454
|
+
timestamp: hoursAgo(24),
|
|
1455
|
+
slug: "smart_link_clicked"
|
|
1456
|
+
},
|
|
1457
|
+
{
|
|
1458
|
+
id: 8,
|
|
1459
|
+
userName: "Tom Martinez",
|
|
1460
|
+
avatarUrl: null,
|
|
1461
|
+
activityType: "Review Left",
|
|
1462
|
+
targetName: "Essential Oil Set - 5 stars",
|
|
1463
|
+
timestamp: hoursAgo(36),
|
|
1464
|
+
slug: "review_left"
|
|
1465
|
+
}
|
|
1466
|
+
];
|
|
1467
|
+
|
|
1468
|
+
// src/hooks/use-activities.ts
|
|
1469
|
+
function useActivities() {
|
|
1470
|
+
return {
|
|
1471
|
+
data: [...DEMO_ACTIVITIES],
|
|
1472
|
+
isLoading: false,
|
|
1473
|
+
isError: false
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
// src/hooks/demo-data/catchups.ts
|
|
1478
|
+
var DEMO_CATCHUPS = [
|
|
1479
|
+
{
|
|
1480
|
+
id: 1,
|
|
1481
|
+
suggestion_title: "Sarah Johnson hasn't ordered in 30 days"
|
|
1482
|
+
},
|
|
1483
|
+
{
|
|
1484
|
+
id: 2,
|
|
1485
|
+
suggestion_title: "Mike Chen's subscription is expiring soon"
|
|
1486
|
+
},
|
|
1487
|
+
{
|
|
1488
|
+
id: 3,
|
|
1489
|
+
suggestion_title: "Emily Rodriguez left a cart with 3 items"
|
|
1490
|
+
}
|
|
1491
|
+
];
|
|
1492
|
+
|
|
1493
|
+
// src/hooks/use-catchups.ts
|
|
1494
|
+
function useCatchUps() {
|
|
1495
|
+
return {
|
|
1496
|
+
data: [...DEMO_CATCHUPS],
|
|
1497
|
+
isLoading: false,
|
|
1498
|
+
isError: false
|
|
1499
|
+
};
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
// src/hooks/demo-data/mysite.ts
|
|
1503
|
+
var DEMO_MYSITE = {
|
|
1504
|
+
url: "https://my-portal.example.com",
|
|
1505
|
+
views: 1243,
|
|
1506
|
+
leads: 37,
|
|
1507
|
+
userName: "Demo User"
|
|
1508
|
+
};
|
|
1509
|
+
|
|
1510
|
+
// src/hooks/use-mysite.ts
|
|
1511
|
+
function useMySite() {
|
|
1512
|
+
return {
|
|
1513
|
+
data: DEMO_MYSITE,
|
|
1514
|
+
isLoading: false,
|
|
1515
|
+
isError: false
|
|
1516
|
+
};
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
// src/hooks/demo-data/conversations.ts
|
|
1520
|
+
var now4 = /* @__PURE__ */ new Date();
|
|
1521
|
+
function hoursAgo2(hours) {
|
|
1522
|
+
const d = new Date(now4);
|
|
1523
|
+
d.setHours(d.getHours() - hours);
|
|
1524
|
+
return d.toISOString();
|
|
1525
|
+
}
|
|
1526
|
+
function daysAgo(days) {
|
|
1527
|
+
const d = new Date(now4);
|
|
1528
|
+
d.setDate(d.getDate() - days);
|
|
1529
|
+
return d.toISOString();
|
|
1530
|
+
}
|
|
1531
|
+
var DEMO_CONVERSATIONS = [
|
|
1532
|
+
{
|
|
1533
|
+
id: "conv-1",
|
|
1534
|
+
title: "Sarah Johnson",
|
|
1535
|
+
participants: [
|
|
1536
|
+
{ id: "user-1", name: "You", email: "me@example.com", isOnline: true },
|
|
1537
|
+
{
|
|
1538
|
+
id: "user-2",
|
|
1539
|
+
name: "Sarah Johnson",
|
|
1540
|
+
email: "sarah.johnson@example.com",
|
|
1541
|
+
isOnline: true
|
|
1542
|
+
}
|
|
1543
|
+
],
|
|
1544
|
+
lastMessage: {
|
|
1545
|
+
id: "msg-1-3",
|
|
1546
|
+
conversationId: "conv-1",
|
|
1547
|
+
senderId: "user-2",
|
|
1548
|
+
senderName: "Sarah Johnson",
|
|
1549
|
+
type: "text",
|
|
1550
|
+
content: "Sounds great! I'll place the order by end of day.",
|
|
1551
|
+
timestamp: hoursAgo2(1),
|
|
1552
|
+
isRead: false
|
|
1553
|
+
},
|
|
1554
|
+
unreadCount: 1,
|
|
1555
|
+
status: "active",
|
|
1556
|
+
createdAt: daysAgo(30),
|
|
1557
|
+
updatedAt: hoursAgo2(1)
|
|
1558
|
+
},
|
|
1559
|
+
{
|
|
1560
|
+
id: "conv-2",
|
|
1561
|
+
title: "Mike Chen",
|
|
1562
|
+
participants: [
|
|
1563
|
+
{ id: "user-1", name: "You", email: "me@example.com", isOnline: true },
|
|
1564
|
+
{
|
|
1565
|
+
id: "user-3",
|
|
1566
|
+
name: "Mike Chen",
|
|
1567
|
+
email: "mike.chen@acmecorp.com",
|
|
1568
|
+
isOnline: false
|
|
1569
|
+
}
|
|
1570
|
+
],
|
|
1571
|
+
lastMessage: {
|
|
1572
|
+
id: "msg-2-2",
|
|
1573
|
+
conversationId: "conv-2",
|
|
1574
|
+
senderId: "user-1",
|
|
1575
|
+
senderName: "You",
|
|
1576
|
+
type: "text",
|
|
1577
|
+
content: "I've attached the updated pricing sheet. Let me know if you have any questions!",
|
|
1578
|
+
timestamp: hoursAgo2(5),
|
|
1579
|
+
isRead: true
|
|
1580
|
+
},
|
|
1581
|
+
unreadCount: 0,
|
|
1582
|
+
status: "active",
|
|
1583
|
+
createdAt: daysAgo(14),
|
|
1584
|
+
updatedAt: hoursAgo2(5)
|
|
1585
|
+
},
|
|
1586
|
+
{
|
|
1587
|
+
id: "conv-3",
|
|
1588
|
+
title: "Team Updates",
|
|
1589
|
+
participants: [
|
|
1590
|
+
{ id: "user-1", name: "You", email: "me@example.com", isOnline: true },
|
|
1591
|
+
{
|
|
1592
|
+
id: "user-4",
|
|
1593
|
+
name: "Emily Rodriguez",
|
|
1594
|
+
email: "emily.r@healthfirst.io"
|
|
1595
|
+
},
|
|
1596
|
+
{ id: "user-5", name: "David Park", email: "david.park@email.com" }
|
|
1597
|
+
],
|
|
1598
|
+
lastMessage: {
|
|
1599
|
+
id: "msg-3-4",
|
|
1600
|
+
conversationId: "conv-3",
|
|
1601
|
+
senderId: "user-4",
|
|
1602
|
+
senderName: "Emily Rodriguez",
|
|
1603
|
+
type: "text",
|
|
1604
|
+
content: "The new product samples arrived today. Will distribute to the team tomorrow.",
|
|
1605
|
+
timestamp: daysAgo(1),
|
|
1606
|
+
isRead: true
|
|
1607
|
+
},
|
|
1608
|
+
unreadCount: 0,
|
|
1609
|
+
status: "active",
|
|
1610
|
+
createdAt: daysAgo(60),
|
|
1611
|
+
updatedAt: daysAgo(1)
|
|
1612
|
+
}
|
|
1613
|
+
];
|
|
1614
|
+
var DEMO_MESSAGES = [
|
|
1615
|
+
{
|
|
1616
|
+
id: "msg-1-1",
|
|
1617
|
+
conversationId: "conv-1",
|
|
1618
|
+
senderId: "user-1",
|
|
1619
|
+
senderName: "You",
|
|
1620
|
+
type: "text",
|
|
1621
|
+
content: "Hi Sarah! I wanted to follow up on the Wellness Starter Kit. We have a special promotion running this month.",
|
|
1622
|
+
timestamp: hoursAgo2(3),
|
|
1623
|
+
isRead: true
|
|
1624
|
+
},
|
|
1625
|
+
{
|
|
1626
|
+
id: "msg-1-2",
|
|
1627
|
+
conversationId: "conv-1",
|
|
1628
|
+
senderId: "user-2",
|
|
1629
|
+
senderName: "Sarah Johnson",
|
|
1630
|
+
type: "text",
|
|
1631
|
+
content: "That's perfect timing! I was just thinking about reordering. What's the promo?",
|
|
1632
|
+
timestamp: hoursAgo2(2),
|
|
1633
|
+
isRead: true
|
|
1634
|
+
},
|
|
1635
|
+
{
|
|
1636
|
+
id: "msg-1-3",
|
|
1637
|
+
conversationId: "conv-1",
|
|
1638
|
+
senderId: "user-2",
|
|
1639
|
+
senderName: "Sarah Johnson",
|
|
1640
|
+
type: "text",
|
|
1641
|
+
content: "Sounds great! I'll place the order by end of day.",
|
|
1642
|
+
timestamp: hoursAgo2(1),
|
|
1643
|
+
isRead: false
|
|
1644
|
+
}
|
|
1645
|
+
];
|
|
1646
|
+
|
|
1647
|
+
// src/hooks/use-conversations.ts
|
|
1648
|
+
function useConversations() {
|
|
1649
|
+
return {
|
|
1650
|
+
data: [...DEMO_CONVERSATIONS],
|
|
1651
|
+
isLoading: false,
|
|
1652
|
+
isError: false
|
|
1653
|
+
};
|
|
1654
|
+
}
|
|
1655
|
+
function useConversationMessages(_conversationId) {
|
|
1656
|
+
return {
|
|
1657
|
+
data: [...DEMO_MESSAGES],
|
|
1658
|
+
isLoading: false,
|
|
1659
|
+
isError: false
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
// src/types/screen-types.ts
|
|
1664
|
+
var CONTACT_STATUSES = {
|
|
1665
|
+
active: "active",
|
|
1666
|
+
inactive: "inactive",
|
|
1667
|
+
lead: "lead",
|
|
1668
|
+
prospect: "prospect"
|
|
1669
|
+
};
|
|
1670
|
+
|
|
1671
|
+
// src/hooks/demo-data/contacts.ts
|
|
1672
|
+
var now5 = /* @__PURE__ */ new Date();
|
|
1673
|
+
function daysAgo2(days) {
|
|
1674
|
+
const d = new Date(now5);
|
|
1675
|
+
d.setDate(d.getDate() - days);
|
|
1676
|
+
return d.toISOString();
|
|
1677
|
+
}
|
|
1678
|
+
var DEMO_CONTACTS = [
|
|
1679
|
+
{
|
|
1680
|
+
id: "contact-1",
|
|
1681
|
+
firstName: "Sarah",
|
|
1682
|
+
lastName: "Johnson",
|
|
1683
|
+
email: "sarah.johnson@example.com",
|
|
1684
|
+
phone: "+1 (555) 123-4567",
|
|
1685
|
+
company: "Wellness Works Inc.",
|
|
1686
|
+
jobTitle: "Purchasing Manager",
|
|
1687
|
+
status: "active",
|
|
1688
|
+
type: "individual",
|
|
1689
|
+
tags: ["VIP", "Repeat Buyer"],
|
|
1690
|
+
createdAt: daysAgo2(90),
|
|
1691
|
+
updatedAt: daysAgo2(2)
|
|
1692
|
+
},
|
|
1693
|
+
{
|
|
1694
|
+
id: "contact-2",
|
|
1695
|
+
firstName: "Mike",
|
|
1696
|
+
lastName: "Chen",
|
|
1697
|
+
email: "mike.chen@acmecorp.com",
|
|
1698
|
+
phone: "+1 (555) 234-5678",
|
|
1699
|
+
company: "Acme Corp",
|
|
1700
|
+
jobTitle: "Director of Operations",
|
|
1701
|
+
status: "active",
|
|
1702
|
+
type: "individual",
|
|
1703
|
+
tags: ["Enterprise"],
|
|
1704
|
+
createdAt: daysAgo2(60),
|
|
1705
|
+
updatedAt: daysAgo2(5)
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
id: "contact-3",
|
|
1709
|
+
firstName: "Emily",
|
|
1710
|
+
lastName: "Rodriguez",
|
|
1711
|
+
email: "emily.r@healthfirst.io",
|
|
1712
|
+
company: "HealthFirst",
|
|
1713
|
+
status: "lead",
|
|
1714
|
+
type: "individual",
|
|
1715
|
+
notes: "Interested in bulk pricing for team orders",
|
|
1716
|
+
createdAt: daysAgo2(7),
|
|
1717
|
+
updatedAt: daysAgo2(1)
|
|
1718
|
+
},
|
|
1719
|
+
{
|
|
1720
|
+
id: "contact-4",
|
|
1721
|
+
firstName: "David",
|
|
1722
|
+
lastName: "Park",
|
|
1723
|
+
email: "david.park@email.com",
|
|
1724
|
+
phone: "+1 (555) 345-6789",
|
|
1725
|
+
status: "prospect",
|
|
1726
|
+
type: "individual",
|
|
1727
|
+
tags: ["Referral"],
|
|
1728
|
+
createdAt: daysAgo2(14),
|
|
1729
|
+
updatedAt: daysAgo2(10)
|
|
1730
|
+
},
|
|
1731
|
+
{
|
|
1732
|
+
id: "contact-5",
|
|
1733
|
+
firstName: "Lisa",
|
|
1734
|
+
lastName: "Thompson",
|
|
1735
|
+
email: "lisa.t@globalfit.com",
|
|
1736
|
+
company: "Global Fitness",
|
|
1737
|
+
jobTitle: "CEO",
|
|
1738
|
+
status: "active",
|
|
1739
|
+
type: "individual",
|
|
1740
|
+
address: {
|
|
1741
|
+
city: "Los Angeles",
|
|
1742
|
+
state: "CA",
|
|
1743
|
+
country: "US"
|
|
1744
|
+
},
|
|
1745
|
+
createdAt: daysAgo2(120),
|
|
1746
|
+
updatedAt: daysAgo2(15)
|
|
1747
|
+
},
|
|
1748
|
+
{
|
|
1749
|
+
id: "contact-6",
|
|
1750
|
+
firstName: "James",
|
|
1751
|
+
lastName: "Wilson",
|
|
1752
|
+
email: "jwilson@retired.net",
|
|
1753
|
+
status: "inactive",
|
|
1754
|
+
type: "individual",
|
|
1755
|
+
notes: "Moved out of area, no longer purchasing",
|
|
1756
|
+
createdAt: daysAgo2(200),
|
|
1757
|
+
updatedAt: daysAgo2(45)
|
|
1758
|
+
}
|
|
1759
|
+
];
|
|
1760
|
+
var DEMO_CONTACT = DEMO_CONTACTS[0];
|
|
1761
|
+
|
|
1762
|
+
// src/hooks/use-contacts.ts
|
|
1763
|
+
function isContactStatus(value) {
|
|
1764
|
+
return Object.values(CONTACT_STATUSES).includes(value);
|
|
1765
|
+
}
|
|
1766
|
+
function useContacts(_params) {
|
|
1767
|
+
return {
|
|
1768
|
+
data: [...DEMO_CONTACTS],
|
|
1769
|
+
isLoading: false,
|
|
1770
|
+
isError: false,
|
|
1771
|
+
totalCount: DEMO_CONTACTS.length
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
function useContact(_contactId) {
|
|
1775
|
+
return {
|
|
1776
|
+
data: DEMO_CONTACT,
|
|
1777
|
+
isLoading: false,
|
|
1778
|
+
isError: false
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
function AuthError({
|
|
1782
|
+
message = "You need to be authenticated to view this content.",
|
|
1783
|
+
title = "Authentication Required",
|
|
1784
|
+
children
|
|
1785
|
+
}) {
|
|
1786
|
+
return /* @__PURE__ */ jsx(
|
|
1787
|
+
"div",
|
|
1788
|
+
{
|
|
1789
|
+
style: {
|
|
1790
|
+
display: "flex",
|
|
1791
|
+
flexDirection: "column",
|
|
1792
|
+
alignItems: "center",
|
|
1793
|
+
justifyContent: "center",
|
|
1794
|
+
minHeight: "100vh",
|
|
1795
|
+
padding: "2rem",
|
|
1796
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
1797
|
+
backgroundColor: "#f9fafb",
|
|
1798
|
+
color: "#111827"
|
|
1799
|
+
},
|
|
1800
|
+
children: /* @__PURE__ */ jsxs(
|
|
1801
|
+
"div",
|
|
1802
|
+
{
|
|
1803
|
+
style: {
|
|
1804
|
+
maxWidth: "400px",
|
|
1805
|
+
textAlign: "center",
|
|
1806
|
+
padding: "2rem",
|
|
1807
|
+
backgroundColor: "#ffffff",
|
|
1808
|
+
borderRadius: "0.75rem",
|
|
1809
|
+
boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)"
|
|
1810
|
+
},
|
|
1811
|
+
children: [
|
|
1812
|
+
/* @__PURE__ */ jsx(
|
|
1813
|
+
"div",
|
|
1814
|
+
{
|
|
1815
|
+
style: {
|
|
1816
|
+
width: "64px",
|
|
1817
|
+
height: "64px",
|
|
1818
|
+
margin: "0 auto 1.5rem",
|
|
1819
|
+
backgroundColor: "#fee2e2",
|
|
1820
|
+
borderRadius: "50%",
|
|
1821
|
+
display: "flex",
|
|
1822
|
+
alignItems: "center",
|
|
1823
|
+
justifyContent: "center"
|
|
1824
|
+
},
|
|
1825
|
+
children: /* @__PURE__ */ jsxs(
|
|
1826
|
+
"svg",
|
|
1827
|
+
{
|
|
1828
|
+
width: "32",
|
|
1829
|
+
height: "32",
|
|
1830
|
+
viewBox: "0 0 24 24",
|
|
1831
|
+
fill: "none",
|
|
1832
|
+
stroke: "#dc2626",
|
|
1833
|
+
strokeWidth: "2",
|
|
1834
|
+
strokeLinecap: "round",
|
|
1835
|
+
strokeLinejoin: "round",
|
|
1836
|
+
children: [
|
|
1837
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }),
|
|
1838
|
+
/* @__PURE__ */ jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
|
|
1839
|
+
]
|
|
1840
|
+
}
|
|
1841
|
+
)
|
|
1842
|
+
}
|
|
1843
|
+
),
|
|
1844
|
+
/* @__PURE__ */ jsx(
|
|
1845
|
+
"h1",
|
|
1846
|
+
{
|
|
1847
|
+
style: {
|
|
1848
|
+
fontSize: "1.5rem",
|
|
1849
|
+
fontWeight: "600",
|
|
1850
|
+
marginBottom: "0.75rem",
|
|
1851
|
+
color: "#111827"
|
|
1852
|
+
},
|
|
1853
|
+
children: title
|
|
1854
|
+
}
|
|
1855
|
+
),
|
|
1856
|
+
/* @__PURE__ */ jsx(
|
|
1857
|
+
"p",
|
|
1858
|
+
{
|
|
1859
|
+
style: {
|
|
1860
|
+
fontSize: "1rem",
|
|
1861
|
+
color: "#6b7280",
|
|
1862
|
+
marginBottom: children ? "1.5rem" : "0",
|
|
1863
|
+
lineHeight: "1.5"
|
|
1864
|
+
},
|
|
1865
|
+
children: message
|
|
1866
|
+
}
|
|
1867
|
+
),
|
|
1868
|
+
children
|
|
1869
|
+
]
|
|
1870
|
+
}
|
|
1871
|
+
)
|
|
1872
|
+
}
|
|
1873
|
+
);
|
|
1874
|
+
}
|
|
1875
|
+
function AuthLoading() {
|
|
1876
|
+
return /* @__PURE__ */ jsxs(
|
|
1877
|
+
"div",
|
|
1878
|
+
{
|
|
1879
|
+
style: {
|
|
1880
|
+
display: "flex",
|
|
1881
|
+
flexDirection: "column",
|
|
1882
|
+
alignItems: "center",
|
|
1883
|
+
justifyContent: "center",
|
|
1884
|
+
minHeight: "100vh",
|
|
1885
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
1886
|
+
backgroundColor: "#f9fafb"
|
|
1887
|
+
},
|
|
1888
|
+
children: [
|
|
1889
|
+
/* @__PURE__ */ jsx(
|
|
1890
|
+
"div",
|
|
1891
|
+
{
|
|
1892
|
+
style: {
|
|
1893
|
+
width: "40px",
|
|
1894
|
+
height: "40px",
|
|
1895
|
+
border: "3px solid #e5e7eb",
|
|
1896
|
+
borderTopColor: "#3b82f6",
|
|
1897
|
+
borderRadius: "50%",
|
|
1898
|
+
animation: "spin 1s linear infinite"
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
),
|
|
1902
|
+
/* @__PURE__ */ jsx(
|
|
1903
|
+
"p",
|
|
1904
|
+
{
|
|
1905
|
+
style: {
|
|
1906
|
+
marginTop: "1rem",
|
|
1907
|
+
color: "#6b7280",
|
|
1908
|
+
fontSize: "0.875rem"
|
|
1909
|
+
},
|
|
1910
|
+
children: "Authenticating..."
|
|
1911
|
+
}
|
|
1912
|
+
),
|
|
1913
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
1914
|
+
@keyframes spin {
|
|
1915
|
+
to { transform: rotate(360deg); }
|
|
1916
|
+
}
|
|
1917
|
+
` })
|
|
1918
|
+
]
|
|
1919
|
+
}
|
|
1920
|
+
);
|
|
1921
|
+
}
|
|
1922
|
+
function RequireAuth({
|
|
1923
|
+
children,
|
|
1924
|
+
fallback = /* @__PURE__ */ jsx(AuthLoading, {}),
|
|
1925
|
+
errorComponent = /* @__PURE__ */ jsx(AuthError, {})
|
|
1926
|
+
}) {
|
|
1927
|
+
const { isAuthenticated, isLoading: isLoading2, error } = useFluidAuth();
|
|
1928
|
+
if (isLoading2) {
|
|
1929
|
+
return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
1930
|
+
}
|
|
1931
|
+
if (!isAuthenticated || error) {
|
|
1932
|
+
return /* @__PURE__ */ jsx(Fragment, { children: errorComponent });
|
|
1933
|
+
}
|
|
1934
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
// src/themes/index.ts
|
|
1938
|
+
var themes_exports = {};
|
|
1939
|
+
__reExport(themes_exports, theme_star);
|
|
1940
|
+
|
|
1941
|
+
// src/screens/index.ts
|
|
1942
|
+
var screenPropertySchemas = {
|
|
1943
|
+
MessagingScreen: () => import('./MessagingScreen-O42JEJMW.js').then((m) => m.messagingScreenPropertySchema),
|
|
1944
|
+
ContactsScreen: () => import('./ContactsScreen-BYXF74BO.js').then((m) => m.contactsScreenPropertySchema),
|
|
1945
|
+
OrdersScreen: () => import('./OrdersScreen-QQJFTTSS.js').then((m) => m.ordersScreenPropertySchema),
|
|
1946
|
+
CustomersScreen: () => import('./CustomersScreen-VS6LGULO.js').then((m) => m.customersScreenPropertySchema),
|
|
1947
|
+
ProductsScreen: () => import('./ProductsScreen-TRIT2FE3.js').then((m) => m.productsScreenPropertySchema)
|
|
1948
|
+
};
|
|
1949
|
+
var CORE_PAGE_IDS = {
|
|
1950
|
+
MESSAGING: "core-messaging",
|
|
1951
|
+
CONTACTS: "core-contacts",
|
|
1952
|
+
ORDERS: "core-orders",
|
|
1953
|
+
CUSTOMERS: "core-customers",
|
|
1954
|
+
PRODUCTS: "core-products"
|
|
1955
|
+
};
|
|
1956
|
+
function registerCorePageTemplates() {
|
|
1957
|
+
PageTemplateRegistry.register({
|
|
1958
|
+
id: CORE_PAGE_IDS.MESSAGING,
|
|
1959
|
+
slug: "messaging",
|
|
1960
|
+
name: "Messaging",
|
|
1961
|
+
description: "Messaging interface provided by Fluid Commerce",
|
|
1962
|
+
category: PAGE_CATEGORIES.COMMUNICATION,
|
|
1963
|
+
tags: ["messaging", "chat", "conversations", "communication"],
|
|
1964
|
+
version: "1.0.0",
|
|
1965
|
+
isCore: true,
|
|
1966
|
+
component_tree: [
|
|
1967
|
+
{
|
|
1968
|
+
type: "MessagingScreen",
|
|
1969
|
+
id: "messaging-screen-root",
|
|
1970
|
+
props: {}
|
|
1971
|
+
}
|
|
1972
|
+
],
|
|
1973
|
+
defaultProps: {}
|
|
1974
|
+
});
|
|
1975
|
+
PageTemplateRegistry.register({
|
|
1976
|
+
id: CORE_PAGE_IDS.CONTACTS,
|
|
1977
|
+
slug: "contacts",
|
|
1978
|
+
name: "Contacts",
|
|
1979
|
+
description: "Contact management provided by Fluid Commerce",
|
|
1980
|
+
category: PAGE_CATEGORIES.CORE,
|
|
1981
|
+
tags: ["contacts", "people", "address-book"],
|
|
1982
|
+
version: "1.0.0",
|
|
1983
|
+
isCore: true,
|
|
1984
|
+
component_tree: [
|
|
1985
|
+
{
|
|
1986
|
+
type: "ContactsScreen",
|
|
1987
|
+
id: "contacts-screen-root",
|
|
1988
|
+
props: {}
|
|
1989
|
+
}
|
|
1990
|
+
],
|
|
1991
|
+
defaultProps: {}
|
|
1992
|
+
});
|
|
1993
|
+
PageTemplateRegistry.register({
|
|
1994
|
+
id: CORE_PAGE_IDS.ORDERS,
|
|
1995
|
+
slug: "orders",
|
|
1996
|
+
name: "Orders",
|
|
1997
|
+
description: "Order management provided by Fluid Commerce",
|
|
1998
|
+
category: PAGE_CATEGORIES.CORE,
|
|
1999
|
+
tags: ["orders", "commerce", "sales"],
|
|
2000
|
+
version: "1.0.0",
|
|
2001
|
+
isCore: true,
|
|
2002
|
+
component_tree: [
|
|
2003
|
+
{
|
|
2004
|
+
type: "OrdersScreen",
|
|
2005
|
+
id: "orders-screen-root",
|
|
2006
|
+
props: {}
|
|
2007
|
+
}
|
|
2008
|
+
],
|
|
2009
|
+
defaultProps: {}
|
|
2010
|
+
});
|
|
2011
|
+
PageTemplateRegistry.register({
|
|
2012
|
+
id: CORE_PAGE_IDS.CUSTOMERS,
|
|
2013
|
+
slug: "customers",
|
|
2014
|
+
name: "Customers",
|
|
2015
|
+
description: "Customer management provided by Fluid Commerce",
|
|
2016
|
+
category: PAGE_CATEGORIES.CORE,
|
|
2017
|
+
tags: ["customers", "people", "commerce"],
|
|
2018
|
+
version: "1.0.0",
|
|
2019
|
+
isCore: true,
|
|
2020
|
+
component_tree: [
|
|
2021
|
+
{
|
|
2022
|
+
type: "CustomersScreen",
|
|
2023
|
+
id: "customers-screen-root",
|
|
2024
|
+
props: {}
|
|
2025
|
+
}
|
|
2026
|
+
],
|
|
2027
|
+
defaultProps: {}
|
|
2028
|
+
});
|
|
2029
|
+
PageTemplateRegistry.register({
|
|
2030
|
+
id: CORE_PAGE_IDS.PRODUCTS,
|
|
2031
|
+
slug: "products",
|
|
2032
|
+
name: "Products",
|
|
2033
|
+
description: "Product catalog provided by Fluid Commerce",
|
|
2034
|
+
category: PAGE_CATEGORIES.CORE,
|
|
2035
|
+
tags: ["products", "catalog", "commerce"],
|
|
2036
|
+
version: "1.0.0",
|
|
2037
|
+
isCore: true,
|
|
2038
|
+
component_tree: [
|
|
2039
|
+
{
|
|
2040
|
+
type: "ProductsScreen",
|
|
2041
|
+
id: "products-screen-root",
|
|
2042
|
+
props: {}
|
|
2043
|
+
}
|
|
2044
|
+
],
|
|
2045
|
+
defaultProps: {}
|
|
2046
|
+
});
|
|
2047
|
+
}
|
|
2048
|
+
registerCorePageTemplates();
|
|
2049
|
+
var export_BUILT_IN_THEMES = themes_exports.BUILT_IN_THEMES;
|
|
2050
|
+
var export_CORE_COLOR_KEYS = themes_exports.CORE_COLOR_KEYS;
|
|
2051
|
+
var export_DEFAULT_CORE_COLORS = themes_exports.DEFAULT_CORE_COLORS;
|
|
2052
|
+
var export_catppuccinMocha = themes_exports.catppuccinMocha;
|
|
2053
|
+
var export_clampChroma = themes_exports.clampChroma;
|
|
2054
|
+
var export_defaultTheme = themes_exports.defaultTheme;
|
|
2055
|
+
var export_detectThemeMode = themes_exports.detectThemeMode;
|
|
2056
|
+
var export_dracula = themes_exports.dracula;
|
|
2057
|
+
var export_everforest = themes_exports.everforest;
|
|
2058
|
+
var export_generateColorSwatches = themes_exports.generateColorSwatches;
|
|
2059
|
+
var export_generateDualTheme = themes_exports.generateDualTheme;
|
|
2060
|
+
var export_generateSmartDualTheme = themes_exports.generateSmartDualTheme;
|
|
2061
|
+
var export_generateTheme = themes_exports.generateTheme;
|
|
2062
|
+
var export_generateThemeCssVars = themes_exports.generateThemeCssVars;
|
|
2063
|
+
var export_gruvbox = themes_exports.gruvbox;
|
|
2064
|
+
var export_mod = themes_exports.mod;
|
|
2065
|
+
var export_monokai = themes_exports.monokai;
|
|
2066
|
+
var export_nord = themes_exports.nord;
|
|
2067
|
+
var export_oklchString = themes_exports.oklchString;
|
|
2068
|
+
var export_parseOklch = themes_exports.parseOklch;
|
|
2069
|
+
var export_rosePine = themes_exports.rosePine;
|
|
2070
|
+
var export_rotateHue = themes_exports.rotateHue;
|
|
2071
|
+
var export_rotateSoft = themes_exports.rotateSoft;
|
|
2072
|
+
var export_solarized = themes_exports.solarized;
|
|
2073
|
+
var export_toDarkMode = themes_exports.toDarkMode;
|
|
2074
|
+
var export_toLightMode = themes_exports.toLightMode;
|
|
2075
|
+
var export_tokyoNight = themes_exports.tokyoNight;
|
|
2076
|
+
|
|
2077
|
+
export { ACTIVITY_SLUGS, AUTH_CONSTANTS, ApiError, AuthError, AuthLoading, export_BUILT_IN_THEMES as BUILT_IN_THEMES, export_CORE_COLOR_KEYS as CORE_COLOR_KEYS, CORE_PAGE_IDS, CURRENT_REP_QUERY_KEY, export_DEFAULT_CORE_COLORS as DEFAULT_CORE_COLORS, FluidAuthProvider, FluidProvider, FluidThemeProvider, PAGE_CATEGORIES, PERMISSIONS_QUERY_KEY, PROFILE_QUERY_KEY, PageTemplateProvider, PageTemplateRegistry, RequireAuth, STORAGE_KEYS, URL_PARAMS, USER_TYPES, export_catppuccinMocha as catppuccinMocha, export_clampChroma as clampChroma, cleanTokenFromUrl, clearTokens, createFluidClient, decodeToken, export_defaultTheme as defaultTheme, export_detectThemeMode as detectThemeMode, export_dracula as dracula, export_everforest as everforest, extractAllTokensFromUrl, extractCompanyTokenFromUrl, extractTokenFromUrl, export_generateColorSwatches as generateColorSwatches, export_generateDualTheme as generateDualTheme, export_generateSmartDualTheme as generateSmartDualTheme, export_generateTheme as generateTheme, export_generateThemeCssVars as generateThemeCssVars, getAvailablePageTemplates, getCorePageTemplates, getOptionalPageTemplates, getProperty, getStoredToken, getTokenExpiration, getTokenTimeRemaining, export_gruvbox as gruvbox, hasData, hasStoredToken, hasTokenInUrl, isActivitySlug, isApiError, isContactStatus, isErrorResult, isIdle, isLoading, isTokenExpired, isUserType, isValidToken, export_mod as mod, export_monokai as monokai, export_nord as nord, export_oklchString as oklchString, export_parseOklch as parseOklch, resolveNavigationPages, export_rosePine as rosePine, export_rotateHue as rotateHue, export_rotateSoft as rotateSoft, screenPropertySchemas, selectProperty, export_solarized as solarized, storeToken, export_toDarkMode as toDarkMode, export_toLightMode as toLightMode, export_tokyoNight as tokyoNight, useActivities, useCalendarEvents, useCatchUps, useContact, useContacts, useConversationMessages, useConversations, useCurrentRep, useFluidApi, useFluidAuth, useFluidAuthContext, useFluidContext, useFluidPermissions, useFluidProfile, useFluidTheme, useMySite, usePageTemplates, useResolvedPages, useThemeContext, useTodos, validateNavigationPages, validateToken };
|
|
2078
|
+
//# sourceMappingURL=index.js.map
|
|
2079
|
+
//# sourceMappingURL=index.js.map
|