@teamvortexsoftware/vortex-react-native 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/dist/InviteFormCore-D4HkMMo0.d.mts +721 -0
  2. package/dist/InviteFormCore-D9oUCbu7.d.ts +721 -0
  3. package/dist/VortexClient.js +192 -0
  4. package/dist/VortexClient.js.map +1 -0
  5. package/dist/VortexDeferredLinks.js +127 -0
  6. package/dist/VortexDeferredLinks.js.map +1 -0
  7. package/dist/clientInfo.js +45 -0
  8. package/dist/clientInfo.js.map +1 -0
  9. package/dist/components/ContactsPickerModal.js +182 -0
  10. package/dist/components/ContactsPickerModal.js.map +1 -0
  11. package/dist/components/InviteFormCore.js +2141 -0
  12. package/dist/components/InviteFormCore.js.map +1 -0
  13. package/dist/components/InviteFormMobile.js +463 -0
  14. package/dist/components/InviteFormMobile.js.map +1 -0
  15. package/dist/components/InviteFormWeb.js +295 -0
  16. package/dist/components/InviteFormWeb.js.map +1 -0
  17. package/dist/components/PlacedItemToolbar.js +147 -0
  18. package/dist/components/PlacedItemToolbar.js.map +1 -0
  19. package/dist/components/ShareButtons.js +181 -0
  20. package/dist/components/ShareButtons.js.map +1 -0
  21. package/dist/components/VrtxContactsImport.js +234 -0
  22. package/dist/components/VrtxContactsImport.js.map +1 -0
  23. package/dist/components/VrtxEmailInvitations.js +341 -0
  24. package/dist/components/VrtxEmailInvitations.js.map +1 -0
  25. package/dist/components/VrtxFindFriends.js +400 -0
  26. package/dist/components/VrtxFindFriends.js.map +1 -0
  27. package/dist/components/VrtxHeading.js +58 -0
  28. package/dist/components/VrtxHeading.js.map +1 -0
  29. package/dist/components/VrtxIncomingInvitations.js +657 -0
  30. package/dist/components/VrtxIncomingInvitations.js.map +1 -0
  31. package/dist/components/VrtxInvitationSuggestions.js +506 -0
  32. package/dist/components/VrtxInvitationSuggestions.js.map +1 -0
  33. package/dist/components/VrtxInviteContacts.js +512 -0
  34. package/dist/components/VrtxInviteContacts.js.map +1 -0
  35. package/dist/components/VrtxOutgoingInvitations.js +572 -0
  36. package/dist/components/VrtxOutgoingInvitations.js.map +1 -0
  37. package/dist/components/VrtxSearchBox.js +487 -0
  38. package/dist/components/VrtxSearchBox.js.map +1 -0
  39. package/dist/components/VrtxSelect.js +27 -0
  40. package/dist/components/VrtxSelect.js.map +1 -0
  41. package/dist/components/VrtxShareOptions.js +435 -0
  42. package/dist/components/VrtxShareOptions.js.map +1 -0
  43. package/dist/components/VrtxSubmit.js +132 -0
  44. package/dist/components/VrtxSubmit.js.map +1 -0
  45. package/dist/components/VrtxText.js +146 -0
  46. package/dist/components/VrtxText.js.map +1 -0
  47. package/dist/constants/mockData.d.mts +7 -0
  48. package/dist/constants/mockData.d.ts +7 -0
  49. package/dist/constants/mockData.js +48 -0
  50. package/dist/constants/mockData.js.map +1 -0
  51. package/dist/constants/mockData.mjs +22 -0
  52. package/dist/constants/mockData.mjs.map +1 -0
  53. package/dist/context/VortexModulesContext.js +135 -0
  54. package/dist/context/VortexModulesContext.js.map +1 -0
  55. package/dist/hooks/useInvitationFormLogic.d.mts +2 -0
  56. package/dist/hooks/useInvitationFormLogic.d.ts +2 -0
  57. package/dist/hooks/useInvitationFormLogic.js +300 -0
  58. package/dist/hooks/useInvitationFormLogic.js.map +1 -0
  59. package/dist/hooks/useInvitationFormLogic.mjs +276 -0
  60. package/dist/hooks/useInvitationFormLogic.mjs.map +1 -0
  61. package/dist/hooks/usePrefetchWidgetConfiguration.js +117 -0
  62. package/dist/hooks/usePrefetchWidgetConfiguration.js.map +1 -0
  63. package/dist/hooks/useThemeStyles.js +41 -0
  64. package/dist/hooks/useThemeStyles.js.map +1 -0
  65. package/dist/hooks/useVortexInvite.js +732 -0
  66. package/dist/hooks/useVortexInvite.js.map +1 -0
  67. package/dist/index-web.d.mts +93 -0
  68. package/dist/index-web.d.ts +93 -0
  69. package/dist/index-web.js +7397 -0
  70. package/dist/index-web.js.map +1 -0
  71. package/dist/index-web.mjs +7445 -0
  72. package/dist/index-web.mjs.map +1 -0
  73. package/dist/index.d.mts +656 -0
  74. package/dist/index.d.ts +656 -0
  75. package/dist/index.js +10206 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/index.mjs +10244 -0
  78. package/dist/index.mjs.map +1 -0
  79. package/dist/types/VortexClient.d.ts +106 -0
  80. package/dist/types/VortexClient.d.ts.map +1 -0
  81. package/dist/types/VortexDeferredLinks.d.ts +73 -0
  82. package/dist/types/VortexDeferredLinks.d.ts.map +1 -0
  83. package/dist/types/clientInfo.d.ts +5 -0
  84. package/dist/types/clientInfo.d.ts.map +1 -0
  85. package/dist/types/components/ContactsPickerModal.d.ts +18 -0
  86. package/dist/types/components/ContactsPickerModal.d.ts.map +1 -0
  87. package/dist/types/components/InviteFormCore.d.ts +166 -0
  88. package/dist/types/components/InviteFormCore.d.ts.map +1 -0
  89. package/dist/types/components/InviteFormMobile.d.ts +42 -0
  90. package/dist/types/components/InviteFormMobile.d.ts.map +1 -0
  91. package/dist/types/components/InviteFormWeb.d.ts +87 -0
  92. package/dist/types/components/InviteFormWeb.d.ts.map +1 -0
  93. package/dist/types/components/PlacedItemToolbar.d.ts +16 -0
  94. package/dist/types/components/PlacedItemToolbar.d.ts.map +1 -0
  95. package/dist/types/components/ShareButtons.d.ts +29 -0
  96. package/dist/types/components/ShareButtons.d.ts.map +1 -0
  97. package/dist/types/components/VrtxContactsImport.d.ts +14 -0
  98. package/dist/types/components/VrtxContactsImport.d.ts.map +1 -0
  99. package/dist/types/components/VrtxEmailInvitations.d.ts +31 -0
  100. package/dist/types/components/VrtxEmailInvitations.d.ts.map +1 -0
  101. package/dist/types/components/VrtxFindFriends.d.ts +25 -0
  102. package/dist/types/components/VrtxFindFriends.d.ts.map +1 -0
  103. package/dist/types/components/VrtxHeading.d.ts +6 -0
  104. package/dist/types/components/VrtxHeading.d.ts.map +1 -0
  105. package/dist/types/components/VrtxIncomingInvitations.d.ts +27 -0
  106. package/dist/types/components/VrtxIncomingInvitations.d.ts.map +1 -0
  107. package/dist/types/components/VrtxInvitationSuggestions.d.ts +25 -0
  108. package/dist/types/components/VrtxInvitationSuggestions.d.ts.map +1 -0
  109. package/dist/types/components/VrtxInviteContacts.d.ts +24 -0
  110. package/dist/types/components/VrtxInviteContacts.d.ts.map +1 -0
  111. package/dist/types/components/VrtxOutgoingInvitations.d.ts +27 -0
  112. package/dist/types/components/VrtxOutgoingInvitations.d.ts.map +1 -0
  113. package/dist/types/components/VrtxSearchBox.d.ts +28 -0
  114. package/dist/types/components/VrtxSearchBox.d.ts.map +1 -0
  115. package/dist/types/components/VrtxSelect.d.ts +6 -0
  116. package/dist/types/components/VrtxSelect.d.ts.map +1 -0
  117. package/dist/types/components/VrtxShareOptions.d.ts +41 -0
  118. package/dist/types/components/VrtxShareOptions.d.ts.map +1 -0
  119. package/dist/types/components/VrtxSubmit.d.ts +18 -0
  120. package/dist/types/components/VrtxSubmit.d.ts.map +1 -0
  121. package/dist/types/components/VrtxText.d.ts +8 -0
  122. package/dist/types/components/VrtxText.d.ts.map +1 -0
  123. package/dist/types/constants/mockData.d.ts +4 -0
  124. package/dist/types/constants/mockData.d.ts.map +1 -0
  125. package/dist/types/context/VortexModulesContext.d.ts +238 -0
  126. package/dist/types/context/VortexModulesContext.d.ts.map +1 -0
  127. package/dist/types/findFriends.js +10 -0
  128. package/dist/types/findFriends.js.map +1 -0
  129. package/dist/types/hooks/useInvitationFormLogic.d.ts +55 -0
  130. package/dist/types/hooks/useInvitationFormLogic.d.ts.map +1 -0
  131. package/dist/types/hooks/usePrefetchWidgetConfiguration.d.ts +39 -0
  132. package/dist/types/hooks/usePrefetchWidgetConfiguration.d.ts.map +1 -0
  133. package/dist/types/hooks/useThemeStyles.d.ts +35 -0
  134. package/dist/types/hooks/useThemeStyles.d.ts.map +1 -0
  135. package/dist/types/hooks/useVortexInvite.d.ts +86 -0
  136. package/dist/types/hooks/useVortexInvite.d.ts.map +1 -0
  137. package/dist/types/index-web.d.ts +23 -0
  138. package/dist/types/index-web.d.ts.map +1 -0
  139. package/dist/types/index.d.ts +23 -0
  140. package/dist/types/index.d.ts.map +1 -0
  141. package/dist/types/invitations.js +13 -0
  142. package/dist/types/invitations.js.map +1 -0
  143. package/dist/types/inviteContacts.js +14 -0
  144. package/dist/types/inviteContacts.js.map +1 -0
  145. package/dist/types/platformOperations.js +3 -0
  146. package/dist/types/platformOperations.js.map +1 -0
  147. package/dist/types/searchBox.js +11 -0
  148. package/dist/types/searchBox.js.map +1 -0
  149. package/dist/types/types/findFriends.d.ts +101 -0
  150. package/dist/types/types/findFriends.d.ts.map +1 -0
  151. package/dist/types/types/invitations.d.ts +301 -0
  152. package/dist/types/types/invitations.d.ts.map +1 -0
  153. package/dist/types/types/inviteContacts.d.ts +86 -0
  154. package/dist/types/types/inviteContacts.d.ts.map +1 -0
  155. package/dist/types/types/platformOperations.d.ts +185 -0
  156. package/dist/types/types/platformOperations.d.ts.map +1 -0
  157. package/dist/types/types/searchBox.d.ts +69 -0
  158. package/dist/types/types/searchBox.d.ts.map +1 -0
  159. package/dist/types/types/unfurlConfig.d.ts +34 -0
  160. package/dist/types/types/unfurlConfig.d.ts.map +1 -0
  161. package/dist/types/unfurlConfig.js +21 -0
  162. package/dist/types/unfurlConfig.js.map +1 -0
  163. package/dist/types/utils/analytics.d.ts +54 -0
  164. package/dist/types/utils/analytics.d.ts.map +1 -0
  165. package/dist/types/utils/configCache.d.ts +34 -0
  166. package/dist/types/utils/configCache.d.ts.map +1 -0
  167. package/dist/types/utils/contactUtils.d.ts +9 -0
  168. package/dist/types/utils/contactUtils.d.ts.map +1 -0
  169. package/dist/types/utils/featureWarnings.d.ts +56 -0
  170. package/dist/types/utils/featureWarnings.d.ts.map +1 -0
  171. package/dist/types/utils/formUtils.d.ts +93 -0
  172. package/dist/types/utils/formUtils.d.ts.map +1 -0
  173. package/dist/types/utils/gradientUtils.d.ts +67 -0
  174. package/dist/types/utils/gradientUtils.d.ts.map +1 -0
  175. package/dist/types/utils/invitationEvents.d.ts +21 -0
  176. package/dist/types/utils/invitationEvents.d.ts.map +1 -0
  177. package/dist/types/utils/moduleLoaders.d.ts +115 -0
  178. package/dist/types/utils/moduleLoaders.d.ts.map +1 -0
  179. package/dist/types/utils/moduleLoaders.web.d.ts +73 -0
  180. package/dist/types/utils/moduleLoaders.web.d.ts.map +1 -0
  181. package/dist/types/utils/nameUtils.d.ts +15 -0
  182. package/dist/types/utils/nameUtils.d.ts.map +1 -0
  183. package/dist/types/utils/themeUtils.d.ts +38 -0
  184. package/dist/types/utils/themeUtils.d.ts.map +1 -0
  185. package/dist/types/vortexInvite.d.ts +165 -0
  186. package/dist/types/vortexInvite.d.ts.map +1 -0
  187. package/dist/useInvitationFormLogic-Ct73M19B.d.mts +242 -0
  188. package/dist/useInvitationFormLogic-Ct73M19B.d.ts +242 -0
  189. package/dist/utils/analytics.js +92 -0
  190. package/dist/utils/analytics.js.map +1 -0
  191. package/dist/utils/configCache.js +68 -0
  192. package/dist/utils/configCache.js.map +1 -0
  193. package/dist/utils/contactUtils.d.mts +12 -0
  194. package/dist/utils/contactUtils.d.ts +12 -0
  195. package/dist/utils/contactUtils.js +37 -0
  196. package/dist/utils/contactUtils.js.map +1 -0
  197. package/dist/utils/contactUtils.mjs +12 -0
  198. package/dist/utils/contactUtils.mjs.map +1 -0
  199. package/dist/utils/featureWarnings.js +214 -0
  200. package/dist/utils/featureWarnings.js.map +1 -0
  201. package/dist/utils/formUtils.js +284 -0
  202. package/dist/utils/formUtils.js.map +1 -0
  203. package/dist/utils/gradientUtils.js +120 -0
  204. package/dist/utils/gradientUtils.js.map +1 -0
  205. package/dist/utils/invitationEvents.js +45 -0
  206. package/dist/utils/invitationEvents.js.map +1 -0
  207. package/dist/utils/moduleLoaders.js +275 -0
  208. package/dist/utils/moduleLoaders.js.map +1 -0
  209. package/dist/utils/moduleLoaders.web.js +72 -0
  210. package/dist/utils/moduleLoaders.web.js.map +1 -0
  211. package/dist/utils/nameUtils.js +51 -0
  212. package/dist/utils/nameUtils.js.map +1 -0
  213. package/dist/utils/themeUtils.js +141 -0
  214. package/dist/utils/themeUtils.js.map +1 -0
  215. package/dist/vortexInvite.js +83 -0
  216. package/dist/vortexInvite.js.map +1 -0
  217. package/package.json +21 -56
