@fluid-app/portal-sdk 0.1.13 → 0.1.15

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 (45) hide show
  1. package/dist/AccountScreen-B08uxzt6.mjs +2 -0
  2. package/dist/AccountScreen-CQCwpKEC.mjs +741 -0
  3. package/dist/AccountScreen-CQCwpKEC.mjs.map +1 -0
  4. package/dist/AccountScreen-CbhrIAa4.cjs +780 -0
  5. package/dist/AccountScreen-CbhrIAa4.cjs.map +1 -0
  6. package/dist/{ContactsScreen-CB6l0Lf1.mjs → ContactsScreen-CHLFZX_N.mjs} +2 -2
  7. package/dist/{ContactsScreen-CB6l0Lf1.mjs.map → ContactsScreen-CHLFZX_N.mjs.map} +1 -1
  8. package/dist/{ContactsScreen-Dwn5onLu.cjs → ContactsScreen-CjnCemeI.cjs} +4 -4
  9. package/dist/{ContactsScreen-Dwn5onLu.cjs.map → ContactsScreen-CjnCemeI.cjs.map} +1 -1
  10. package/dist/{CoreScreenPlaceholder-Bw8YOPwv.cjs → CoreScreenPlaceholder-C9lBkcyc.cjs} +2 -2
  11. package/dist/{CoreScreenPlaceholder-Bw8YOPwv.cjs.map → CoreScreenPlaceholder-C9lBkcyc.cjs.map} +1 -1
  12. package/dist/{CoreScreenPlaceholder-D93ZYKt2.mjs → CoreScreenPlaceholder-DCJ1hFvJ.mjs} +1 -1
  13. package/dist/{CoreScreenPlaceholder-D93ZYKt2.mjs.map → CoreScreenPlaceholder-DCJ1hFvJ.mjs.map} +1 -1
  14. package/dist/{CustomersScreen-gQb6cWL5.cjs → CustomersScreen-CqwRJogV.cjs} +4 -4
  15. package/dist/{CustomersScreen-gQb6cWL5.cjs.map → CustomersScreen-CqwRJogV.cjs.map} +1 -1
  16. package/dist/{CustomersScreen-BEar6Leg.mjs → CustomersScreen-DBicCB3o.mjs} +2 -2
  17. package/dist/{CustomersScreen-BEar6Leg.mjs.map → CustomersScreen-DBicCB3o.mjs.map} +1 -1
  18. package/dist/{MessagingScreen-YyzXdr95.mjs → FluidProvider-BafZw8PJ.mjs} +6 -503
  19. package/dist/FluidProvider-BafZw8PJ.mjs.map +1 -0
  20. package/dist/{MessagingScreen-Ca22FObh.cjs → FluidProvider-C6SCZDjX.cjs} +3 -542
  21. package/dist/FluidProvider-C6SCZDjX.cjs.map +1 -0
  22. package/dist/MessagingScreen-Bd-1_J9q.cjs +369 -0
  23. package/dist/MessagingScreen-Bd-1_J9q.cjs.map +1 -0
  24. package/dist/MessagingScreen-D8W8V2TW.mjs +2 -0
  25. package/dist/MessagingScreen-DCS0mtbd.mjs +324 -0
  26. package/dist/MessagingScreen-DCS0mtbd.mjs.map +1 -0
  27. package/dist/{OrdersScreen-DB1v051q.mjs → OrdersScreen-B6JCMBY5.mjs} +2 -2
  28. package/dist/{OrdersScreen-DB1v051q.mjs.map → OrdersScreen-B6JCMBY5.mjs.map} +1 -1
  29. package/dist/{OrdersScreen-DbON-kBA.cjs → OrdersScreen-DBxpXgZ9.cjs} +4 -4
  30. package/dist/{OrdersScreen-DbON-kBA.cjs.map → OrdersScreen-DBxpXgZ9.cjs.map} +1 -1
  31. package/dist/{ProductsScreen-CMDGGvE2.cjs → ProductsScreen-BK8cz_MN.cjs} +4 -4
  32. package/dist/{ProductsScreen-CMDGGvE2.cjs.map → ProductsScreen-BK8cz_MN.cjs.map} +1 -1
  33. package/dist/{ProductsScreen-nVDsY6kf.mjs → ProductsScreen-DafsauTY.mjs} +2 -2
  34. package/dist/{ProductsScreen-nVDsY6kf.mjs.map → ProductsScreen-DafsauTY.mjs.map} +1 -1
  35. package/dist/index.cjs +73 -138
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +29 -22
  38. package/dist/index.d.cts.map +1 -1
  39. package/dist/index.d.mts +29 -22
  40. package/dist/index.d.mts.map +1 -1
  41. package/dist/index.mjs +49 -116
  42. package/dist/index.mjs.map +1 -1
  43. package/package.json +19 -13
  44. package/dist/MessagingScreen-Ca22FObh.cjs.map +0 -1
  45. package/dist/MessagingScreen-YyzXdr95.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessagingScreen-Bd-1_J9q.cjs","names":["useFluidContext","useFluidAuthContext","useFluidContext","useFluidAuthContext","useFluidContext","MessagingApp"],"sources":["../src/hooks/use-fluid-api.ts","../src/messaging/use-messaging-auth.ts","../src/messaging/use-messaging-config.ts","../src/messaging/fluid-file-uploader.ts","../src/screens/MessagingScreen.tsx"],"sourcesContent":["import { useFluidContext } from \"../providers/FluidProvider\";\nimport type { FluidClient } from \"../client/fluid-client\";\n\n/**\n * Hook to access the Fluid API client\n *\n * @example\n * ```tsx\n * function ProductList() {\n * const api = useFluidApi();\n *\n * const { data: products } = useQuery({\n * queryKey: [\"products\"],\n * queryFn: () => api.products.list(),\n * });\n *\n * return <ul>{products?.map(p => <li key={p.id}>{p.name}</li>)}</ul>;\n * }\n * ```\n */\nexport function useFluidApi(): FluidClient {\n const { client } = useFluidContext();\n return client;\n}\n","/**\n * Bridge hook: maps portal SDK auth context to MessagingAuthContext.\n *\n * The messaging system identifies users by `recipient_id`, which is NOT in the\n * JWT payload or the /reps/me endpoint. It IS returned by GET /api/me.\n * This hook fetches that data and maps it into the shape MessagingApp expects.\n */\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport type {\n MessagingAuthContext,\n MessagingCurrentUser,\n} from \"@fluid-app/messaging-core\";\nimport { useFluidAuthContext } from \"../providers/FluidAuthProvider\";\nimport { useFluidApi } from \"../hooks/use-fluid-api\";\n\nconst USERS_ME_QUERY_KEY = [\"fluid\", \"users\", \"me\"] as const;\n\nexport function useMessagingAuth(): MessagingAuthContext {\n const auth = useFluidAuthContext();\n const api = useFluidApi();\n\n const {\n data: userMe,\n isLoading: isUserMeLoading,\n isError,\n } = useQuery({\n queryKey: USERS_ME_QUERY_KEY,\n queryFn: () => api.users.me(),\n enabled: auth.isAuthenticated,\n staleTime: Infinity,\n retry: 1,\n });\n\n if (auth.isLoading || (auth.isAuthenticated && isUserMeLoading)) {\n return {\n recipientId: null,\n companyId: null,\n currentUser: null,\n isLoading: true,\n };\n }\n\n if (!auth.isAuthenticated || isError || !userMe) {\n return {\n recipientId: null,\n companyId: null,\n currentUser: null,\n isLoading: false,\n };\n }\n\n const currentUser: MessagingCurrentUser | null = userMe.recipient_id\n ? {\n id: userMe.id,\n recipientId: userMe.recipient_id,\n firstName: userMe.first_name ?? \"\",\n lastName: userMe.last_name ?? \"\",\n email: userMe.email,\n ...(userMe.image_url != null && { imageUrl: userMe.image_url }),\n ...(userMe.affiliate_id != null && {\n affiliateId: userMe.affiliate_id,\n }),\n }\n : null;\n\n return {\n recipientId: userMe.recipient_id,\n companyId: userMe.company_id ?? null,\n currentUser,\n isLoading: false,\n };\n}\n","/**\n * Hook that derives MessagingApiConfig from the portal SDK's FluidProvider context.\n *\n * Maps FluidSDKConfig fields to the shape expected by MessagingApp:\n * - baseUrl -> from config.baseUrl\n * - getHeaders -> builds Authorization header from config.getAuthToken()\n * - onAuthError -> from config.onAuthError\n * - websocketUrl -> config.websocketUrl or derived from baseUrl\n * - token -> from auth context\n */\n\nimport { useCallback, useMemo } from \"react\";\nimport type { MessagingApiConfig } from \"@fluid-app/messaging-api-client\";\nimport { useFluidContext } from \"../providers/FluidProvider\";\nimport { useFluidAuthContext } from \"../providers/FluidAuthProvider\";\n\nexport interface MessagingConfig {\n readonly apiConfig: MessagingApiConfig;\n readonly websocketUrl: string;\n readonly token: string | null;\n}\n\nfunction deriveWebsocketUrl(baseUrl: string): string {\n // Strip trailing slashes and /api suffix, then append /cable\n // Handles both \"https://api.fluid.app\" and \"https://api.fluid.app/api\"\n const base = baseUrl.replace(/\\/+$/, \"\").replace(/\\/api$/, \"\");\n return `${base}/cable`;\n}\n\nexport function useMessagingConfig(): MessagingConfig {\n const { config } = useFluidContext();\n const auth = useFluidAuthContext();\n\n const getHeaders = useCallback(async (): Promise<Record<string, string>> => {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...config.defaultHeaders,\n };\n\n if (config.getAuthToken) {\n const token = await config.getAuthToken();\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n }\n\n return headers;\n }, [config]);\n\n const apiBaseUrl = useMemo(() => {\n const base = config.baseUrl.replace(/\\/+$/, \"\");\n return base.endsWith(\"/api\") ? base : `${base}/api`;\n }, [config.baseUrl]);\n\n const apiConfig = useMemo(\n (): MessagingApiConfig => ({\n baseUrl: apiBaseUrl,\n getHeaders,\n ...(config.onAuthError != null && { onAuthError: config.onAuthError }),\n }),\n [apiBaseUrl, config.onAuthError, getHeaders],\n );\n\n const websocketUrl = useMemo(\n () => config.websocketUrl ?? deriveWebsocketUrl(config.baseUrl),\n [config.websocketUrl, config.baseUrl],\n );\n\n return {\n apiConfig,\n websocketUrl,\n token: auth.token,\n };\n}\n","/**\n * Lightweight Filestack file uploader for the portal SDK.\n *\n * Uploads files to Filestack using the REST API (no filestack-js dependency).\n * Flow: upload to `https://www.filestackapi.com/api/store/S3?key=<apiKey>`\n * Uses XMLHttpRequest for upload progress tracking.\n */\n\nimport type {\n FileUploader,\n UploadCallbacks,\n UploadResult,\n} from \"@fluid-app/messaging-core\";\nimport { getFileTypeFromMimetype } from \"@fluid-app/messaging-core\";\n\nconst FILESTACK_UPLOAD_URL = \"https://www.filestackapi.com/api/store/S3\";\n\nfunction getImageDimensions(\n file: File,\n): Promise<{ width: number; height: number } | null> {\n if (!file.type.startsWith(\"image/\")) return Promise.resolve(null);\n\n return new Promise((resolve) => {\n const img = new Image();\n const url = URL.createObjectURL(file);\n\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve({ width: img.naturalWidth, height: img.naturalHeight });\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n resolve(null);\n };\n\n img.src = url;\n });\n}\n\nfunction uploadToFilestack(\n file: File,\n apiKey: string,\n callbacks: UploadCallbacks,\n): { abort: () => void } {\n const xhr = new XMLHttpRequest();\n let aborted = false;\n\n // Extract dimensions first (for images), then upload\n getImageDimensions(file)\n .then((metadata) => {\n if (aborted) return;\n\n const url = `${FILESTACK_UPLOAD_URL}?key=${encodeURIComponent(apiKey)}`;\n\n xhr.open(\"POST\", url);\n xhr.setRequestHeader(\"Content-Type\", file.type);\n\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n const progress = Math.round((event.loaded / event.total) * 100);\n callbacks.onProgress(progress);\n }\n };\n\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const response = JSON.parse(xhr.responseText) as {\n url: string;\n size: number;\n type: string;\n };\n\n const result: UploadResult = {\n url: response.url,\n size: file.size,\n mimetype: file.type,\n kind: getFileTypeFromMimetype(file.type),\n metadata,\n };\n callbacks.onSuccess(result);\n } catch {\n callbacks.onError(new Error(\"Failed to parse upload response\"));\n }\n } else {\n callbacks.onError(\n new Error(`Upload failed with status ${xhr.status}`),\n );\n }\n };\n\n xhr.onerror = () => {\n if (!aborted) {\n callbacks.onError(new Error(\"Upload failed due to a network error\"));\n }\n };\n\n xhr.onabort = () => {\n // Silently handle abort — caller initiated it\n };\n\n xhr.send(file);\n })\n .catch((error) => {\n if (!aborted) {\n callbacks.onError(\n error instanceof Error\n ? error\n : new Error(\"Upload preparation failed\"),\n );\n }\n });\n\n return {\n abort: () => {\n aborted = true;\n xhr.abort();\n },\n };\n}\n\n/**\n * Creates a FileUploader that uploads to Filestack using the REST API.\n *\n * @param apiKey - Filestack API key. If falsy, returns a noop uploader\n * that rejects uploads with a helpful error message.\n */\nexport function createFluidFileUploader(\n apiKey: string | undefined,\n): FileUploader {\n if (!apiKey) {\n return {\n uploadFile: (_file: File, callbacks: UploadCallbacks) => {\n callbacks.onError(\n new Error(\n \"File uploads are not configured. Set filestackApiKey in your SDK config to enable attachments.\",\n ),\n );\n return { abort: () => {} };\n },\n };\n }\n\n return {\n uploadFile: (file: File, callbacks: UploadCallbacks) =>\n uploadToFilestack(file, apiKey, callbacks),\n };\n}\n","import {\n useCallback,\n useMemo,\n type ComponentProps,\n type ReactNode,\n} from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { MessagingApp } from \"@fluid-app/messaging-ui/app\";\nimport type { TagOption } from \"@fluid-app/messaging-ui\";\nimport {\n extractEmoji,\n formatMessageChannelName,\n} from \"@fluid-app/messaging-ui\";\nimport {\n listConnectedRecipients,\n searchConversations,\n} from \"@fluid-app/messaging-api-client\";\nimport type {\n Recipient,\n NominalConversation,\n} from \"@fluid-app/messaging-api-client\";\nimport { useMessagingAuth } from \"../messaging/use-messaging-auth\";\nimport { useMessagingConfig } from \"../messaging/use-messaging-config\";\nimport { createFluidFileUploader } from \"../messaging/fluid-file-uploader\";\nimport { useFluidContext } from \"../providers/FluidProvider\";\n\ntype MessagingScreenProps = ComponentProps<\"div\"> & {\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Messaging overrides\n onToast?: (message: string, type: \"success\" | \"error\") => void;\n filestackApiKey?: string;\n websocketUrl?: string;\n};\n\nfunction renderImage(props: {\n src: string;\n alt: string;\n width: number;\n height: number;\n className?: string;\n}): ReactNode {\n return (\n <img\n src={props.src}\n alt={props.alt}\n width={props.width}\n height={props.height}\n className={props.className}\n />\n );\n}\n\nfunction defaultToast(message: string, type: \"success\" | \"error\") {\n if (type === \"error\") {\n console.warn(\"[Messaging]\", message);\n }\n}\n\nexport function MessagingScreen({\n onToast,\n filestackApiKey,\n websocketUrl: websocketUrlOverride,\n /* eslint-disable @typescript-eslint/no-unused-vars -- destructured to exclude from divProps spread */\n background,\n textColor,\n accentColor,\n padding,\n borderRadius,\n /* eslint-enable @typescript-eslint/no-unused-vars */\n ...divProps\n}: MessagingScreenProps): React.JSX.Element {\n const { config } = useFluidContext();\n const { apiConfig, websocketUrl, token } = useMessagingConfig();\n const messagingAuth = useMessagingAuth();\n\n const effectiveApiKey = filestackApiKey ?? config.filestackApiKey;\n const uploader = useMemo(\n () => createFluidFileUploader(effectiveApiKey),\n [effectiveApiKey],\n );\n\n const effectiveWsUrl = websocketUrlOverride ?? websocketUrl;\n const effectiveToast = onToast ?? defaultToast;\n\n const searchUsers = useCallback(\n async (query: string): Promise<TagOption[]> => {\n const result = await listConnectedRecipients(apiConfig, {\n filterrific: { search_query: query },\n per_page: 10,\n page: 1,\n });\n // Without `kind`, the API returns Recipient[] (not WithContactRecipient[])\n const recipients = (result?.[1]?.items ?? []) as Recipient[];\n return recipients.map((user) => {\n const hasName =\n [user.first_name, user.last_name].filter(Boolean).length > 0;\n const name = hasName\n ? [user.first_name, user.last_name].filter(Boolean).join(\" \")\n : `User ${user.id}`;\n return {\n id: String(user.id),\n label: name,\n imageType: \"user\" as const,\n userData: {\n first_name: user.first_name,\n last_name: user.last_name,\n image_url: user.avatar_url,\n phone: user.phone || undefined,\n email: user.email || undefined,\n },\n conversationName: name,\n };\n });\n },\n [apiConfig],\n );\n\n const searchChannels = useCallback(\n async (query: string): Promise<TagOption[]> => {\n const channels = ((await searchConversations(apiConfig, {\n filterrific: { search_query: query },\n })) ?? []) as NominalConversation[];\n return channels.map((channel) => {\n const { text: nameWithoutEmoji } = extractEmoji(channel.name);\n return {\n id: `channel-${channel.id}`,\n label: formatMessageChannelName(nameWithoutEmoji),\n imageType: \"channel\" as const,\n userData: {\n first_name: channel.name,\n last_name: null,\n image_url: channel.avatar_url,\n },\n conversationName: channel.name,\n };\n });\n },\n [apiConfig],\n );\n\n if (messagingAuth.isLoading) {\n return (\n <div\n {...divProps}\n className={`flex h-full items-center justify-center ${divProps.className ?? \"\"}`}\n >\n <div className=\"text-muted-foreground\">Loading messaging...</div>\n </div>\n );\n }\n\n if (!messagingAuth.recipientId) {\n return (\n <div\n {...divProps}\n className={`flex h-full items-center justify-center ${divProps.className ?? \"\"}`}\n >\n <div className=\"border-border max-w-sm rounded-lg border border-dashed p-8 text-center\">\n <h2 className=\"text-foreground text-xl font-semibold\">Messaging</h2>\n <p className=\"text-muted-foreground mt-2\">\n Messaging is not available for your account\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div {...divProps} className={`h-full ${divProps.className ?? \"\"}`}>\n <MessagingApp\n config={apiConfig}\n auth={messagingAuth}\n websocketUrl={effectiveWsUrl}\n token={token}\n renderImage={renderImage}\n showAdminFeatures={false}\n onToast={effectiveToast}\n messagesViewProps={{\n uploader,\n saveDrafts: true,\n onToast: effectiveToast,\n }}\n newMessageViewProps={{\n searchUsers,\n searchChannels,\n }}\n />\n </div>\n );\n}\n\nexport const messagingScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"MessagingScreen\",\n displayName: \"Messaging Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { n as messagingScreenPropertySchema } from "./MessagingScreen-DCS0mtbd.mjs";