@@ -0,0 +1,732 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.useVortexInvite = useVortexInvite;
16
+ const react_1 = require("react");
17
+ const react_native_1 = require("react-native");
18
+ const themeUtils_1 = require("../utils/themeUtils");
19
+ const useThemeStyles_1 = require("./useThemeStyles");
20
+ const react_native_uuid_1 = __importDefault(require("react-native-uuid"));
21
+ const formUtils_1 = require("../utils/formUtils");
22
+ const vortex_shared_ui_1 = require("@teamvortexsoftware/vortex-shared-ui");
23
+ const configCache_1 = require("../utils/configCache");
24
+ const analytics_client_1 = require("@teamvortexsoftware/analytics-client");
25
+ const analytics_1 = require("../utils/analytics");
26
+ function useVortexInvite({ componentId, vortexApiUrl, isLoading = false, jwt, user, onSuccess, onError, group, groups, scope, scopeType, widgetConfiguration: initialWidgetConfiguration, analyticsBaseURL, onEvent, analyticsSegmentation, locale, }) {
27
+ // Check FIRST, before any hooks are called
28
+ if (!componentId) {
29
+ throw Error('[Vortex Invite] componentId is required to fetch configuration');
30
+ }
31
+ // Create effective groups with fallback logic: group > scope+scopeType
32
+ const effectiveGroup = (0, react_1.useMemo)(() => {
33
+ if (group)
34
+ return group;
35
+ if (scope && scopeType) {
36
+ return { type: scopeType, groupId: scope, name: scope };
37
+ }
38
+ return undefined;
39
+ }, [group, scope, scopeType]);
40
+ // If user is provided, construct the insecure JWT token
41
+ const effectiveJwt = (0, react_1.useMemo)(() => {
42
+ if (jwt)
43
+ return jwt;
44
+ if (user) {
45
+ if (typeof user === 'string') {
46
+ return user;
47
+ }
48
+ const payload = Object.assign(Object.assign({}, user), { componentId });
49
+ const jsonString = JSON.stringify(payload);
50
+ const base64Encoded = Buffer.from(jsonString).toString('base64');
51
+ return `raw-data:${base64Encoded}`;
52
+ }
53
+ return undefined;
54
+ }, [jwt, user, componentId]);
55
+ const vortexClient = (0, react_1.useMemo)(() => {
56
+ const clientInfo = (0, vortex_shared_ui_1.getClientInfo)();
57
+ const sessionId = react_native_uuid_1.default.v4();
58
+ return new vortex_shared_ui_1.VortexClient(vortexApiUrl, clientInfo.name, clientInfo.version, sessionId);
59
+ }, [vortexApiUrl]);
60
+ // Initialize from cache first, then fall back to initialWidgetConfiguration prop
61
+ const cachedConfig = configCache_1.configCache.get(componentId);
62
+ const [widgetConfiguration, setWidgetConfiguration] = (0, react_1.useState)(cachedConfig || initialWidgetConfiguration);
63
+ const [error, setError] = (0, react_1.useState)(null);
64
+ const [fetching, setFetching] = (0, react_1.useState)(isLoading);
65
+ const [loading, setLoading] = (0, react_1.useState)(!cachedConfig && !initialWidgetConfiguration); // Start as false if we have cached or prefetched config
66
+ const [email, setEmail] = (0, react_1.useState)('');
67
+ const [shareableLink, setShareableLink] = (0, react_1.useState)();
68
+ const [role, setRole] = (0, react_1.useState)(undefined);
69
+ const [inviteLoading, setInviteLoading] = (0, react_1.useState)(false);
70
+ const [showSuccessMessage, setShowSuccessMessage] = (0, react_1.useState)(false);
71
+ const opacity = new react_native_1.Animated.Value(0.3);
72
+ // Analytics state
73
+ const [deploymentId, setDeploymentId] = (0, react_1.useState)(null);
74
+ const [sessionId] = (0, react_1.useState)(() => react_native_uuid_1.default.v4());
75
+ const [widgetRenderTracked, setWidgetRenderTracked] = (0, react_1.useState)(false);
76
+ const [formRenderTime, setFormRenderTime] = (0, react_1.useState)(null);
77
+ // Track when config has been fetched through VortexClient (which sets sessionAttestation)
78
+ const [configFetchedViaClient, setConfigFetchedViaClient] = (0, react_1.useState)(false);
79
+ // Create analytics client (memoized to avoid recreation)
80
+ const analyticsClient = (0, react_1.useMemo)(() => {
81
+ if (!effectiveJwt)
82
+ return null;
83
+ const analyticsUrl = analyticsBaseURL || analytics_1.DEFAULT_ANALYTICS_URL;
84
+ const clientInfo = (0, vortex_shared_ui_1.getClientInfo)();
85
+ return new analytics_client_1.AnalyticsClient(analyticsUrl, effectiveJwt, sessionId, clientInfo.name, clientInfo.version);
86
+ }, [effectiveJwt, analyticsBaseURL, sessionId]);
87
+ // Compute effective groups for analytics
88
+ const effectiveGroups = (0, react_1.useMemo)(() => {
89
+ if (groups && groups.length > 0)
90
+ return groups;
91
+ if (effectiveGroup) {
92
+ return [{
93
+ type: effectiveGroup.type,
94
+ id: effectiveGroup.groupId || effectiveGroup.id || '',
95
+ name: effectiveGroup.name,
96
+ }];
97
+ }
98
+ return undefined;
99
+ }, [groups, effectiveGroup]);
100
+ // Core event tracking function
101
+ const trackEvent = (0, react_1.useCallback)((name, payload) => __awaiter(this, void 0, void 0, function* () {
102
+ const event = {
103
+ name,
104
+ widgetConfigurationId: (widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.id) || '',
105
+ deploymentId: deploymentId || '',
106
+ environmentId: '', // Not currently used (matches web SDK)
107
+ platform: react_native_1.Platform.OS, // 'ios' or 'android'
108
+ timestamp: Math.floor(Date.now() / 1000), // Unix seconds
109
+ sessionId,
110
+ useragent: (0, analytics_1.getDeviceInfo)(),
111
+ foreignUserId: (0, analytics_1.extractForeignUserId)(effectiveJwt),
112
+ segmentation: analyticsSegmentation,
113
+ payload,
114
+ groups: effectiveGroups,
115
+ };
116
+ // Call user's onEvent callback
117
+ if (onEvent) {
118
+ onEvent(event);
119
+ }
120
+ // Send to analytics backend (fire-and-forget, non-blocking)
121
+ if (analyticsClient && deploymentId && widgetConfiguration) {
122
+ analyticsClient.track(event).catch(() => {
123
+ // Silently ignore errors - analytics should never impact user experience
124
+ });
125
+ }
126
+ }), [
127
+ widgetConfiguration,
128
+ deploymentId,
129
+ sessionId,
130
+ effectiveJwt,
131
+ analyticsSegmentation,
132
+ effectiveGroups,
133
+ onEvent,
134
+ analyticsClient,
135
+ ]);
136
+ // Track widget render once per hook instance (on initial render only)
137
+ // The flag resets when component unmounts, so remounting fires a new event (expected behavior)
138
+ const trackWidgetRender = (0, react_1.useCallback)(() => {
139
+ if (widgetRenderTracked)
140
+ return;
141
+ setWidgetRenderTracked(true);
142
+ setFormRenderTime(Date.now());
143
+ trackEvent(analytics_client_1.EventNames.INVITE_FORM_RENDER_SUCCEEDED);
144
+ }, [widgetRenderTracked, trackEvent]);
145
+ // Track widget error
146
+ const trackWidgetError = (0, react_1.useCallback)((errorMessage) => {
147
+ trackEvent(analytics_client_1.EventNames.INVITE_FORM_RENDER_FAILED, { error: errorMessage });
148
+ }, [trackEvent]);
149
+ // Track share link clicks
150
+ const trackShareLinkClick = (0, react_1.useCallback)((clickName) => {
151
+ trackEvent(analytics_client_1.EventNames.SHARING_DESTINATION_BUTTON_CLICKED, { clickName });
152
+ }, [trackEvent]);
153
+ // Track email field focus
154
+ const trackEmailFieldFocus = (0, react_1.useCallback)(() => {
155
+ const timestamp = formRenderTime ? Date.now() - formRenderTime : 0;
156
+ trackEvent(analytics_client_1.EventNames.EMAIL_FIELD_FOCUSSED, { timestamp });
157
+ }, [formRenderTime, trackEvent]);
158
+ // Track email field blur
159
+ const trackEmailFieldBlur = (0, react_1.useCallback)(() => {
160
+ const timestamp = formRenderTime ? Date.now() - formRenderTime : 0;
161
+ trackEvent(analytics_client_1.EventNames.EMAIL_FIELD_BLURRED, { timestamp });
162
+ }, [formRenderTime, trackEvent]);
163
+ // Track email validation
164
+ const trackEmailValidation = (0, react_1.useCallback)((emailValue, isValid) => {
165
+ trackEvent(analytics_client_1.EventNames.EMAIL_SUBMISSION_VALIDATED, { email: emailValue, isValid });
166
+ }, [trackEvent]);
167
+ // Track form submission
168
+ const trackEmailInvitationsSubmitted = (0, react_1.useCallback)((formData) => {
169
+ trackEvent(analytics_client_1.EventNames.EMAIL_FIELD_SUBMISSION_SUCCEEDED, { formData });
170
+ }, [trackEvent]);
171
+ // Track email validation error (now uses WIDGET_EMAIL_VALIDATION with error payload)
172
+ const trackEmailValidationError = (0, react_1.useCallback)((formData) => {
173
+ trackEvent(analytics_client_1.EventNames.EMAIL_SUBMISSION_VALIDATED, { formData, hasError: true });
174
+ }, [trackEvent]);
175
+ // Track email submit error
176
+ const trackEmailSubmitError = (0, react_1.useCallback)((errorMessage) => {
177
+ trackEvent(analytics_client_1.EventNames.EMAIL_FIELD_SUBMISSION_FAILED, { error: errorMessage });
178
+ }, [trackEvent]);
179
+ // Extract theme colors and feature flags using utility functions
180
+ const themeColors = (0, react_1.useMemo)(() => (0, themeUtils_1.extractThemeColors)(widgetConfiguration), [widgetConfiguration]);
181
+ // Extract form configuration
182
+ const formConfig = (0, react_1.useMemo)(() => (0, formUtils_1.extractFormConfiguration)(widgetConfiguration), [widgetConfiguration]);
183
+ // Get base theme styles
184
+ const baseThemeStyles = (0, useThemeStyles_1.useThemeStyles)(themeColors);
185
+ // Merge theme styles with component-specific styles from form configuration
186
+ const themeStyles = (0, react_1.useMemo)(() => (0, formUtils_1.mergeThemeAndComponentStyles)(baseThemeStyles, themeColors, formConfig), [baseThemeStyles, themeColors, formConfig]);
187
+ const options = (0, react_1.useMemo)(() => {
188
+ var _a;
189
+ return ((_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) || {};
190
+ }, [widgetConfiguration]);
191
+ // Extract form layout information
192
+ const formLayout = (0, react_1.useMemo)(() => ({
193
+ emailPlaceholder: (0, formUtils_1.getEmailPlaceholder)(formConfig),
194
+ submitButtonLabel: (0, formUtils_1.getSubmitButtonLabel)(formConfig),
195
+ isGridLayout: (0, formUtils_1.hasGridLayout)(formConfig),
196
+ hasSeparateColumns: (0, formUtils_1.hasEmailAndShareInSeparateColumns)(formConfig),
197
+ formConfig,
198
+ }), [formConfig]);
199
+ // Extract role options and initialize default role
200
+ const roleOptions = (0, react_1.useMemo)(() => (0, formUtils_1.getRoleOptions)(formConfig), [formConfig]);
201
+ (0, react_1.useEffect)(() => {
202
+ var _a;
203
+ if (!role && roleOptions.length > 0) {
204
+ setRole((_a = roleOptions[0]) === null || _a === void 0 ? void 0 : _a.value);
205
+ }
206
+ }, [role, roleOptions]);
207
+ const has = (0, react_1.useMemo)(() => {
208
+ const flags = (0, themeUtils_1.extractFeatureFlags)(widgetConfiguration);
209
+ console.log('[Vortex] Invite has', flags);
210
+ return flags;
211
+ }, [widgetConfiguration]);
212
+ // Log the host only once when the hook mounts
213
+ (0, react_1.useEffect)(() => {
214
+ if (vortexApiUrl.indexOf('localhost') > -1) {
215
+ console.warn('[Vortex] Invite Using localhost as host');
216
+ }
217
+ }, [vortexApiUrl]);
218
+ // Loading animation effect (skip if we have prefetched configuration)
219
+ (0, react_1.useEffect)(() => {
220
+ // If we already have configuration, no need for loading animation
221
+ if (initialWidgetConfiguration) {
222
+ return;
223
+ }
224
+ const animation = react_native_1.Animated.loop(react_native_1.Animated.sequence([
225
+ react_native_1.Animated.timing(opacity, {
226
+ toValue: 1,
227
+ duration: 1000,
228
+ useNativeDriver: false,
229
+ }),
230
+ react_native_1.Animated.timing(opacity, {
231
+ toValue: 0.3,
232
+ duration: 1000,
233
+ useNativeDriver: false,
234
+ }),
235
+ ]));
236
+ animation.start();
237
+ setTimeout(() => {
238
+ setLoading(false);
239
+ animation.stop();
240
+ }, 2000);
241
+ }, [opacity, initialWidgetConfiguration]);
242
+ // Fetch widget configuration (always fetch to get latest, but don't show loading if we have prefetched data)
243
+ (0, react_1.useEffect)(() => {
244
+ if (!effectiveJwt) {
245
+ console.log('[Vortex] Invite JWT is required');
246
+ return;
247
+ }
248
+ const fetchData = () => __awaiter(this, void 0, void 0, function* () {
249
+ var _a;
250
+ // Only show loading state if we don't have ANY configuration yet
251
+ const shouldShowLoading = !widgetConfiguration;
252
+ if (shouldShowLoading) {
253
+ console.log('[Vortex] Invite Fetching Data (first load)...');
254
+ setFetching(true);
255
+ setLoading(true);
256
+ }
257
+ else {
258
+ console.log('[Vortex] Invite Refreshing configuration in background...');
259
+ }
260
+ setError(null);
261
+ try {
262
+ const result = yield vortexClient.getWidgetConfiguration(componentId, effectiveJwt, undefined, locale);
263
+ if ((_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.widgetConfiguration) {
264
+ const freshConfig = result.data.widgetConfiguration;
265
+ setWidgetConfiguration(freshConfig);
266
+ configCache_1.configCache.set(componentId, freshConfig); // Update shared cache
267
+ // Mark that config was fetched via VortexClient (sessionAttestation is now set)
268
+ setConfigFetchedViaClient(true);
269
+ // Extract deploymentId from API response (CRITICAL for analytics)
270
+ if (result.data.deploymentId) {
271
+ setDeploymentId(result.data.deploymentId);
272
+ console.log('[Vortex] Invite deploymentId:', result.data.deploymentId);
273
+ }
274
+ console.log('[Vortex] Invite Successfully fetched widgetConfiguration', JSON.stringify(freshConfig));
275
+ }
276
+ else {
277
+ const error = 'No configuration data found.';
278
+ console.error(`[Vortex] Invite ${error}`);
279
+ throw new Error(error);
280
+ }
281
+ }
282
+ catch (err) {
283
+ // Check if this is a VortexWidgetError with structured error information
284
+ if (vortex_shared_ui_1.VortexWidgetError.isVortexWidgetError(err)) {
285
+ console.error('[Vortex] Invite Widget Error:', {
286
+ code: err.code,
287
+ userMessage: err.userMessage,
288
+ developerMessage: err.developerMessage,
289
+ context: err.context,
290
+ statusCode: err.statusCode,
291
+ });
292
+ setError({
293
+ message: err.userMessage || err.message,
294
+ code: err.code,
295
+ userMessage: err.userMessage,
296
+ developerMessage: err.developerMessage,
297
+ });
298
+ }
299
+ else if (err instanceof Error) {
300
+ const fetchError = err;
301
+ console.error('[Vortex] Invite Error Details:', {
302
+ message: fetchError.message,
303
+ status: fetchError.status || 'unknown',
304
+ statusText: fetchError.statusText,
305
+ body: fetchError.body,
306
+ stack: fetchError.stack,
307
+ });
308
+ setError({
309
+ message: err.message || 'Something went wrong!',
310
+ });
311
+ }
312
+ else {
313
+ console.error('[Vortex] Invite Error', err);
314
+ setError({
315
+ message: 'Something went wrong!',
316
+ });
317
+ }
318
+ }
319
+ finally {
320
+ if (shouldShowLoading) {
321
+ setFetching(false);
322
+ setLoading(false);
323
+ }
324
+ }
325
+ });
326
+ fetchData();
327
+ }, [componentId, effectiveJwt, vortexClient, locale]); // Removed widgetConfiguration from deps to allow refetch
328
+ // Prefetch the shareable invitation link to avoid UI delays when user taps Copy Link or QR Code
329
+ // IMPORTANT: Only prefetch after config has been fetched via VortexClient, which sets sessionAttestation
330
+ (0, react_1.useEffect)(() => {
331
+ if ((widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.id) && effectiveJwt && vortexClient && !shareableLink && configFetchedViaClient) {
332
+ console.log('[Vortex] Prefetching shareable invitation link...');
333
+ getShareableInviteLink().catch((error) => {
334
+ console.warn('[Vortex] Failed to prefetch shareable link:', error);
335
+ // Silent fail - user can still trigger it manually later
336
+ });
337
+ }
338
+ }, [widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.id, effectiveJwt, vortexClient, shareableLink, configFetchedViaClient]);
339
+ const handleInviteClick = (contentTokens) => __awaiter(this, void 0, void 0, function* () {
340
+ try {
341
+ setInviteLoading(true);
342
+ setShowSuccessMessage(false);
343
+ if (!(widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.id)) {
344
+ console.log('[Vortex Invite] Widget configuration ID is required');
345
+ return;
346
+ }
347
+ // const url = `${host}/api/v1/no-auth/components/widget-configuration/${widgetConfigurationId}/invite`; // TODO should we use options.widgetHost?.value ?
348
+ console.log('[Vortex] Invite Sending invitation', {
349
+ email,
350
+ componentId,
351
+ });
352
+ if (!effectiveJwt) {
353
+ throw new Error('[Vortex Invite] JWT is required');
354
+ }
355
+ const payload = Object.assign(Object.assign({}, contentTokens), { email: {
356
+ value: email,
357
+ type: 'email',
358
+ } });
359
+ if (role) {
360
+ payload.role = {
361
+ value: role,
362
+ type: 'string',
363
+ };
364
+ }
365
+ // Use groups parameter instead of adding group to payload
366
+ const groups = effectiveGroup ? [{ type: effectiveGroup.type, id: effectiveGroup.groupId || effectiveGroup.id, name: effectiveGroup.name }] : undefined;
367
+ const body = yield vortexClient.createInvite(effectiveJwt, widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.id, payload, 'email', groups);
368
+ console.log('[Vortex] Invite Response', body);
369
+ if (onSuccess) {
370
+ onSuccess({
371
+ type: 'invite',
372
+ data: 'Email invite sent',
373
+ });
374
+ }
375
+ setShowSuccessMessage(true);
376
+ // Auto-hide success message after 5 seconds
377
+ setTimeout(() => {
378
+ setShowSuccessMessage(false);
379
+ }, 5000);
380
+ return;
381
+ }
382
+ catch (error) {
383
+ console.error('[Vortex]', error);
384
+ if (onError) {
385
+ onError(error instanceof Error ? error : new Error(String(error)), 'invite');
386
+ }
387
+ throw error; // Re-throw the error to be caught by the component
388
+ }
389
+ finally {
390
+ setInviteLoading(false);
391
+ }
392
+ });
393
+ const getShareableLink = () => {
394
+ return vortexClient.getShareableLinkFormatted();
395
+ };
396
+ /**
397
+ * Create an invitation with internal ID target type.
398
+ * Used by Find Friends component when user taps Connect.
399
+ * Matches iOS SDK payload structure: { type: 'internal', value: { value, name, avatarUrl? } }
400
+ */
401
+ const createUserIdInvitation = (userId, name, avatarUrl, metadata) => __awaiter(this, void 0, void 0, function* () {
402
+ if (!effectiveJwt) {
403
+ throw new Error('[Vortex Invite] JWT is required');
404
+ }
405
+ if (!(widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.id)) {
406
+ throw new Error('[Vortex Invite] Widget configuration is required');
407
+ }
408
+ console.log('[Vortex] Creating user ID invitation', { userId, name, avatarUrl });
409
+ // Build the target value object matching iOS SDK structure
410
+ const targetValue = {
411
+ value: userId,
412
+ };
413
+ if (name) {
414
+ targetValue.name = name;
415
+ }
416
+ if (avatarUrl) {
417
+ targetValue.avatarUrl = avatarUrl;
418
+ }
419
+ const payload = {
420
+ internalId: {
421
+ type: 'internal',
422
+ value: targetValue,
423
+ },
424
+ };
425
+ const groups = effectiveGroup
426
+ ? [{ type: effectiveGroup.type, id: effectiveGroup.groupId || effectiveGroup.id, name: effectiveGroup.name }]
427
+ : undefined;
428
+ yield vortexClient.createInvite(effectiveJwt, widgetConfiguration.id, payload, 'other', groups, undefined, metadata || undefined);
429
+ console.log('[Vortex] Internal ID invitation created successfully');
430
+ });
431
+ const handleSmsShare = () => __awaiter(this, void 0, void 0, function* () {
432
+ var _a, _b, _c;
433
+ try {
434
+ const template = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.template.body']) === null || _c === void 0 ? void 0 : _c.value;
435
+ if (!template)
436
+ throw new Error('No template available');
437
+ const shareableLink = yield getShareableInviteLink();
438
+ if (!shareableLink)
439
+ throw new Error('No shareable link available');
440
+ const body = encodeURIComponent(template.replace(/{{vortex_share_link}}/g, shareableLink));
441
+ const smsUrl = `sms:?body=${body}`;
442
+ yield react_native_1.Linking.openURL(smsUrl);
443
+ }
444
+ catch (error) {
445
+ console.error('[Vortex] Failed to open SMS app:', error);
446
+ if (onError)
447
+ onError(error instanceof Error ? error : new Error(String(error)), 'share');
448
+ }
449
+ });
450
+ const handleEmailShare = () => __awaiter(this, void 0, void 0, function* () {
451
+ var _a, _b, _c, _d, _e, _f, _g;
452
+ try {
453
+ const template = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.template.body']) === null || _c === void 0 ? void 0 : _c.value;
454
+ if (!template)
455
+ throw new Error('No template available');
456
+ const subject = ((_g = (_f = (_e = (_d = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _d === void 0 ? void 0 : _d.props) === null || _e === void 0 ? void 0 : _e['vortex.components.share.template.subject']) === null || _f === void 0 ? void 0 : _f.value) === null || _g === void 0 ? void 0 : _g.trim()) || "You're Invited";
457
+ const shareableLink = yield getShareableInviteLink();
458
+ if (!shareableLink)
459
+ throw new Error('No shareable link available');
460
+ const body = encodeURIComponent(template.replace(/{{vortex_share_link}}/g, shareableLink));
461
+ const mailtoUrl = `mailto:?subject=${encodeURIComponent(subject)}&body=${body}`;
462
+ yield react_native_1.Linking.openURL(mailtoUrl);
463
+ }
464
+ catch (error) {
465
+ console.error('[Vortex] Failed to open Email app:', error);
466
+ if (onError)
467
+ onError(error instanceof Error ? error : new Error(String(error)), 'share');
468
+ }
469
+ });
470
+ const handleWhatsAppShare = () => __awaiter(this, void 0, void 0, function* () {
471
+ var _a, _b, _c;
472
+ try {
473
+ const template = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.template.body']) === null || _c === void 0 ? void 0 : _c.value;
474
+ if (!template)
475
+ throw new Error('No template available');
476
+ const shareableLink = yield getShareableInviteLink();
477
+ if (!shareableLink)
478
+ throw new Error('No shareable link available');
479
+ const message = encodeURIComponent(template.replace(/{{vortex_share_link}}/g, shareableLink));
480
+ const whatsappUrl = `whatsapp://send?text=${message}`;
481
+ yield react_native_1.Linking.openURL(whatsappUrl).catch(() => {
482
+ console.warn('WhatsApp not installed');
483
+ });
484
+ }
485
+ catch (error) {
486
+ console.error('[Vortex] Failed to open WhatsApp:', error);
487
+ if (onError)
488
+ onError(error instanceof Error ? error : new Error(String(error)), 'share');
489
+ }
490
+ });
491
+ const getShareableInviteLink = (contentTokens) => __awaiter(this, void 0, void 0, function* () {
492
+ // if (this.isLoading || !this.vortex) {
493
+ // return;
494
+ // }
495
+ if (!effectiveJwt || !(widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.id) || !vortexClient) {
496
+ return;
497
+ }
498
+ if (shareableLink) {
499
+ return shareableLink;
500
+ }
501
+ // Use groups parameter for shareable invite as well
502
+ const groups = effectiveGroup ? [{ type: effectiveGroup.type, id: effectiveGroup.groupId || effectiveGroup.id, name: effectiveGroup.name }] : undefined;
503
+ const invite = yield vortexClient.createShareableInvite(effectiveJwt, widgetConfiguration.id, groups);
504
+ if (!invite ||
505
+ !invite.data ||
506
+ !invite.data.invitation.id ||
507
+ !invite.data.invitation.shortLink) {
508
+ console.error('No shareable link found');
509
+ onError === null || onError === void 0 ? void 0 : onError(new Error('No shareable link found'), 'share');
510
+ // this.error = {
511
+ // message: 'No sharable link found',
512
+ // };
513
+ // this.host.requestUpdate();
514
+ return;
515
+ }
516
+ const link = invite.data.invitation.shortLink;
517
+ setShareableLink(link);
518
+ return link;
519
+ });
520
+ const handleShareLink = () => __awaiter(this, void 0, void 0, function* () {
521
+ var _a, _b, _c, _d, _e, _f, _g;
522
+ try {
523
+ const link = yield getShareableInviteLink();
524
+ if (!link) {
525
+ throw new Error('No shareable link available');
526
+ }
527
+ const template = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.template.body']) === null || _c === void 0 ? void 0 : _c.value;
528
+ const subject = (_g = (_f = (_e = (_d = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _d === void 0 ? void 0 : _d.props) === null || _e === void 0 ? void 0 : _e['vortex.components.share.template.subject']) === null || _f === void 0 ? void 0 : _f.value) === null || _g === void 0 ? void 0 : _g.trim();
529
+ // Compose message
530
+ let message = '';
531
+ if (typeof template === 'string' && template.length > 0) {
532
+ if (template.includes('{{vortex_share_link}}')) {
533
+ message = template.replace(/{{vortex_share_link}}/g, link);
534
+ }
535
+ else {
536
+ message = `${template}${template.endsWith(' ') ? '' : ' '}${link}`;
537
+ }
538
+ }
539
+ else {
540
+ message = link;
541
+ }
542
+ // Informative log about iOS share sheet branding
543
+ if (react_native_1.Platform.OS === 'ios') {
544
+ console.log('[Vortex] iOS share sheet branding note: The icon/name come from the host app bundle; link preview (if any) is pulled from the shared URL\'s Open Graph/Twitter meta tags. Customizing the header/logo via RN Share is not supported.');
545
+ }
546
+ const content = Object.assign({ message, url: link, title: subject || 'Share Invite Link' }, (subject ? { subject } : {}));
547
+ const options = react_native_1.Platform.select({
548
+ android: {
549
+ dialogTitle: subject || 'Share Invite Link',
550
+ },
551
+ ios: Object.assign({}, (subject ? { subject } : {})),
552
+ default: {},
553
+ });
554
+ yield react_native_1.Share.share(content, options);
555
+ console.log('[Vortex] handleShareLink', 'The invite link has been shared.');
556
+ onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess({ type: 'share', data: 'Sharable link used' });
557
+ }
558
+ catch (error) {
559
+ console.error('[Vortex] Failed to share link:', error);
560
+ onError === null || onError === void 0 ? void 0 : onError(error instanceof Error ? error : new Error(String(error)), 'share');
561
+ }
562
+ });
563
+ const handleCopyLink = () => __awaiter(this, void 0, void 0, function* () {
564
+ var _a;
565
+ try {
566
+ const shareableLink = yield getShareableInviteLink();
567
+ if (!shareableLink) {
568
+ throw new Error('No shareable link available');
569
+ }
570
+ // Try expo-clipboard first, then @react-native-clipboard/clipboard, then web clipboard
571
+ let copied = false;
572
+ try {
573
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
574
+ const expoClipboard = require('expo-clipboard');
575
+ yield expoClipboard.setStringAsync(shareableLink);
576
+ copied = true;
577
+ }
578
+ catch (e) {
579
+ try {
580
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
581
+ const rnClipboard = require('@react-native-clipboard/clipboard');
582
+ rnClipboard.default.setString(shareableLink);
583
+ copied = true;
584
+ }
585
+ catch (e2) {
586
+ // Fall back to web clipboard API
587
+ if (typeof navigator !== 'undefined' && ((_a = navigator.clipboard) === null || _a === void 0 ? void 0 : _a.writeText)) {
588
+ yield navigator.clipboard.writeText(shareableLink);
589
+ copied = true;
590
+ }
591
+ }
592
+ }
593
+ if (!copied) {
594
+ throw new Error('No clipboard implementation available');
595
+ }
596
+ console.log('[Vortex] handleCopyLink', 'The invite link has been copied.');
597
+ if (onSuccess) {
598
+ onSuccess({
599
+ type: 'share',
600
+ data: 'Sharable copied',
601
+ });
602
+ }
603
+ }
604
+ catch (error) {
605
+ console.error('[Vortex] Failed to copy link:', error);
606
+ if (onError) {
607
+ onError(error instanceof Error ? error : new Error(String(error)), 'share');
608
+ }
609
+ }
610
+ });
611
+ // Contacts import: dynamically use expo-contacts when available (iOS & Android)
612
+ const fetchContactsWithEmailsIOS = () => __awaiter(this, void 0, void 0, function* () {
613
+ var _a, _b, _c, _d, _e, _f, _g;
614
+ try {
615
+ let Contacts = null;
616
+ try {
617
+ // Dynamic require so the library does not hard depend on expo-contacts
618
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
619
+ Contacts = require('expo-contacts');
620
+ }
621
+ catch (e) {
622
+ throw new Error('Contacts feature is not available. Please ensure expo-contacts is installed.');
623
+ }
624
+ // First check current permission status
625
+ let currentStatus;
626
+ try {
627
+ const currentPerm = yield (Contacts.getPermissionsAsync
628
+ ? Contacts.getPermissionsAsync()
629
+ : (_a = Contacts.getPermissionAsync) === null || _a === void 0 ? void 0 : _a.call(Contacts));
630
+ currentStatus = currentPerm === null || currentPerm === void 0 ? void 0 : currentPerm.status;
631
+ }
632
+ catch (permErr) {
633
+ console.warn('[Vortex] Failed to check contacts permission:', permErr);
634
+ }
635
+ // If already denied, inform user they need to go to Settings
636
+ if (currentStatus === 'denied') {
637
+ throw new Error('Contacts access was denied. Please enable Contacts access in your device Settings to import contacts.');
638
+ }
639
+ // Request permission (either undetermined or checking again)
640
+ let status;
641
+ try {
642
+ const perm = yield (Contacts.requestPermissionsAsync
643
+ ? Contacts.requestPermissionsAsync()
644
+ : (_b = Contacts.requestPermissionAsync) === null || _b === void 0 ? void 0 : _b.call(Contacts));
645
+ status = perm === null || perm === void 0 ? void 0 : perm.status;
646
+ }
647
+ catch (permErr) {
648
+ console.warn('[Vortex] Contacts permission request failed:', permErr);
649
+ throw new Error('Failed to request contacts permission. Please try again.');
650
+ }
651
+ if (status === 'denied') {
652
+ throw new Error('Contacts access was denied. Please enable Contacts access in your device Settings to import contacts.');
653
+ }
654
+ if (status !== 'granted') {
655
+ throw new Error('Contacts access is required to import contacts.');
656
+ }
657
+ // Fetch contacts with emails and images
658
+ const fields = Contacts.Fields
659
+ ? [Contacts.Fields.Emails, Contacts.Fields.Image]
660
+ : ['emails', 'image'];
661
+ const args = { fields, pageSize: 500 };
662
+ if ((_c = Contacts.SortTypes) === null || _c === void 0 ? void 0 : _c.FirstName) {
663
+ args.sort = Contacts.SortTypes.FirstName;
664
+ }
665
+ const result = yield Contacts.getContactsAsync(args);
666
+ const data = (result === null || result === void 0 ? void 0 : result.data) || [];
667
+ if (!Array.isArray(data) || data.length === 0) {
668
+ return [];
669
+ }
670
+ const normalizeEmail = (e) => (e === null || e === void 0 ? void 0 : e.email) || (e === null || e === void 0 ? void 0 : e.address) || (typeof e === 'string' ? e : undefined);
671
+ const items = [];
672
+ for (const c of data) {
673
+ const emailsSrc = ((c === null || c === void 0 ? void 0 : c.emails) || (c === null || c === void 0 ? void 0 : c.emailAddresses) || []);
674
+ const emails = emailsSrc.map(normalizeEmail).filter(Boolean);
675
+ if (emails.length > 0) {
676
+ const name = ((_d = ((c === null || c === void 0 ? void 0 : c.name) || `${(c === null || c === void 0 ? void 0 : c.firstName) || ''} ${(c === null || c === void 0 ? void 0 : c.lastName) || ''}`)) === null || _d === void 0 ? void 0 : _d.trim()) || 'Unknown';
677
+ const imageUri = ((_e = c === null || c === void 0 ? void 0 : c.image) === null || _e === void 0 ? void 0 : _e.uri) || (c === null || c === void 0 ? void 0 : c.imageAvailable) ? (_f = c === null || c === void 0 ? void 0 : c.image) === null || _f === void 0 ? void 0 : _f.uri : undefined;
678
+ items.push({ id: String((_g = c === null || c === void 0 ? void 0 : c.id) !== null && _g !== void 0 ? _g : Math.random()), name, emails, imageUri });
679
+ }
680
+ }
681
+ return items;
682
+ }
683
+ catch (err) {
684
+ // Re-throw errors with messages so UI can display them properly
685
+ if (err instanceof Error) {
686
+ throw err;
687
+ }
688
+ console.error('[Vortex] Failed to fetch contacts:', err);
689
+ throw new Error('An unexpected error occurred while accessing contacts.');
690
+ }
691
+ });
692
+ return {
693
+ widgetConfiguration,
694
+ error,
695
+ fetching,
696
+ loading,
697
+ email,
698
+ setEmail,
699
+ role,
700
+ setRole,
701
+ roleOptions,
702
+ opacity,
703
+ themeColors,
704
+ themeStyles,
705
+ has,
706
+ options,
707
+ inviteLoading,
708
+ showSuccessMessage,
709
+ handleInviteClick,
710
+ handleShareLink,
711
+ handleCopyLink,
712
+ handleSmsShare,
713
+ handleEmailShare,
714
+ handleWhatsAppShare,
715
+ getShareableLink,
716
+ getShareableInviteLink,
717
+ createUserIdInvitation,
718
+ formLayout,
719
+ fetchContactsWithEmailsIOS,
720
+ // Analytics tracking functions
721
+ trackWidgetRender,
722
+ trackWidgetError,
723
+ trackShareLinkClick,
724
+ trackEmailFieldFocus,
725
+ trackEmailFieldBlur,
726
+ trackEmailValidation,
727
+ trackEmailInvitationsSubmitted,
728
+ trackEmailValidationError,
729
+ trackEmailSubmitError,
730
+ };
731
+ }
732
+ //# sourceMappingURL=useVortexInvite.js.map