2
+ export { messagingScreenPropertySchema };
@@ -0,0 +1,324 @@
1
+ import { a as useFluidAuthContext, n as useFluidContext } from "./FluidProvider-BafZw8PJ.mjs";
2
+ import { useCallback, useMemo } from "react";
3
+ import { useQuery } from "@tanstack/react-query";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { getFileTypeFromMimetype } from "@fluid-app/messaging-core";
6
+ import { MessagingApp } from "@fluid-app/messaging-ui/app";
7
+ import { extractEmoji, formatMessageChannelName } from "@fluid-app/messaging-ui";
8
+ import { listConnectedRecipients, searchConversations } from "@fluid-app/messaging-api-client";
9
+ //#region src/hooks/use-fluid-api.ts
10
+ /**
11
+ * Hook to access the Fluid API client
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * function ProductList() {
16
+ * const api = useFluidApi();
17
+ *
18
+ * const { data: products } = useQuery({
19
+ * queryKey: ["products"],
20
+ * queryFn: () => api.products.list(),
21
+ * });
22
+ *
23
+ * return <ul>{products?.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
24
+ * }
25
+ * ```
26
+ */
27
+ function useFluidApi() {
28
+ const { client } = useFluidContext();
29
+ return client;
30
+ }
31
+ //#endregion
32
+ //#region src/messaging/use-messaging-auth.ts
33
+ /**
34
+ * Bridge hook: maps portal SDK auth context to MessagingAuthContext.
35
+ *
36
+ * The messaging system identifies users by `recipient_id`, which is NOT in the
37
+ * JWT payload or the /reps/me endpoint. It IS returned by GET /api/me.
38
+ * This hook fetches that data and maps it into the shape MessagingApp expects.
39
+ */
40
+ const USERS_ME_QUERY_KEY = [
41
+ "fluid",
42
+ "users",
43
+ "me"
44
+ ];
45
+ function useMessagingAuth() {
46
+ const auth = useFluidAuthContext();
47
+ const api = useFluidApi();
48
+ const { data: userMe, isLoading: isUserMeLoading, isError } = useQuery({
49
+ queryKey: USERS_ME_QUERY_KEY,
50
+ queryFn: () => api.users.me(),
51
+ enabled: auth.isAuthenticated,
52
+ staleTime: Infinity,
53
+ retry: 1
54
+ });
55
+ if (auth.isLoading || auth.isAuthenticated && isUserMeLoading) return {
56
+ recipientId: null,
57
+ companyId: null,
58
+ currentUser: null,
59
+ isLoading: true
60
+ };
61
+ if (!auth.isAuthenticated || isError || !userMe) return {
62
+ recipientId: null,
63
+ companyId: null,
64
+ currentUser: null,
65
+ isLoading: false
66
+ };
67
+ const currentUser = userMe.recipient_id ? {
68
+ id: userMe.id,
69
+ recipientId: userMe.recipient_id,
70
+ firstName: userMe.first_name ?? "",
71
+ lastName: userMe.last_name ?? "",
72
+ email: userMe.email,
73
+ ...userMe.image_url != null && { imageUrl: userMe.image_url },
74
+ ...userMe.affiliate_id != null && { affiliateId: userMe.affiliate_id }
75
+ } : null;
76
+ return {
77
+ recipientId: userMe.recipient_id,
78
+ companyId: userMe.company_id ?? null,
79
+ currentUser,
80
+ isLoading: false
81
+ };
82
+ }
83
+ //#endregion
84
+ //#region src/messaging/use-messaging-config.ts
85
+ /**
86
+ * Hook that derives MessagingApiConfig from the portal SDK's FluidProvider context.
87
+ *
88
+ * Maps FluidSDKConfig fields to the shape expected by MessagingApp:
89
+ * - baseUrl -> from config.baseUrl
90
+ * - getHeaders -> builds Authorization header from config.getAuthToken()
91
+ * - onAuthError -> from config.onAuthError
92
+ * - websocketUrl -> config.websocketUrl or derived from baseUrl
93
+ * - token -> from auth context
94
+ */
95
+ function deriveWebsocketUrl(baseUrl) {
96
+ return `${baseUrl.replace(/\/+$/, "").replace(/\/api$/, "")}/cable`;
97
+ }
98
+ function useMessagingConfig() {
99
+ const { config } = useFluidContext();
100
+ const auth = useFluidAuthContext();
101
+ const getHeaders = useCallback(async () => {
102
+ const headers = {
103
+ "Content-Type": "application/json",
104
+ ...config.defaultHeaders
105
+ };
106
+ if (config.getAuthToken) {
107
+ const token = await config.getAuthToken();
108
+ if (token) headers.Authorization = `Bearer ${token}`;
109
+ }
110
+ return headers;
111
+ }, [config]);
112
+ const apiBaseUrl = useMemo(() => {
113
+ const base = config.baseUrl.replace(/\/+$/, "");
114
+ return base.endsWith("/api") ? base : `${base}/api`;
115
+ }, [config.baseUrl]);
116
+ return {
117
+ apiConfig: useMemo(() => ({
118
+ baseUrl: apiBaseUrl,
119
+ getHeaders,
120
+ ...config.onAuthError != null && { onAuthError: config.onAuthError }
121
+ }), [
122
+ apiBaseUrl,
123
+ config.onAuthError,
124
+ getHeaders
125
+ ]),
126
+ websocketUrl: useMemo(() => config.websocketUrl ?? deriveWebsocketUrl(config.baseUrl), [config.websocketUrl, config.baseUrl]),
127
+ token: auth.token
128
+ };
129
+ }
130
+ //#endregion
131
+ //#region src/messaging/fluid-file-uploader.ts
132
+ const FILESTACK_UPLOAD_URL = "https://www.filestackapi.com/api/store/S3";
133
+ function getImageDimensions(file) {
134
+ if (!file.type.startsWith("image/")) return Promise.resolve(null);
135
+ return new Promise((resolve) => {
136
+ const img = new Image();
137
+ const url = URL.createObjectURL(file);
138
+ img.onload = () => {
139
+ URL.revokeObjectURL(url);
140
+ resolve({
141
+ width: img.naturalWidth,
142
+ height: img.naturalHeight
143
+ });
144
+ };
145
+ img.onerror = () => {
146
+ URL.revokeObjectURL(url);
147
+ resolve(null);
148
+ };
149
+ img.src = url;
150
+ });
151
+ }
152
+ function uploadToFilestack(file, apiKey, callbacks) {
153
+ const xhr = new XMLHttpRequest();
154
+ let aborted = false;
155
+ getImageDimensions(file).then((metadata) => {
156
+ if (aborted) return;
157
+ const url = `${FILESTACK_UPLOAD_URL}?key=${encodeURIComponent(apiKey)}`;
158
+ xhr.open("POST", url);
159
+ xhr.setRequestHeader("Content-Type", file.type);
160
+ xhr.upload.onprogress = (event) => {
161
+ if (event.lengthComputable) {
162
+ const progress = Math.round(event.loaded / event.total * 100);
163
+ callbacks.onProgress(progress);
164
+ }
165
+ };
166
+ xhr.onload = () => {
167
+ if (xhr.status >= 200 && xhr.status < 300) try {
168
+ const result = {
169
+ url: JSON.parse(xhr.responseText).url,
170
+ size: file.size,
171
+ mimetype: file.type,
172
+ kind: getFileTypeFromMimetype(file.type),
173
+ metadata
174
+ };
175
+ callbacks.onSuccess(result);
176
+ } catch {
177
+ callbacks.onError(/* @__PURE__ */ new Error("Failed to parse upload response"));
178
+ }
179
+ else callbacks.onError(/* @__PURE__ */ new Error(`Upload failed with status ${xhr.status}`));
180
+ };
181
+ xhr.onerror = () => {
182
+ if (!aborted) callbacks.onError(/* @__PURE__ */ new Error("Upload failed due to a network error"));
183
+ };
184
+ xhr.onabort = () => {};
185
+ xhr.send(file);
186
+ }).catch((error) => {
187
+ if (!aborted) callbacks.onError(error instanceof Error ? error : /* @__PURE__ */ new Error("Upload preparation failed"));
188
+ });
189
+ return { abort: () => {
190
+ aborted = true;
191
+ xhr.abort();
192
+ } };
193
+ }
194
+ /**
195
+ * Creates a FileUploader that uploads to Filestack using the REST API.
196
+ *
197
+ * @param apiKey - Filestack API key. If falsy, returns a noop uploader
198
+ * that rejects uploads with a helpful error message.
199
+ */
200
+ function createFluidFileUploader(apiKey) {
201
+ if (!apiKey) return { uploadFile: (_file, callbacks) => {
202
+ callbacks.onError(/* @__PURE__ */ new Error("File uploads are not configured. Set filestackApiKey in your SDK config to enable attachments."));
203
+ return { abort: () => {} };
204
+ } };
205
+ return { uploadFile: (file, callbacks) => uploadToFilestack(file, apiKey, callbacks) };
206
+ }
207
+ //#endregion
208
+ //#region src/screens/MessagingScreen.tsx
209
+ function renderImage(props) {
210
+ return /* @__PURE__ */ jsx("img", {
211
+ src: props.src,
212
+ alt: props.alt,
213
+ width: props.width,
214
+ height: props.height,
215
+ className: props.className
216
+ });
217
+ }
218
+ function defaultToast(message, type) {
219
+ if (type === "error") console.warn("[Messaging]", message);
220
+ }
221
+ function MessagingScreen({ onToast, filestackApiKey, websocketUrl: websocketUrlOverride, background, textColor, accentColor, padding, borderRadius, ...divProps }) {
222
+ const { config } = useFluidContext();
223
+ const { apiConfig, websocketUrl, token } = useMessagingConfig();
224
+ const messagingAuth = useMessagingAuth();
225
+ const effectiveApiKey = filestackApiKey ?? config.filestackApiKey;
226
+ const uploader = useMemo(() => createFluidFileUploader(effectiveApiKey), [effectiveApiKey]);
227
+ const effectiveWsUrl = websocketUrlOverride ?? websocketUrl;
228
+ const effectiveToast = onToast ?? defaultToast;
229
+ const searchUsers = useCallback(async (query) => {
230
+ return ((await listConnectedRecipients(apiConfig, {
231
+ filterrific: { search_query: query },
232
+ per_page: 10,
233
+ page: 1
234
+ }))?.[1]?.items ?? []).map((user) => {
235
+ const name = [user.first_name, user.last_name].filter(Boolean).length > 0 ? [user.first_name, user.last_name].filter(Boolean).join(" ") : `User ${user.id}`;
236
+ return {
237
+ id: String(user.id),
238
+ label: name,
239
+ imageType: "user",
240
+ userData: {
241
+ first_name: user.first_name,
242
+ last_name: user.last_name,
243
+ image_url: user.avatar_url,
244
+ phone: user.phone || void 0,
245
+ email: user.email || void 0
246
+ },
247
+ conversationName: name
248
+ };
249
+ });
250
+ }, [apiConfig]);
251
+ const searchChannels = useCallback(async (query) => {
252
+ return (await searchConversations(apiConfig, { filterrific: { search_query: query } }) ?? []).map((channel) => {
253
+ const { text: nameWithoutEmoji } = extractEmoji(channel.name);
254
+ return {
255
+ id: `channel-${channel.id}`,
256
+ label: formatMessageChannelName(nameWithoutEmoji),
257
+ imageType: "channel",
258
+ userData: {
259
+ first_name: channel.name,
260
+ last_name: null,
261
+ image_url: channel.avatar_url
262
+ },
263
+ conversationName: channel.name
264
+ };
265
+ });
266
+ }, [apiConfig]);
267
+ if (messagingAuth.isLoading) return /* @__PURE__ */ jsx("div", {
268
+ ...divProps,
269
+ className: `flex h-full items-center justify-center ${divProps.className ?? ""}`,
270
+ children: /* @__PURE__ */ jsx("div", {
271
+ className: "text-muted-foreground",
272
+ children: "Loading messaging..."
273
+ })
274
+ });
275
+ if (!messagingAuth.recipientId) return /* @__PURE__ */ jsx("div", {
276
+ ...divProps,
277
+ className: `flex h-full items-center justify-center ${divProps.className ?? ""}`,
278
+ children: /* @__PURE__ */ jsxs("div", {
279
+ className: "border-border max-w-sm rounded-lg border border-dashed p-8 text-center",
280
+ children: [/* @__PURE__ */ jsx("h2", {
281
+ className: "text-foreground text-xl font-semibold",
282
+ children: "Messaging"
283
+ }), /* @__PURE__ */ jsx("p", {
284
+ className: "text-muted-foreground mt-2",
285
+ children: "Messaging is not available for your account"
286
+ })]
287
+ })
288
+ });
289
+ return /* @__PURE__ */ jsx("div", {
290
+ ...divProps,
291
+ className: `h-full ${divProps.className ?? ""}`,
292
+ children: /* @__PURE__ */ jsx(MessagingApp, {
293
+ config: apiConfig,
294
+ auth: messagingAuth,
295
+ websocketUrl: effectiveWsUrl,
296
+ token,
297
+ renderImage,
298
+ showAdminFeatures: false,
299
+ onToast: effectiveToast,
300
+ messagesViewProps: {
301
+ uploader,
302
+ saveDrafts: true,
303
+ onToast: effectiveToast
304
+ },
305
+ newMessageViewProps: {
306
+ searchUsers,
307
+ searchChannels
308
+ }
309
+ })
310
+ });
311
+ }
312
+ const messagingScreenPropertySchema = {
313
+ widgetType: "MessagingScreen",
314
+ displayName: "Messaging Screen",
315
+ tabsConfig: [{
316
+ id: "styling",
317
+ label: "Styling"
318
+ }],
319
+ fields: []
320
+ };
321
+ //#endregion
322
+ export { useMessagingAuth as a, useMessagingConfig as i, messagingScreenPropertySchema as n, useFluidApi as o, createFluidFileUploader as r, MessagingScreen as t };
323
+
324
+ //# sourceMappingURL=MessagingScreen-DCS0mtbd.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessagingScreen-DCS0mtbd.mjs","names":[],"sources":["../src/hooks/use-fluid-api.ts","../src/messaging/use-messaging-auth.ts","../src/messaging/use-messaging-config.ts","../src/messaging/fluid-file-uploader.ts","../src/screens/MessagingScreen.tsx"],"sourcesContent":["import { useFluidContext } from \"../providers/FluidProvider\";\nimport type { FluidClient } from \"../client/fluid-client\";\n\n/**\n * Hook to access the Fluid API client\n *\n * @example\n * ```tsx\n * function ProductList() {\n * const api = useFluidApi();\n *\n * const { data: products } = useQuery({\n * queryKey: [\"products\"],\n * queryFn: () => api.products.list(),\n * });\n *\n * return <ul>{products?.map(p => <li key={p.id}>{p.name}</li>)}</ul>;\n * }\n * ```\n */\nexport function useFluidApi(): FluidClient {\n const { client } = useFluidContext();\n return client;\n}\n","/**\n * Bridge hook: maps portal SDK auth context to MessagingAuthContext.\n *\n * The messaging system identifies users by `recipient_id`, which is NOT in the\n * JWT payload or the /reps/me endpoint. It IS returned by GET /api/me.\n * This hook fetches that data and maps it into the shape MessagingApp expects.\n */\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport type {\n MessagingAuthContext,\n MessagingCurrentUser,\n} from \"@fluid-app/messaging-core\";\nimport { useFluidAuthContext } from \"../providers/FluidAuthProvider\";\nimport { useFluidApi } from \"../hooks/use-fluid-api\";\n\nconst USERS_ME_QUERY_KEY = [\"fluid\", \"users\", \"me\"] as const;\n\nexport function useMessagingAuth(): MessagingAuthContext {\n const auth = useFluidAuthContext();\n const api = useFluidApi();\n\n const {\n data: userMe,\n isLoading: isUserMeLoading,\n isError,\n } = useQuery({\n queryKey: USERS_ME_QUERY_KEY,\n queryFn: () => api.users.me(),\n enabled: auth.isAuthenticated,\n staleTime: Infinity,\n retry: 1,\n });\n\n if (auth.isLoading || (auth.isAuthenticated && isUserMeLoading)) {\n return {\n recipientId: null,\n companyId: null,\n currentUser: null,\n isLoading: true,\n };\n }\n\n if (!auth.isAuthenticated || isError || !userMe) {\n return {\n recipientId: null,\n companyId: null,\n currentUser: null,\n isLoading: false,\n };\n }\n\n const currentUser: MessagingCurrentUser | null = userMe.recipient_id\n ? {\n id: userMe.id,\n recipientId: userMe.recipient_id,\n firstName: userMe.first_name ?? \"\",\n lastName: userMe.last_name ?? \"\",\n email: userMe.email,\n ...(userMe.image_url != null && { imageUrl: userMe.image_url }),\n ...(userMe.affiliate_id != null && {\n affiliateId: userMe.affiliate_id,\n }),\n }\n : null;\n\n return {\n recipientId: userMe.recipient_id,\n companyId: userMe.company_id ?? null,\n currentUser,\n isLoading: false,\n };\n}\n","/**\n * Hook that derives MessagingApiConfig from the portal SDK's FluidProvider context.\n *\n * Maps FluidSDKConfig fields to the shape expected by MessagingApp:\n * - baseUrl -> from config.baseUrl\n * - getHeaders -> builds Authorization header from config.getAuthToken()\n * - onAuthError -> from config.onAuthError\n * - websocketUrl -> config.websocketUrl or derived from baseUrl\n * - token -> from auth context\n */\n\nimport { useCallback, useMemo } from \"react\";\nimport type { MessagingApiConfig } from \"@fluid-app/messaging-api-client\";\nimport { useFluidContext } from \"../providers/FluidProvider\";\nimport { useFluidAuthContext } from \"../providers/FluidAuthProvider\";\n\nexport interface MessagingConfig {\n readonly apiConfig: MessagingApiConfig;\n readonly websocketUrl: string;\n readonly token: string | null;\n}\n\nfunction deriveWebsocketUrl(baseUrl: string): string {\n // Strip trailing slashes and /api suffix, then append /cable\n // Handles both \"https://api.fluid.app\" and \"https://api.fluid.app/api\"\n const base = baseUrl.replace(/\\/+$/, \"\").replace(/\\/api$/, \"\");\n return `${base}/cable`;\n}\n\nexport function useMessagingConfig(): MessagingConfig {\n const { config } = useFluidContext();\n const auth = useFluidAuthContext();\n\n const getHeaders = useCallback(async (): Promise<Record<string, string>> => {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...config.defaultHeaders,\n };\n\n if (config.getAuthToken) {\n const token = await config.getAuthToken();\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n }\n\n return headers;\n }, [config]);\n\n const apiBaseUrl = useMemo(() => {\n const base = config.baseUrl.replace(/\\/+$/, \"\");\n return base.endsWith(\"/api\") ? base : `${base}/api`;\n }, [config.baseUrl]);\n\n const apiConfig = useMemo(\n (): MessagingApiConfig => ({\n baseUrl: apiBaseUrl,\n getHeaders,\n ...(config.onAuthError != null && { onAuthError: config.onAuthError }),\n }),\n [apiBaseUrl, config.onAuthError, getHeaders],\n );\n\n const websocketUrl = useMemo(\n () => config.websocketUrl ?? deriveWebsocketUrl(config.baseUrl),\n [config.websocketUrl, config.baseUrl],\n );\n\n return {\n apiConfig,\n websocketUrl,\n token: auth.token,\n };\n}\n","/**\n * Lightweight Filestack file uploader for the portal SDK.\n *\n * Uploads files to Filestack using the REST API (no filestack-js dependency).\n * Flow: upload to `https://www.filestackapi.com/api/store/S3?key=<apiKey>`\n * Uses XMLHttpRequest for upload progress tracking.\n */\n\nimport type {\n FileUploader,\n UploadCallbacks,\n UploadResult,\n} from \"@fluid-app/messaging-core\";\nimport { getFileTypeFromMimetype } from \"@fluid-app/messaging-core\";\n\nconst FILESTACK_UPLOAD_URL = \"https://www.filestackapi.com/api/store/S3\";\n\nfunction getImageDimensions(\n file: File,\n): Promise<{ width: number; height: number } | null> {\n if (!file.type.startsWith(\"image/\")) return Promise.resolve(null);\n\n return new Promise((resolve) => {\n const img = new Image();\n const url = URL.createObjectURL(file);\n\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve({ width: img.naturalWidth, height: img.naturalHeight });\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n resolve(null);\n };\n\n img.src = url;\n });\n}\n\nfunction uploadToFilestack(\n file: File,\n apiKey: string,\n callbacks: UploadCallbacks,\n): { abort: () => void } {\n const xhr = new XMLHttpRequest();\n let aborted = false;\n\n // Extract dimensions first (for images), then upload\n getImageDimensions(file)\n .then((metadata) => {\n if (aborted) return;\n\n const url = `${FILESTACK_UPLOAD_URL}?key=${encodeURIComponent(apiKey)}`;\n\n xhr.open(\"POST\", url);\n xhr.setRequestHeader(\"Content-Type\", file.type);\n\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n const progress = Math.round((event.loaded / event.total) * 100);\n callbacks.onProgress(progress);\n }\n };\n\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const response = JSON.parse(xhr.responseText) as {\n url: string;\n size: number;\n type: string;\n };\n\n const result: UploadResult = {\n url: response.url,\n size: file.size,\n mimetype: file.type,\n kind: getFileTypeFromMimetype(file.type),\n metadata,\n };\n callbacks.onSuccess(result);\n } catch {\n callbacks.onError(new Error(\"Failed to parse upload response\"));\n }\n } else {\n callbacks.onError(\n new Error(`Upload failed with status ${xhr.status}`),\n );\n }\n };\n\n xhr.onerror = () => {\n if (!aborted) {\n callbacks.onError(new Error(\"Upload failed due to a network error\"));\n }\n };\n\n xhr.onabort = () => {\n // Silently handle abort — caller initiated it\n };\n\n xhr.send(file);\n })\n .catch((error) => {\n if (!aborted) {\n callbacks.onError(\n error instanceof Error\n ? error\n : new Error(\"Upload preparation failed\"),\n );\n }\n });\n\n return {\n abort: () => {\n aborted = true;\n xhr.abort();\n },\n };\n}\n\n/**\n * Creates a FileUploader that uploads to Filestack using the REST API.\n *\n * @param apiKey - Filestack API key. If falsy, returns a noop uploader\n * that rejects uploads with a helpful error message.\n */\nexport function createFluidFileUploader(\n apiKey: string | undefined,\n): FileUploader {\n if (!apiKey) {\n return {\n uploadFile: (_file: File, callbacks: UploadCallbacks) => {\n callbacks.onError(\n new Error(\n \"File uploads are not configured. Set filestackApiKey in your SDK config to enable attachments.\",\n ),\n );\n return { abort: () => {} };\n },\n };\n }\n\n return {\n uploadFile: (file: File, callbacks: UploadCallbacks) =>\n uploadToFilestack(file, apiKey, callbacks),\n };\n}\n","import {\n useCallback,\n useMemo,\n type ComponentProps,\n type ReactNode,\n} from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { MessagingApp } from \"@fluid-app/messaging-ui/app\";\nimport type { TagOption } from \"@fluid-app/messaging-ui\";\nimport {\n extractEmoji,\n formatMessageChannelName,\n} from \"@fluid-app/messaging-ui\";\nimport {\n listConnectedRecipients,\n searchConversations,\n} from \"@fluid-app/messaging-api-client\";\nimport type {\n Recipient,\n NominalConversation,\n} from \"@fluid-app/messaging-api-client\";\nimport { useMessagingAuth } from \"../messaging/use-messaging-auth\";\nimport { useMessagingConfig } from \"../messaging/use-messaging-config\";\nimport { createFluidFileUploader } from \"../messaging/fluid-file-uploader\";\nimport { useFluidContext } from \"../providers/FluidProvider\";\n\ntype MessagingScreenProps = ComponentProps<\"div\"> & {\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Messaging overrides\n onToast?: (message: string, type: \"success\" | \"error\") => void;\n filestackApiKey?: string;\n websocketUrl?: string;\n};\n\nfunction renderImage(props: {\n src: string;\n alt: string;\n width: number;\n height: number;\n className?: string;\n}): ReactNode {\n return (\n <img\n src={props.src}\n alt={props.alt}\n width={props.width}\n height={props.height}\n className={props.className}\n />\n );\n}\n\nfunction defaultToast(message: string, type: \"success\" | \"error\") {\n if (type === \"error\") {\n console.warn(\"[Messaging]\", message);\n }\n}\n\nexport function MessagingScreen({\n onToast,\n filestackApiKey,\n websocketUrl: websocketUrlOverride,\n /* eslint-disable @typescript-eslint/no-unused-vars -- destructured to exclude from divProps spread */\n background,\n textColor,\n accentColor,\n padding,\n borderRadius,\n /* eslint-enable @typescript-eslint/no-unused-vars */\n ...divProps\n}: MessagingScreenProps): React.JSX.Element {\n const { config } = useFluidContext();\n const { apiConfig, websocketUrl, token } = useMessagingConfig();\n const messagingAuth = useMessagingAuth();\n\n const effectiveApiKey = filestackApiKey ?? config.filestackApiKey;\n const uploader = useMemo(\n () => createFluidFileUploader(effectiveApiKey),\n [effectiveApiKey],\n );\n\n const effectiveWsUrl = websocketUrlOverride ?? websocketUrl;\n const effectiveToast = onToast ?? defaultToast;\n\n const searchUsers = useCallback(\n async (query: string): Promise<TagOption[]> => {\n const result = await listConnectedRecipients(apiConfig, {\n filterrific: { search_query: query },\n per_page: 10,\n page: 1,\n });\n // Without `kind`, the API returns Recipient[] (not WithContactRecipient[])\n const recipients = (result?.[1]?.items ?? []) as Recipient[];\n return recipients.map((user) => {\n const hasName =\n [user.first_name, user.last_name].filter(Boolean).length > 0;\n const name = hasName\n ? [user.first_name, user.last_name].filter(Boolean).join(\" \")\n : `User ${user.id}`;\n return {\n id: String(user.id),\n label: name,\n imageType: \"user\" as const,\n userData: {\n first_name: user.first_name,\n last_name: user.last_name,\n image_url: user.avatar_url,\n phone: user.phone || undefined,\n email: user.email || undefined,\n },\n conversationName: name,\n };\n });\n },\n [apiConfig],\n );\n\n const searchChannels = useCallback(\n async (query: string): Promise<TagOption[]> => {\n const channels = ((await searchConversations(apiConfig, {\n filterrific: { search_query: query },\n })) ?? []) as NominalConversation[];\n return channels.map((channel) => {\n const { text: nameWithoutEmoji } = extractEmoji(channel.name);\n return {\n id: `channel-${channel.id}`,\n label: formatMessageChannelName(nameWithoutEmoji),\n imageType: \"channel\" as const,\n userData: {\n first_name: channel.name,\n last_name: null,\n image_url: channel.avatar_url,\n },\n conversationName: channel.name,\n };\n });\n },\n [apiConfig],\n );\n\n if (messagingAuth.isLoading) {\n return (\n <div\n {...divProps}\n className={`flex h-full items-center justify-center ${divProps.className ?? \"\"}`}\n >\n <div className=\"text-muted-foreground\">Loading messaging...</div>\n </div>\n );\n }\n\n if (!messagingAuth.recipientId) {\n return (\n <div\n {...divProps}\n className={`flex h-full items-center justify-center ${divProps.className ?? \"\"}`}\n >\n <div className=\"border-border max-w-sm rounded-lg border border-dashed p-8 text-center\">\n <h2 className=\"text-foreground text-xl font-semibold\">Messaging</h2>\n <p className=\"text-muted-foreground mt-2\">\n Messaging is not available for your account\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div {...divProps} className={`h-full ${divProps.className ?? \"\"}`}>\n <MessagingApp\n config={apiConfig}\n auth={messagingAuth}\n websocketUrl={effectiveWsUrl}\n token={token}\n renderImage={renderImage}\n showAdminFeatures={false}\n onToast={effectiveToast}\n messagesViewProps={{\n uploader,\n saveDrafts: true,\n onToast: effectiveToast,\n }}\n newMessageViewProps={{\n searchUsers,\n searchChannels,\n }}\n />\n </div>\n );\n}\n\nexport const messagingScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"MessagingScreen\",\n displayName: \"Messaging Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./chunk-D1SwGrFN.mjs";
2
- import { t as CoreScreenPlaceholder } from "./CoreScreenPlaceholder-D93ZYKt2.mjs";
2
+ import { t as CoreScreenPlaceholder } from "./CoreScreenPlaceholder-DCJ1hFvJ.mjs";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  //#region src/screens/OrdersScreen.tsx
5
5
  var OrdersScreen_exports = /* @__PURE__ */ __exportAll({
@@ -21,4 +21,4 @@ const ordersScreenPropertySchema = {
21
21
  //#endregion
22
22
  export { OrdersScreen_exports as n, ordersScreenPropertySchema as r, OrdersScreen as t };
23
23
 
24
- //# sourceMappingURL=OrdersScreen-DB1v051q.mjs.map
24
+ //# sourceMappingURL=OrdersScreen-B6JCMBY5.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"OrdersScreen-DB1v051q.mjs","names":[],"sources":["../src/screens/OrdersScreen.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { CoreScreenPlaceholder } from \"./CoreScreenPlaceholder\";\n\ntype OrdersScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function OrdersScreen(_props: OrdersScreenProps): React.JSX.Element {\n return <CoreScreenPlaceholder name=\"Orders\" />;\n}\n\nexport const ordersScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"OrdersScreen\",\n displayName: \"Orders Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":";;;;;;;;AAmBA,SAAgB,aAAa,QAA8C;AACzE,QAAO,oBAAC,uBAAD,EAAuB,MAAK,UAAW,CAAA;;AAGhD,MAAa,6BAAmD;CAC9D,YAAY;CACZ,aAAa;CACb,YAAY,CAAC;EAAE,IAAI;EAAW,OAAO;EAAW,CAAC;CACjD,QAAQ,EAAE;CACX"}
1
+ {"version":3,"file":"OrdersScreen-B6JCMBY5.mjs","names":[],"sources":["../src/screens/OrdersScreen.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { CoreScreenPlaceholder } from \"./CoreScreenPlaceholder\";\n\ntype OrdersScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function OrdersScreen(_props: OrdersScreenProps): React.JSX.Element {\n return <CoreScreenPlaceholder name=\"Orders\" />;\n}\n\nexport const ordersScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"OrdersScreen\",\n displayName: \"Orders Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":";;;;;;;;AAmBA,SAAgB,aAAa,QAA8C;AACzE,QAAO,oBAAC,uBAAD,EAAuB,MAAK,UAAW,CAAA;;AAGhD,MAAa,6BAAmD;CAC9D,YAAY;CACZ,aAAa;CACb,YAAY,CAAC;EAAE,IAAI;EAAW,OAAO;EAAW,CAAC;CACjD,QAAQ,EAAE;CACX"}
@@ -1,8 +1,8 @@
1
- const require_MessagingScreen = require("./MessagingScreen-Ca22FObh.cjs");
2
- const require_CoreScreenPlaceholder = require("./CoreScreenPlaceholder-Bw8YOPwv.cjs");
1
+ const require_FluidProvider = require("./FluidProvider-C6SCZDjX.cjs");
2
+ const require_CoreScreenPlaceholder = require("./CoreScreenPlaceholder-C9lBkcyc.cjs");
3
3
  let react_jsx_runtime = require("react/jsx-runtime");
4
4
  //#region src/screens/OrdersScreen.tsx
5
- var OrdersScreen_exports = /* @__PURE__ */ require_MessagingScreen.__exportAll({
5
+ var OrdersScreen_exports = /* @__PURE__ */ require_FluidProvider.__exportAll({
6
6
  OrdersScreen: () => OrdersScreen,
7
7
  ordersScreenPropertySchema: () => ordersScreenPropertySchema
8
8
  });
@@ -38,4 +38,4 @@ Object.defineProperty(exports, "ordersScreenPropertySchema", {
38
38
  }
39
39
  });
40
40
 
41
- //# sourceMappingURL=OrdersScreen-DbON-kBA.cjs.map
41
+ //# sourceMappingURL=OrdersScreen-DBxpXgZ9.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"OrdersScreen-DbON-kBA.cjs","names":["CoreScreenPlaceholder"],"sources":["../src/screens/OrdersScreen.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { CoreScreenPlaceholder } from \"./CoreScreenPlaceholder\";\n\ntype OrdersScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function OrdersScreen(_props: OrdersScreenProps): React.JSX.Element {\n return <CoreScreenPlaceholder name=\"Orders\" />;\n}\n\nexport const ordersScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"OrdersScreen\",\n displayName: \"Orders Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":";;;;;;;;AAmBA,SAAgB,aAAa,QAA8C;AACzE,QAAO,iBAAA,GAAA,kBAAA,KAACA,8BAAAA,uBAAD,EAAuB,MAAK,UAAW,CAAA;;AAGhD,MAAa,6BAAmD;CAC9D,YAAY;CACZ,aAAa;CACb,YAAY,CAAC;EAAE,IAAI;EAAW,OAAO;EAAW,CAAC;CACjD,QAAQ,EAAE;CACX"}
1
+ {"version":3,"file":"OrdersScreen-DBxpXgZ9.cjs","names":["CoreScreenPlaceholder"],"sources":["../src/screens/OrdersScreen.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { CoreScreenPlaceholder } from \"./CoreScreenPlaceholder\";\n\ntype OrdersScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function OrdersScreen(_props: OrdersScreenProps): React.JSX.Element {\n return <CoreScreenPlaceholder name=\"Orders\" />;\n}\n\nexport const ordersScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"OrdersScreen\",\n displayName: \"Orders Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":";;;;;;;;AAmBA,SAAgB,aAAa,QAA8C;AACzE,QAAO,iBAAA,GAAA,kBAAA,KAACA,8BAAAA,uBAAD,EAAuB,MAAK,UAAW,CAAA;;AAGhD,MAAa,6BAAmD;CAC9D,YAAY;CACZ,aAAa;CACb,YAAY,CAAC;EAAE,IAAI;EAAW,OAAO;EAAW,CAAC;CACjD,QAAQ,EAAE;CACX"}
@@ -1,8 +1,8 @@
1
- const require_MessagingScreen = require("./MessagingScreen-Ca22FObh.cjs");
2
- const require_CoreScreenPlaceholder = require("./CoreScreenPlaceholder-Bw8YOPwv.cjs");
1
+ const require_FluidProvider = require("./FluidProvider-C6SCZDjX.cjs");
2
+ const require_CoreScreenPlaceholder = require("./CoreScreenPlaceholder-C9lBkcyc.cjs");
3
3
  let react_jsx_runtime = require("react/jsx-runtime");
4
4
  //#region src/screens/ProductsScreen.tsx
5
- var ProductsScreen_exports = /* @__PURE__ */ require_MessagingScreen.__exportAll({
5
+ var ProductsScreen_exports = /* @__PURE__ */ require_FluidProvider.__exportAll({
6
6
  ProductsScreen: () => ProductsScreen,
7
7
  productsScreenPropertySchema: () => productsScreenPropertySchema
8
8
  });
@@ -38,4 +38,4 @@ Object.defineProperty(exports, "productsScreenPropertySchema", {
38
38
  }
39
39
  });
40
40
 
41
- //# sourceMappingURL=ProductsScreen-CMDGGvE2.cjs.map
41
+ //# sourceMappingURL=ProductsScreen-BK8cz_MN.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsScreen-CMDGGvE2.cjs","names":["CoreScreenPlaceholder"],"sources":["../src/screens/ProductsScreen.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { CoreScreenPlaceholder } from \"./CoreScreenPlaceholder\";\n\ntype ProductsScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function ProductsScreen(_props: ProductsScreenProps): React.JSX.Element {\n return <CoreScreenPlaceholder name=\"Products\" />;\n}\n\nexport const productsScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"ProductsScreen\",\n displayName: \"Products Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":";;;;;;;;AAmBA,SAAgB,eAAe,QAAgD;AAC7E,QAAO,iBAAA,GAAA,kBAAA,KAACA,8BAAAA,uBAAD,EAAuB,MAAK,YAAa,CAAA;;AAGlD,MAAa,+BAAqD;CAChE,YAAY;CACZ,aAAa;CACb,YAAY,CAAC;EAAE,IAAI;EAAW,OAAO;EAAW,CAAC;CACjD,QAAQ,EAAE;CACX"}
1
+ {"version":3,"file":"ProductsScreen-BK8cz_MN.cjs","names":["CoreScreenPlaceholder"],"sources":["../src/screens/ProductsScreen.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { CoreScreenPlaceholder } from \"./CoreScreenPlaceholder\";\n\ntype ProductsScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function ProductsScreen(_props: ProductsScreenProps): React.JSX.Element {\n return <CoreScreenPlaceholder name=\"Products\" />;\n}\n\nexport const productsScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"ProductsScreen\",\n displayName: \"Products Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":";;;;;;;;AAmBA,SAAgB,eAAe,QAAgD;AAC7E,QAAO,iBAAA,GAAA,kBAAA,KAACA,8BAAAA,uBAAD,EAAuB,MAAK,YAAa,CAAA;;AAGlD,MAAa,+BAAqD;CAChE,YAAY;CACZ,aAAa;CACb,YAAY,CAAC;EAAE,IAAI;EAAW,OAAO;EAAW,CAAC;CACjD,QAAQ,EAAE;CACX"}
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./chunk-D1SwGrFN.mjs";
2
- import { t as CoreScreenPlaceholder } from "./CoreScreenPlaceholder-D93ZYKt2.mjs";
2
+ import { t as CoreScreenPlaceholder } from "./CoreScreenPlaceholder-DCJ1hFvJ.mjs";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  //#region src/screens/ProductsScreen.tsx
5
5
  var ProductsScreen_exports = /* @__PURE__ */ __exportAll({
@@ -21,4 +21,4 @@ const productsScreenPropertySchema = {
21
21
  //#endregion
22
22
  export { ProductsScreen_exports as n, productsScreenPropertySchema as r, ProductsScreen as t };
23
23
 
24
- //# sourceMappingURL=ProductsScreen-nVDsY6kf.mjs.map
24
+ //# sourceMappingURL=ProductsScreen-DafsauTY.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsScreen-nVDsY6kf.mjs","names":[],"sources":["../src/screens/ProductsScreen.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { CoreScreenPlaceholder } from \"./CoreScreenPlaceholder\";\n\ntype ProductsScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function ProductsScreen(_props: ProductsScreenProps): React.JSX.Element {\n return <CoreScreenPlaceholder name=\"Products\" />;\n}\n\nexport const productsScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"ProductsScreen\",\n displayName: \"Products Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":";;;;;;;;AAmBA,SAAgB,eAAe,QAAgD;AAC7E,QAAO,oBAAC,uBAAD,EAAuB,MAAK,YAAa,CAAA;;AAGlD,MAAa,+BAAqD;CAChE,YAAY;CACZ,aAAa;CACb,YAAY,CAAC;EAAE,IAAI;EAAW,OAAO;EAAW,CAAC;CACjD,QAAQ,EAAE;CACX"}
1
+ {"version":3,"file":"ProductsScreen-DafsauTY.mjs","names":[],"sources":["../src/screens/ProductsScreen.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { CoreScreenPlaceholder } from \"./CoreScreenPlaceholder\";\n\ntype ProductsScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function ProductsScreen(_props: ProductsScreenProps): React.JSX.Element {\n return <CoreScreenPlaceholder name=\"Products\" />;\n}\n\nexport const productsScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"ProductsScreen\",\n displayName: \"Products Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":";;;;;;;;AAmBA,SAAgB,eAAe,QAAgD;AAC7E,QAAO,oBAAC,uBAAD,EAAuB,MAAK,YAAa,CAAA;;AAGlD,MAAa,+BAAqD;CAChE,YAAY;CACZ,aAAa;CACb,YAAY,CAAC;EAAE,IAAI;EAAW,OAAO;EAAW,CAAC;CACjD,QAAQ,EAAE;CACX"}