@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.
- package/dist/InviteFormCore-D4HkMMo0.d.mts +721 -0
- package/dist/InviteFormCore-D9oUCbu7.d.ts +721 -0
- package/dist/VortexClient.js +192 -0
- package/dist/VortexClient.js.map +1 -0
- package/dist/VortexDeferredLinks.js +127 -0
- package/dist/VortexDeferredLinks.js.map +1 -0
- package/dist/clientInfo.js +45 -0
- package/dist/clientInfo.js.map +1 -0
- package/dist/components/ContactsPickerModal.js +182 -0
- package/dist/components/ContactsPickerModal.js.map +1 -0
- package/dist/components/InviteFormCore.js +2141 -0
- package/dist/components/InviteFormCore.js.map +1 -0
- package/dist/components/InviteFormMobile.js +463 -0
- package/dist/components/InviteFormMobile.js.map +1 -0
- package/dist/components/InviteFormWeb.js +295 -0
- package/dist/components/InviteFormWeb.js.map +1 -0
- package/dist/components/PlacedItemToolbar.js +147 -0
- package/dist/components/PlacedItemToolbar.js.map +1 -0
- package/dist/components/ShareButtons.js +181 -0
- package/dist/components/ShareButtons.js.map +1 -0
- package/dist/components/VrtxContactsImport.js +234 -0
- package/dist/components/VrtxContactsImport.js.map +1 -0
- package/dist/components/VrtxEmailInvitations.js +341 -0
- package/dist/components/VrtxEmailInvitations.js.map +1 -0
- package/dist/components/VrtxFindFriends.js +400 -0
- package/dist/components/VrtxFindFriends.js.map +1 -0
- package/dist/components/VrtxHeading.js +58 -0
- package/dist/components/VrtxHeading.js.map +1 -0
- package/dist/components/VrtxIncomingInvitations.js +657 -0
- package/dist/components/VrtxIncomingInvitations.js.map +1 -0
- package/dist/components/VrtxInvitationSuggestions.js +506 -0
- package/dist/components/VrtxInvitationSuggestions.js.map +1 -0
- package/dist/components/VrtxInviteContacts.js +512 -0
- package/dist/components/VrtxInviteContacts.js.map +1 -0
- package/dist/components/VrtxOutgoingInvitations.js +572 -0
- package/dist/components/VrtxOutgoingInvitations.js.map +1 -0
- package/dist/components/VrtxSearchBox.js +487 -0
- package/dist/components/VrtxSearchBox.js.map +1 -0
- package/dist/components/VrtxSelect.js +27 -0
- package/dist/components/VrtxSelect.js.map +1 -0
- package/dist/components/VrtxShareOptions.js +435 -0
- package/dist/components/VrtxShareOptions.js.map +1 -0
- package/dist/components/VrtxSubmit.js +132 -0
- package/dist/components/VrtxSubmit.js.map +1 -0
- package/dist/components/VrtxText.js +146 -0
- package/dist/components/VrtxText.js.map +1 -0
- package/dist/constants/mockData.d.mts +7 -0
- package/dist/constants/mockData.d.ts +7 -0
- package/dist/constants/mockData.js +48 -0
- package/dist/constants/mockData.js.map +1 -0
- package/dist/constants/mockData.mjs +22 -0
- package/dist/constants/mockData.mjs.map +1 -0
- package/dist/context/VortexModulesContext.js +135 -0
- package/dist/context/VortexModulesContext.js.map +1 -0
- package/dist/hooks/useInvitationFormLogic.d.mts +2 -0
- package/dist/hooks/useInvitationFormLogic.d.ts +2 -0
- package/dist/hooks/useInvitationFormLogic.js +300 -0
- package/dist/hooks/useInvitationFormLogic.js.map +1 -0
- package/dist/hooks/useInvitationFormLogic.mjs +276 -0
- package/dist/hooks/useInvitationFormLogic.mjs.map +1 -0
- package/dist/hooks/usePrefetchWidgetConfiguration.js +117 -0
- package/dist/hooks/usePrefetchWidgetConfiguration.js.map +1 -0
- package/dist/hooks/useThemeStyles.js +41 -0
- package/dist/hooks/useThemeStyles.js.map +1 -0
- package/dist/hooks/useVortexInvite.js +732 -0
- package/dist/hooks/useVortexInvite.js.map +1 -0
- package/dist/index-web.d.mts +93 -0
- package/dist/index-web.d.ts +93 -0
- package/dist/index-web.js +7397 -0
- package/dist/index-web.js.map +1 -0
- package/dist/index-web.mjs +7445 -0
- package/dist/index-web.mjs.map +1 -0
- package/dist/index.d.mts +656 -0
- package/dist/index.d.ts +656 -0
- package/dist/index.js +10206 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +10244 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types/VortexClient.d.ts +106 -0
- package/dist/types/VortexClient.d.ts.map +1 -0
- package/dist/types/VortexDeferredLinks.d.ts +73 -0
- package/dist/types/VortexDeferredLinks.d.ts.map +1 -0
- package/dist/types/clientInfo.d.ts +5 -0
- package/dist/types/clientInfo.d.ts.map +1 -0
- package/dist/types/components/ContactsPickerModal.d.ts +18 -0
- package/dist/types/components/ContactsPickerModal.d.ts.map +1 -0
- package/dist/types/components/InviteFormCore.d.ts +166 -0
- package/dist/types/components/InviteFormCore.d.ts.map +1 -0
- package/dist/types/components/InviteFormMobile.d.ts +42 -0
- package/dist/types/components/InviteFormMobile.d.ts.map +1 -0
- package/dist/types/components/InviteFormWeb.d.ts +87 -0
- package/dist/types/components/InviteFormWeb.d.ts.map +1 -0
- package/dist/types/components/PlacedItemToolbar.d.ts +16 -0
- package/dist/types/components/PlacedItemToolbar.d.ts.map +1 -0
- package/dist/types/components/ShareButtons.d.ts +29 -0
- package/dist/types/components/ShareButtons.d.ts.map +1 -0
- package/dist/types/components/VrtxContactsImport.d.ts +14 -0
- package/dist/types/components/VrtxContactsImport.d.ts.map +1 -0
- package/dist/types/components/VrtxEmailInvitations.d.ts +31 -0
- package/dist/types/components/VrtxEmailInvitations.d.ts.map +1 -0
- package/dist/types/components/VrtxFindFriends.d.ts +25 -0
- package/dist/types/components/VrtxFindFriends.d.ts.map +1 -0
- package/dist/types/components/VrtxHeading.d.ts +6 -0
- package/dist/types/components/VrtxHeading.d.ts.map +1 -0
- package/dist/types/components/VrtxIncomingInvitations.d.ts +27 -0
- package/dist/types/components/VrtxIncomingInvitations.d.ts.map +1 -0
- package/dist/types/components/VrtxInvitationSuggestions.d.ts +25 -0
- package/dist/types/components/VrtxInvitationSuggestions.d.ts.map +1 -0
- package/dist/types/components/VrtxInviteContacts.d.ts +24 -0
- package/dist/types/components/VrtxInviteContacts.d.ts.map +1 -0
- package/dist/types/components/VrtxOutgoingInvitations.d.ts +27 -0
- package/dist/types/components/VrtxOutgoingInvitations.d.ts.map +1 -0
- package/dist/types/components/VrtxSearchBox.d.ts +28 -0
- package/dist/types/components/VrtxSearchBox.d.ts.map +1 -0
- package/dist/types/components/VrtxSelect.d.ts +6 -0
- package/dist/types/components/VrtxSelect.d.ts.map +1 -0
- package/dist/types/components/VrtxShareOptions.d.ts +41 -0
- package/dist/types/components/VrtxShareOptions.d.ts.map +1 -0
- package/dist/types/components/VrtxSubmit.d.ts +18 -0
- package/dist/types/components/VrtxSubmit.d.ts.map +1 -0
- package/dist/types/components/VrtxText.d.ts +8 -0
- package/dist/types/components/VrtxText.d.ts.map +1 -0
- package/dist/types/constants/mockData.d.ts +4 -0
- package/dist/types/constants/mockData.d.ts.map +1 -0
- package/dist/types/context/VortexModulesContext.d.ts +238 -0
- package/dist/types/context/VortexModulesContext.d.ts.map +1 -0
- package/dist/types/findFriends.js +10 -0
- package/dist/types/findFriends.js.map +1 -0
- package/dist/types/hooks/useInvitationFormLogic.d.ts +55 -0
- package/dist/types/hooks/useInvitationFormLogic.d.ts.map +1 -0
- package/dist/types/hooks/usePrefetchWidgetConfiguration.d.ts +39 -0
- package/dist/types/hooks/usePrefetchWidgetConfiguration.d.ts.map +1 -0
- package/dist/types/hooks/useThemeStyles.d.ts +35 -0
- package/dist/types/hooks/useThemeStyles.d.ts.map +1 -0
- package/dist/types/hooks/useVortexInvite.d.ts +86 -0
- package/dist/types/hooks/useVortexInvite.d.ts.map +1 -0
- package/dist/types/index-web.d.ts +23 -0
- package/dist/types/index-web.d.ts.map +1 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/invitations.js +13 -0
- package/dist/types/invitations.js.map +1 -0
- package/dist/types/inviteContacts.js +14 -0
- package/dist/types/inviteContacts.js.map +1 -0
- package/dist/types/platformOperations.js +3 -0
- package/dist/types/platformOperations.js.map +1 -0
- package/dist/types/searchBox.js +11 -0
- package/dist/types/searchBox.js.map +1 -0
- package/dist/types/types/findFriends.d.ts +101 -0
- package/dist/types/types/findFriends.d.ts.map +1 -0
- package/dist/types/types/invitations.d.ts +301 -0
- package/dist/types/types/invitations.d.ts.map +1 -0
- package/dist/types/types/inviteContacts.d.ts +86 -0
- package/dist/types/types/inviteContacts.d.ts.map +1 -0
- package/dist/types/types/platformOperations.d.ts +185 -0
- package/dist/types/types/platformOperations.d.ts.map +1 -0
- package/dist/types/types/searchBox.d.ts +69 -0
- package/dist/types/types/searchBox.d.ts.map +1 -0
- package/dist/types/types/unfurlConfig.d.ts +34 -0
- package/dist/types/types/unfurlConfig.d.ts.map +1 -0
- package/dist/types/unfurlConfig.js +21 -0
- package/dist/types/unfurlConfig.js.map +1 -0
- package/dist/types/utils/analytics.d.ts +54 -0
- package/dist/types/utils/analytics.d.ts.map +1 -0
- package/dist/types/utils/configCache.d.ts +34 -0
- package/dist/types/utils/configCache.d.ts.map +1 -0
- package/dist/types/utils/contactUtils.d.ts +9 -0
- package/dist/types/utils/contactUtils.d.ts.map +1 -0
- package/dist/types/utils/featureWarnings.d.ts +56 -0
- package/dist/types/utils/featureWarnings.d.ts.map +1 -0
- package/dist/types/utils/formUtils.d.ts +93 -0
- package/dist/types/utils/formUtils.d.ts.map +1 -0
- package/dist/types/utils/gradientUtils.d.ts +67 -0
- package/dist/types/utils/gradientUtils.d.ts.map +1 -0
- package/dist/types/utils/invitationEvents.d.ts +21 -0
- package/dist/types/utils/invitationEvents.d.ts.map +1 -0
- package/dist/types/utils/moduleLoaders.d.ts +115 -0
- package/dist/types/utils/moduleLoaders.d.ts.map +1 -0
- package/dist/types/utils/moduleLoaders.web.d.ts +73 -0
- package/dist/types/utils/moduleLoaders.web.d.ts.map +1 -0
- package/dist/types/utils/nameUtils.d.ts +15 -0
- package/dist/types/utils/nameUtils.d.ts.map +1 -0
- package/dist/types/utils/themeUtils.d.ts +38 -0
- package/dist/types/utils/themeUtils.d.ts.map +1 -0
- package/dist/types/vortexInvite.d.ts +165 -0
- package/dist/types/vortexInvite.d.ts.map +1 -0
- package/dist/useInvitationFormLogic-Ct73M19B.d.mts +242 -0
- package/dist/useInvitationFormLogic-Ct73M19B.d.ts +242 -0
- package/dist/utils/analytics.js +92 -0
- package/dist/utils/analytics.js.map +1 -0
- package/dist/utils/configCache.js +68 -0
- package/dist/utils/configCache.js.map +1 -0
- package/dist/utils/contactUtils.d.mts +12 -0
- package/dist/utils/contactUtils.d.ts +12 -0
- package/dist/utils/contactUtils.js +37 -0
- package/dist/utils/contactUtils.js.map +1 -0
- package/dist/utils/contactUtils.mjs +12 -0
- package/dist/utils/contactUtils.mjs.map +1 -0
- package/dist/utils/featureWarnings.js +214 -0
- package/dist/utils/featureWarnings.js.map +1 -0
- package/dist/utils/formUtils.js +284 -0
- package/dist/utils/formUtils.js.map +1 -0
- package/dist/utils/gradientUtils.js +120 -0
- package/dist/utils/gradientUtils.js.map +1 -0
- package/dist/utils/invitationEvents.js +45 -0
- package/dist/utils/invitationEvents.js.map +1 -0
- package/dist/utils/moduleLoaders.js +275 -0
- package/dist/utils/moduleLoaders.js.map +1 -0
- package/dist/utils/moduleLoaders.web.js +72 -0
- package/dist/utils/moduleLoaders.web.js.map +1 -0
- package/dist/utils/nameUtils.js +51 -0
- package/dist/utils/nameUtils.js.map +1 -0
- package/dist/utils/themeUtils.js +141 -0
- package/dist/utils/themeUtils.js.map +1 -0
- package/dist/vortexInvite.js +83 -0
- package/dist/vortexInvite.js.map +1 -0
- package/package.json +21 -56
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var __async = (__this, __arguments, generator) => {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
var fulfilled = (value) => {
|
|
22
|
+
try {
|
|
23
|
+
step(generator.next(value));
|
|
24
|
+
} catch (e) {
|
|
25
|
+
reject(e);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var rejected = (value) => {
|
|
29
|
+
try {
|
|
30
|
+
step(generator.throw(value));
|
|
31
|
+
} catch (e) {
|
|
32
|
+
reject(e);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
36
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// src/hooks/useInvitationFormLogic.ts
|
|
41
|
+
var useInvitationFormLogic_exports = {};
|
|
42
|
+
__export(useInvitationFormLogic_exports, {
|
|
43
|
+
useInvitationFormLogic: () => useInvitationFormLogic
|
|
44
|
+
});
|
|
45
|
+
module.exports = __toCommonJS(useInvitationFormLogic_exports);
|
|
46
|
+
var import_react = require("react");
|
|
47
|
+
var import_react_native = require("react-native");
|
|
48
|
+
function useInvitationFormLogic(platformOps, contacts, googleContacts, getShareableInviteLink) {
|
|
49
|
+
const [view, setView] = (0, import_react.useState)("main");
|
|
50
|
+
const [emailInput, setEmailInput] = (0, import_react.useState)("");
|
|
51
|
+
const [emails, setEmails] = (0, import_react.useState)([]);
|
|
52
|
+
const [role, setRole] = (0, import_react.useState)("member");
|
|
53
|
+
const [copySuccess, setCopySuccess] = (0, import_react.useState)(false);
|
|
54
|
+
const [shareSuccess, setShareSuccess] = (0, import_react.useState)(false);
|
|
55
|
+
const [sendSuccess, setSendSuccess] = (0, import_react.useState)(false);
|
|
56
|
+
const [searchQuery, setSearchQuery] = (0, import_react.useState)("");
|
|
57
|
+
const [invitedContactIds, setInvitedContactIds] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
58
|
+
const [invitedGoogleContactIds, setInvitedGoogleContactIds] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
59
|
+
const [googleSearchQuery, setGoogleSearchQuery] = (0, import_react.useState)("");
|
|
60
|
+
const [loadingContactIds, setLoadingContactIds] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
61
|
+
const [loadingGoogleContactIds, setLoadingGoogleContactIds] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
62
|
+
const [loadingEmailInvite, setLoadingEmailInvite] = (0, import_react.useState)(false);
|
|
63
|
+
const [loadingCopy, setLoadingCopy] = (0, import_react.useState)(false);
|
|
64
|
+
const [loadingShare, setLoadingShare] = (0, import_react.useState)(false);
|
|
65
|
+
const [invitationLink, setInvitationLink] = (0, import_react.useState)("https://app.vortexsoftware.com/invite/abc123");
|
|
66
|
+
const [loadingInvitationLink, setLoadingInvitationLink] = (0, import_react.useState)(false);
|
|
67
|
+
const fetchedRef = (0, import_react.useRef)(false);
|
|
68
|
+
(0, import_react.useEffect)(() => {
|
|
69
|
+
if (import_react_native.Platform.OS === "web") {
|
|
70
|
+
console.log("[Vortex] Web preview mode: using placeholder QR code for demo");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (view === "qrcode" && getShareableInviteLink && !fetchedRef.current) {
|
|
74
|
+
fetchedRef.current = true;
|
|
75
|
+
setLoadingInvitationLink(true);
|
|
76
|
+
getShareableInviteLink().then((link) => {
|
|
77
|
+
if (link) {
|
|
78
|
+
setInvitationLink(link);
|
|
79
|
+
console.log("[Vortex] QR code invitation link fetched:", link);
|
|
80
|
+
} else {
|
|
81
|
+
console.warn("[Vortex] No invitation link available for QR code");
|
|
82
|
+
}
|
|
83
|
+
}).catch((error) => {
|
|
84
|
+
console.error("[Vortex] Failed to fetch invitation link for QR code:", error);
|
|
85
|
+
fetchedRef.current = false;
|
|
86
|
+
}).finally(() => {
|
|
87
|
+
setLoadingInvitationLink(false);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (view !== "qrcode") {
|
|
91
|
+
fetchedRef.current = false;
|
|
92
|
+
}
|
|
93
|
+
}, [view, getShareableInviteLink]);
|
|
94
|
+
const handleClose = () => {
|
|
95
|
+
platformOps.close();
|
|
96
|
+
};
|
|
97
|
+
const handleSendInvitation = () => __async(null, null, function* () {
|
|
98
|
+
const trimmedEmail = emailInput.trim();
|
|
99
|
+
let emailsToSend = [...emails];
|
|
100
|
+
if (trimmedEmail && isValidEmail(trimmedEmail)) {
|
|
101
|
+
emailsToSend = [...emails, trimmedEmail];
|
|
102
|
+
setEmails(emailsToSend);
|
|
103
|
+
}
|
|
104
|
+
if (trimmedEmail && !isValidEmail(trimmedEmail)) {
|
|
105
|
+
setLastInvalidEmail(trimmedEmail);
|
|
106
|
+
setTimeout(() => setLastInvalidEmail(null), 1500);
|
|
107
|
+
}
|
|
108
|
+
if (emailsToSend.length === 0) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const uniqueEmails = [...new Set(emailsToSend)];
|
|
112
|
+
setLoadingEmailInvite(true);
|
|
113
|
+
try {
|
|
114
|
+
yield Promise.all(uniqueEmails.map((email) => platformOps.invite(email)));
|
|
115
|
+
console.log("[Vortex] Successfully sent invitations to:", emailsToSend);
|
|
116
|
+
setSendSuccess(true);
|
|
117
|
+
setEmails([]);
|
|
118
|
+
setEmailInput("");
|
|
119
|
+
setTimeout(() => setSendSuccess(false), 2e3);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error("[Vortex] Failed to send invitations:", error);
|
|
122
|
+
} finally {
|
|
123
|
+
setLoadingEmailInvite(false);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
const handleCopyLink = () => __async(null, null, function* () {
|
|
127
|
+
setLoadingCopy(true);
|
|
128
|
+
try {
|
|
129
|
+
yield platformOps.copyToClipboard();
|
|
130
|
+
setCopySuccess(true);
|
|
131
|
+
setTimeout(() => setCopySuccess(false), 2e3);
|
|
132
|
+
} catch (err) {
|
|
133
|
+
console.error("Failed to copy:", err);
|
|
134
|
+
} finally {
|
|
135
|
+
setLoadingCopy(false);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
const handleShare = () => __async(null, null, function* () {
|
|
139
|
+
setLoadingShare(true);
|
|
140
|
+
try {
|
|
141
|
+
yield platformOps.share();
|
|
142
|
+
setShareSuccess(true);
|
|
143
|
+
setTimeout(() => setShareSuccess(false), 2e3);
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.error("Failed to share:", err);
|
|
146
|
+
} finally {
|
|
147
|
+
setLoadingShare(false);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
const isValidEmail = (email) => {
|
|
151
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
152
|
+
return emailRegex.test(email.trim());
|
|
153
|
+
};
|
|
154
|
+
const [lastInvalidEmail, setLastInvalidEmail] = (0, import_react.useState)(null);
|
|
155
|
+
const handleEmailSubmit = (overrideEmail) => {
|
|
156
|
+
const trimmedEmail = (overrideEmail != null ? overrideEmail : emailInput).trim();
|
|
157
|
+
if (!trimmedEmail) return;
|
|
158
|
+
if (isValidEmail(trimmedEmail)) {
|
|
159
|
+
setEmails([...emails, trimmedEmail]);
|
|
160
|
+
setEmailInput("");
|
|
161
|
+
setLastInvalidEmail(null);
|
|
162
|
+
} else {
|
|
163
|
+
setLastInvalidEmail(trimmedEmail);
|
|
164
|
+
setTimeout(() => setLastInvalidEmail(null), 1500);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const handleRemoveEmail = (emailToRemove) => {
|
|
168
|
+
setEmails(emails.filter((email) => email !== emailToRemove));
|
|
169
|
+
};
|
|
170
|
+
const handleSelectFromGoogle = () => {
|
|
171
|
+
setView("googleContacts");
|
|
172
|
+
};
|
|
173
|
+
const handleSelectFromContacts = () => {
|
|
174
|
+
setView("contacts");
|
|
175
|
+
};
|
|
176
|
+
const handleAddByEmail = () => {
|
|
177
|
+
setView("email");
|
|
178
|
+
};
|
|
179
|
+
const handleShowQrCode = () => {
|
|
180
|
+
setView("qrcode");
|
|
181
|
+
};
|
|
182
|
+
const handleBackToMain = () => {
|
|
183
|
+
console.log("[Vortex] handleBackToMain called, returning to main view");
|
|
184
|
+
console.log("[Vortex] Current view before setView:", view);
|
|
185
|
+
setView("main");
|
|
186
|
+
console.log('[Vortex] setView("main") called');
|
|
187
|
+
setSearchQuery("");
|
|
188
|
+
setGoogleSearchQuery("");
|
|
189
|
+
};
|
|
190
|
+
const handleInviteContact = (contactId) => __async(null, null, function* () {
|
|
191
|
+
const contact = contacts == null ? void 0 : contacts.find((c) => c.id === contactId);
|
|
192
|
+
if (!contact) {
|
|
193
|
+
console.error("[Vortex] Contact not found:", contactId);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
setLoadingContactIds((prev) => {
|
|
197
|
+
const newSet = new Set(prev);
|
|
198
|
+
newSet.add(contactId);
|
|
199
|
+
return newSet;
|
|
200
|
+
});
|
|
201
|
+
try {
|
|
202
|
+
yield platformOps.invite(contact.email, contact.name);
|
|
203
|
+
setInvitedContactIds((prev) => {
|
|
204
|
+
const newSet = new Set(prev);
|
|
205
|
+
newSet.add(contactId);
|
|
206
|
+
return newSet;
|
|
207
|
+
});
|
|
208
|
+
} catch (error) {
|
|
209
|
+
console.error("[Vortex] Failed to invite contact:", error);
|
|
210
|
+
} finally {
|
|
211
|
+
setLoadingContactIds((prev) => {
|
|
212
|
+
const newSet = new Set(prev);
|
|
213
|
+
newSet.delete(contactId);
|
|
214
|
+
return newSet;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
const handleInviteGoogleContact = (contactId) => __async(null, null, function* () {
|
|
219
|
+
const contact = googleContacts == null ? void 0 : googleContacts.find((c) => c.id === contactId);
|
|
220
|
+
if (!contact) {
|
|
221
|
+
console.error("[Vortex] Google contact not found:", contactId);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
setLoadingGoogleContactIds((prev) => {
|
|
225
|
+
const newSet = new Set(prev);
|
|
226
|
+
newSet.add(contactId);
|
|
227
|
+
return newSet;
|
|
228
|
+
});
|
|
229
|
+
try {
|
|
230
|
+
yield platformOps.invite(contact.email, contact.name);
|
|
231
|
+
setInvitedGoogleContactIds((prev) => {
|
|
232
|
+
const newSet = new Set(prev);
|
|
233
|
+
newSet.add(contactId);
|
|
234
|
+
return newSet;
|
|
235
|
+
});
|
|
236
|
+
} catch (error) {
|
|
237
|
+
console.error("[Vortex] Failed to invite Google contact:", error);
|
|
238
|
+
} finally {
|
|
239
|
+
setLoadingGoogleContactIds((prev) => {
|
|
240
|
+
const newSet = new Set(prev);
|
|
241
|
+
newSet.delete(contactId);
|
|
242
|
+
return newSet;
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
return {
|
|
247
|
+
// State
|
|
248
|
+
view,
|
|
249
|
+
emailInput,
|
|
250
|
+
emails,
|
|
251
|
+
role,
|
|
252
|
+
copySuccess,
|
|
253
|
+
shareSuccess,
|
|
254
|
+
sendSuccess,
|
|
255
|
+
searchQuery,
|
|
256
|
+
invitedContactIds,
|
|
257
|
+
invitedGoogleContactIds,
|
|
258
|
+
googleSearchQuery,
|
|
259
|
+
invitationLink,
|
|
260
|
+
loadingContactIds,
|
|
261
|
+
loadingGoogleContactIds,
|
|
262
|
+
loadingEmailInvite,
|
|
263
|
+
loadingCopy,
|
|
264
|
+
loadingShare,
|
|
265
|
+
loadingInvitationLink,
|
|
266
|
+
lastInvalidEmail,
|
|
267
|
+
// Setters
|
|
268
|
+
setView,
|
|
269
|
+
setEmailInput,
|
|
270
|
+
setEmails,
|
|
271
|
+
setRole,
|
|
272
|
+
setCopySuccess,
|
|
273
|
+
setShareSuccess,
|
|
274
|
+
setSendSuccess,
|
|
275
|
+
setSearchQuery,
|
|
276
|
+
setInvitedContactIds,
|
|
277
|
+
setInvitedGoogleContactIds,
|
|
278
|
+
setGoogleSearchQuery,
|
|
279
|
+
// Handlers
|
|
280
|
+
handleClose,
|
|
281
|
+
handleSendInvitation,
|
|
282
|
+
handleCopyLink,
|
|
283
|
+
handleShare,
|
|
284
|
+
isValidEmail,
|
|
285
|
+
handleEmailSubmit,
|
|
286
|
+
handleRemoveEmail,
|
|
287
|
+
handleSelectFromGoogle,
|
|
288
|
+
handleSelectFromContacts,
|
|
289
|
+
handleAddByEmail,
|
|
290
|
+
handleShowQrCode,
|
|
291
|
+
handleBackToMain,
|
|
292
|
+
handleInviteContact,
|
|
293
|
+
handleInviteGoogleContact
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
297
|
+
0 && (module.exports = {
|
|
298
|
+
useInvitationFormLogic
|
|
299
|
+
});
|
|
300
|
+
//# sourceMappingURL=useInvitationFormLogic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/useInvitationFormLogic.ts"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport { Platform } from 'react-native';\nimport { PlatformOperations } from '../types/platformOperations';\n\nexport type ViewType = 'main' | 'email' | 'contacts' | 'googleContacts' | 'qrcode';\n\nexport interface Contact {\n id: string;\n name: string;\n email: string;\n imageUri?: string;\n}\n\nexport function useInvitationFormLogic(\n platformOps: PlatformOperations,\n contacts?: Contact[],\n googleContacts?: Contact[],\n getShareableInviteLink?: () => Promise<string | undefined>\n) {\n const [view, setView] = useState<ViewType>('main');\n const [emailInput, setEmailInput] = useState('');\n const [emails, setEmails] = useState<string[]>([]);\n const [role, setRole] = useState<'member' | 'admin'>('member');\n const [copySuccess, setCopySuccess] = useState(false);\n const [shareSuccess, setShareSuccess] = useState(false);\n const [sendSuccess, setSendSuccess] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n const [invitedContactIds, setInvitedContactIds] = useState<Set<string>>(new Set());\n const [invitedGoogleContactIds, setInvitedGoogleContactIds] = useState<Set<string>>(new Set());\n const [googleSearchQuery, setGoogleSearchQuery] = useState('');\n const [loadingContactIds, setLoadingContactIds] = useState<Set<string>>(new Set());\n const [loadingGoogleContactIds, setLoadingGoogleContactIds] = useState<Set<string>>(new Set());\n const [loadingEmailInvite, setLoadingEmailInvite] = useState(false);\n const [loadingCopy, setLoadingCopy] = useState(false);\n const [loadingShare, setLoadingShare] = useState(false);\n const [invitationLink, setInvitationLink] = useState<string>('https://app.vortexsoftware.com/invite/abc123');\n const [loadingInvitationLink, setLoadingInvitationLink] = useState(false);\n const fetchedRef = useRef(false);\n\n // Fetch the actual invitation link when QR code view is shown\n // In web/preview mode, skip fetching and use the placeholder for demo purposes\n useEffect(() => {\n // If we're in web mode, don't fetch - just show the placeholder immediately\n if (Platform.OS === 'web') {\n console.log('[Vortex] Web preview mode: using placeholder QR code for demo');\n return;\n }\n\n if (view === 'qrcode' && getShareableInviteLink && !fetchedRef.current) {\n fetchedRef.current = true;\n setLoadingInvitationLink(true);\n getShareableInviteLink()\n .then((link) => {\n if (link) {\n setInvitationLink(link);\n console.log('[Vortex] QR code invitation link fetched:', link);\n } else {\n console.warn('[Vortex] No invitation link available for QR code');\n }\n })\n .catch((error) => {\n console.error('[Vortex] Failed to fetch invitation link for QR code:', error);\n fetchedRef.current = false; // Allow retry on error\n })\n .finally(() => {\n setLoadingInvitationLink(false);\n });\n }\n \n // Reset when leaving QR code view\n if (view !== 'qrcode') {\n fetchedRef.current = false;\n }\n }, [view, getShareableInviteLink]);\n\n const handleClose = () => {\n platformOps.close();\n };\n\n const handleSendInvitation = async () => {\n // First, process any pending email in the input field\n const trimmedEmail = emailInput.trim();\n let emailsToSend = [...emails];\n \n if (trimmedEmail && isValidEmail(trimmedEmail)) {\n // Add the pending email to the list\n emailsToSend = [...emails, trimmedEmail];\n setEmails(emailsToSend);\n }\n\n // If pending text exists but is invalid, show feedback instead of silently ignoring\n if (trimmedEmail && !isValidEmail(trimmedEmail)) {\n setLastInvalidEmail(trimmedEmail);\n setTimeout(() => setLastInvalidEmail(null), 1500);\n }\n\n // If there are no emails to send, don't proceed\n if (emailsToSend.length === 0) {\n return;\n }\n\n // De-duplicate before sending (user may have entered the same email twice)\n const uniqueEmails = [...new Set(emailsToSend)];\n\n setLoadingEmailInvite(true);\n try {\n // Send invites for all unique emails\n await Promise.all(uniqueEmails.map((email) => platformOps.invite(email)));\n\n console.log('[Vortex] Successfully sent invitations to:', emailsToSend);\n setSendSuccess(true);\n setEmails([]);\n setEmailInput('');\n setTimeout(() => setSendSuccess(false), 2000);\n } catch (error) {\n console.error('[Vortex] Failed to send invitations:', error);\n // Could add error state here if needed\n } finally {\n setLoadingEmailInvite(false);\n }\n };\n\n const handleCopyLink = async () => {\n setLoadingCopy(true);\n try {\n await platformOps.copyToClipboard();\n setCopySuccess(true);\n setTimeout(() => setCopySuccess(false), 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n // On error, loading state is cleared but success is not set\n } finally {\n setLoadingCopy(false);\n }\n };\n\n const handleShare = async () => {\n setLoadingShare(true);\n try {\n await platformOps.share();\n setShareSuccess(true);\n setTimeout(() => setShareSuccess(false), 2000);\n } catch (err) {\n console.error('Failed to share:', err);\n // On error, loading state is cleared but success is not set\n } finally {\n setLoadingShare(false);\n }\n };\n\n const isValidEmail = (email: string): boolean => {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email.trim());\n };\n\n // Track the last invalid email attempt so the UI can show feedback\n const [lastInvalidEmail, setLastInvalidEmail] = useState<string | null>(null);\n\n const handleEmailSubmit = (overrideEmail?: string) => {\n const trimmedEmail = (overrideEmail ?? emailInput).trim();\n if (!trimmedEmail) return;\n\n if (isValidEmail(trimmedEmail)) {\n // Allow duplicate emails — they will be de-duplicated before sending\n setEmails([...emails, trimmedEmail]);\n setEmailInput('');\n setLastInvalidEmail(null);\n } else {\n // Signal invalid email so the UI can show brief feedback (red border flash)\n setLastInvalidEmail(trimmedEmail);\n // Auto-clear the invalid state after a short delay\n setTimeout(() => setLastInvalidEmail(null), 1500);\n }\n };\n\n const handleRemoveEmail = (emailToRemove: string) => {\n setEmails(emails.filter((email) => email !== emailToRemove));\n };\n\n const handleSelectFromGoogle = () => {\n setView('googleContacts');\n };\n\n const handleSelectFromContacts = () => {\n setView('contacts');\n };\n\n const handleAddByEmail = () => {\n setView('email');\n };\n\n const handleShowQrCode = () => {\n setView('qrcode');\n };\n\n const handleBackToMain = () => {\n console.log('[Vortex] handleBackToMain called, returning to main view');\n console.log('[Vortex] Current view before setView:', view);\n setView('main');\n console.log('[Vortex] setView(\"main\") called');\n setSearchQuery('');\n setGoogleSearchQuery('');\n };\n\n const handleInviteContact = async (contactId: string) => {\n const contact = contacts?.find((c) => c.id === contactId);\n if (!contact) {\n console.error('[Vortex] Contact not found:', contactId);\n return;\n }\n\n // Add to loading set\n setLoadingContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.add(contactId);\n return newSet;\n });\n\n try {\n await platformOps.invite(contact.email, contact.name);\n\n setInvitedContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.add(contactId);\n return newSet;\n });\n } catch (error) {\n console.error('[Vortex] Failed to invite contact:', error);\n // On error, we don't add to invited set, just remove from loading\n } finally {\n // Remove from loading set\n setLoadingContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.delete(contactId);\n return newSet;\n });\n }\n };\n\n const handleInviteGoogleContact = async (contactId: string) => {\n const contact = googleContacts?.find((c) => c.id === contactId);\n if (!contact) {\n console.error('[Vortex] Google contact not found:', contactId);\n return;\n }\n\n // Add to loading set\n setLoadingGoogleContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.add(contactId);\n return newSet;\n });\n\n try {\n await platformOps.invite(contact.email, contact.name);\n\n setInvitedGoogleContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.add(contactId);\n return newSet;\n });\n } catch (error) {\n console.error('[Vortex] Failed to invite Google contact:', error);\n // On error, we don't add to invited set, just remove from loading\n } finally {\n // Remove from loading set\n setLoadingGoogleContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.delete(contactId);\n return newSet;\n });\n }\n };\n\n return {\n // State\n view,\n emailInput,\n emails,\n role,\n copySuccess,\n shareSuccess,\n sendSuccess,\n searchQuery,\n invitedContactIds,\n invitedGoogleContactIds,\n googleSearchQuery,\n invitationLink,\n loadingContactIds,\n loadingGoogleContactIds,\n loadingEmailInvite,\n loadingCopy,\n loadingShare,\n loadingInvitationLink,\n lastInvalidEmail,\n // Setters\n setView,\n setEmailInput,\n setEmails,\n setRole,\n setCopySuccess,\n setShareSuccess,\n setSendSuccess,\n setSearchQuery,\n setInvitedContactIds,\n setInvitedGoogleContactIds,\n setGoogleSearchQuery,\n // Handlers\n handleClose,\n handleSendInvitation,\n handleCopyLink,\n handleShare,\n isValidEmail,\n handleEmailSubmit,\n handleRemoveEmail,\n handleSelectFromGoogle,\n handleSelectFromContacts,\n handleAddByEmail,\n handleShowQrCode,\n handleBackToMain,\n handleInviteContact,\n handleInviteGoogleContact,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
var __async = (__this, __arguments, generator) => {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
var fulfilled = (value) => {
|
|
4
|
+
try {
|
|
5
|
+
step(generator.next(value));
|
|
6
|
+
} catch (e) {
|
|
7
|
+
reject(e);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var rejected = (value) => {
|
|
11
|
+
try {
|
|
12
|
+
step(generator.throw(value));
|
|
13
|
+
} catch (e) {
|
|
14
|
+
reject(e);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
18
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// src/hooks/useInvitationFormLogic.ts
|
|
23
|
+
import { useState, useEffect, useRef } from "react";
|
|
24
|
+
import { Platform } from "react-native";
|
|
25
|
+
function useInvitationFormLogic(platformOps, contacts, googleContacts, getShareableInviteLink) {
|
|
26
|
+
const [view, setView] = useState("main");
|
|
27
|
+
const [emailInput, setEmailInput] = useState("");
|
|
28
|
+
const [emails, setEmails] = useState([]);
|
|
29
|
+
const [role, setRole] = useState("member");
|
|
30
|
+
const [copySuccess, setCopySuccess] = useState(false);
|
|
31
|
+
const [shareSuccess, setShareSuccess] = useState(false);
|
|
32
|
+
const [sendSuccess, setSendSuccess] = useState(false);
|
|
33
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
34
|
+
const [invitedContactIds, setInvitedContactIds] = useState(/* @__PURE__ */ new Set());
|
|
35
|
+
const [invitedGoogleContactIds, setInvitedGoogleContactIds] = useState(/* @__PURE__ */ new Set());
|
|
36
|
+
const [googleSearchQuery, setGoogleSearchQuery] = useState("");
|
|
37
|
+
const [loadingContactIds, setLoadingContactIds] = useState(/* @__PURE__ */ new Set());
|
|
38
|
+
const [loadingGoogleContactIds, setLoadingGoogleContactIds] = useState(/* @__PURE__ */ new Set());
|
|
39
|
+
const [loadingEmailInvite, setLoadingEmailInvite] = useState(false);
|
|
40
|
+
const [loadingCopy, setLoadingCopy] = useState(false);
|
|
41
|
+
const [loadingShare, setLoadingShare] = useState(false);
|
|
42
|
+
const [invitationLink, setInvitationLink] = useState("https://app.vortexsoftware.com/invite/abc123");
|
|
43
|
+
const [loadingInvitationLink, setLoadingInvitationLink] = useState(false);
|
|
44
|
+
const fetchedRef = useRef(false);
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (Platform.OS === "web") {
|
|
47
|
+
console.log("[Vortex] Web preview mode: using placeholder QR code for demo");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (view === "qrcode" && getShareableInviteLink && !fetchedRef.current) {
|
|
51
|
+
fetchedRef.current = true;
|
|
52
|
+
setLoadingInvitationLink(true);
|
|
53
|
+
getShareableInviteLink().then((link) => {
|
|
54
|
+
if (link) {
|
|
55
|
+
setInvitationLink(link);
|
|
56
|
+
console.log("[Vortex] QR code invitation link fetched:", link);
|
|
57
|
+
} else {
|
|
58
|
+
console.warn("[Vortex] No invitation link available for QR code");
|
|
59
|
+
}
|
|
60
|
+
}).catch((error) => {
|
|
61
|
+
console.error("[Vortex] Failed to fetch invitation link for QR code:", error);
|
|
62
|
+
fetchedRef.current = false;
|
|
63
|
+
}).finally(() => {
|
|
64
|
+
setLoadingInvitationLink(false);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (view !== "qrcode") {
|
|
68
|
+
fetchedRef.current = false;
|
|
69
|
+
}
|
|
70
|
+
}, [view, getShareableInviteLink]);
|
|
71
|
+
const handleClose = () => {
|
|
72
|
+
platformOps.close();
|
|
73
|
+
};
|
|
74
|
+
const handleSendInvitation = () => __async(null, null, function* () {
|
|
75
|
+
const trimmedEmail = emailInput.trim();
|
|
76
|
+
let emailsToSend = [...emails];
|
|
77
|
+
if (trimmedEmail && isValidEmail(trimmedEmail)) {
|
|
78
|
+
emailsToSend = [...emails, trimmedEmail];
|
|
79
|
+
setEmails(emailsToSend);
|
|
80
|
+
}
|
|
81
|
+
if (trimmedEmail && !isValidEmail(trimmedEmail)) {
|
|
82
|
+
setLastInvalidEmail(trimmedEmail);
|
|
83
|
+
setTimeout(() => setLastInvalidEmail(null), 1500);
|
|
84
|
+
}
|
|
85
|
+
if (emailsToSend.length === 0) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const uniqueEmails = [...new Set(emailsToSend)];
|
|
89
|
+
setLoadingEmailInvite(true);
|
|
90
|
+
try {
|
|
91
|
+
yield Promise.all(uniqueEmails.map((email) => platformOps.invite(email)));
|
|
92
|
+
console.log("[Vortex] Successfully sent invitations to:", emailsToSend);
|
|
93
|
+
setSendSuccess(true);
|
|
94
|
+
setEmails([]);
|
|
95
|
+
setEmailInput("");
|
|
96
|
+
setTimeout(() => setSendSuccess(false), 2e3);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error("[Vortex] Failed to send invitations:", error);
|
|
99
|
+
} finally {
|
|
100
|
+
setLoadingEmailInvite(false);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
const handleCopyLink = () => __async(null, null, function* () {
|
|
104
|
+
setLoadingCopy(true);
|
|
105
|
+
try {
|
|
106
|
+
yield platformOps.copyToClipboard();
|
|
107
|
+
setCopySuccess(true);
|
|
108
|
+
setTimeout(() => setCopySuccess(false), 2e3);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error("Failed to copy:", err);
|
|
111
|
+
} finally {
|
|
112
|
+
setLoadingCopy(false);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
const handleShare = () => __async(null, null, function* () {
|
|
116
|
+
setLoadingShare(true);
|
|
117
|
+
try {
|
|
118
|
+
yield platformOps.share();
|
|
119
|
+
setShareSuccess(true);
|
|
120
|
+
setTimeout(() => setShareSuccess(false), 2e3);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.error("Failed to share:", err);
|
|
123
|
+
} finally {
|
|
124
|
+
setLoadingShare(false);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
const isValidEmail = (email) => {
|
|
128
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
129
|
+
return emailRegex.test(email.trim());
|
|
130
|
+
};
|
|
131
|
+
const [lastInvalidEmail, setLastInvalidEmail] = useState(null);
|
|
132
|
+
const handleEmailSubmit = (overrideEmail) => {
|
|
133
|
+
const trimmedEmail = (overrideEmail != null ? overrideEmail : emailInput).trim();
|
|
134
|
+
if (!trimmedEmail) return;
|
|
135
|
+
if (isValidEmail(trimmedEmail)) {
|
|
136
|
+
setEmails([...emails, trimmedEmail]);
|
|
137
|
+
setEmailInput("");
|
|
138
|
+
setLastInvalidEmail(null);
|
|
139
|
+
} else {
|
|
140
|
+
setLastInvalidEmail(trimmedEmail);
|
|
141
|
+
setTimeout(() => setLastInvalidEmail(null), 1500);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
const handleRemoveEmail = (emailToRemove) => {
|
|
145
|
+
setEmails(emails.filter((email) => email !== emailToRemove));
|
|
146
|
+
};
|
|
147
|
+
const handleSelectFromGoogle = () => {
|
|
148
|
+
setView("googleContacts");
|
|
149
|
+
};
|
|
150
|
+
const handleSelectFromContacts = () => {
|
|
151
|
+
setView("contacts");
|
|
152
|
+
};
|
|
153
|
+
const handleAddByEmail = () => {
|
|
154
|
+
setView("email");
|
|
155
|
+
};
|
|
156
|
+
const handleShowQrCode = () => {
|
|
157
|
+
setView("qrcode");
|
|
158
|
+
};
|
|
159
|
+
const handleBackToMain = () => {
|
|
160
|
+
console.log("[Vortex] handleBackToMain called, returning to main view");
|
|
161
|
+
console.log("[Vortex] Current view before setView:", view);
|
|
162
|
+
setView("main");
|
|
163
|
+
console.log('[Vortex] setView("main") called');
|
|
164
|
+
setSearchQuery("");
|
|
165
|
+
setGoogleSearchQuery("");
|
|
166
|
+
};
|
|
167
|
+
const handleInviteContact = (contactId) => __async(null, null, function* () {
|
|
168
|
+
const contact = contacts == null ? void 0 : contacts.find((c) => c.id === contactId);
|
|
169
|
+
if (!contact) {
|
|
170
|
+
console.error("[Vortex] Contact not found:", contactId);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
setLoadingContactIds((prev) => {
|
|
174
|
+
const newSet = new Set(prev);
|
|
175
|
+
newSet.add(contactId);
|
|
176
|
+
return newSet;
|
|
177
|
+
});
|
|
178
|
+
try {
|
|
179
|
+
yield platformOps.invite(contact.email, contact.name);
|
|
180
|
+
setInvitedContactIds((prev) => {
|
|
181
|
+
const newSet = new Set(prev);
|
|
182
|
+
newSet.add(contactId);
|
|
183
|
+
return newSet;
|
|
184
|
+
});
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.error("[Vortex] Failed to invite contact:", error);
|
|
187
|
+
} finally {
|
|
188
|
+
setLoadingContactIds((prev) => {
|
|
189
|
+
const newSet = new Set(prev);
|
|
190
|
+
newSet.delete(contactId);
|
|
191
|
+
return newSet;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
const handleInviteGoogleContact = (contactId) => __async(null, null, function* () {
|
|
196
|
+
const contact = googleContacts == null ? void 0 : googleContacts.find((c) => c.id === contactId);
|
|
197
|
+
if (!contact) {
|
|
198
|
+
console.error("[Vortex] Google contact not found:", contactId);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
setLoadingGoogleContactIds((prev) => {
|
|
202
|
+
const newSet = new Set(prev);
|
|
203
|
+
newSet.add(contactId);
|
|
204
|
+
return newSet;
|
|
205
|
+
});
|
|
206
|
+
try {
|
|
207
|
+
yield platformOps.invite(contact.email, contact.name);
|
|
208
|
+
setInvitedGoogleContactIds((prev) => {
|
|
209
|
+
const newSet = new Set(prev);
|
|
210
|
+
newSet.add(contactId);
|
|
211
|
+
return newSet;
|
|
212
|
+
});
|
|
213
|
+
} catch (error) {
|
|
214
|
+
console.error("[Vortex] Failed to invite Google contact:", error);
|
|
215
|
+
} finally {
|
|
216
|
+
setLoadingGoogleContactIds((prev) => {
|
|
217
|
+
const newSet = new Set(prev);
|
|
218
|
+
newSet.delete(contactId);
|
|
219
|
+
return newSet;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
return {
|
|
224
|
+
// State
|
|
225
|
+
view,
|
|
226
|
+
emailInput,
|
|
227
|
+
emails,
|
|
228
|
+
role,
|
|
229
|
+
copySuccess,
|
|
230
|
+
shareSuccess,
|
|
231
|
+
sendSuccess,
|
|
232
|
+
searchQuery,
|
|
233
|
+
invitedContactIds,
|
|
234
|
+
invitedGoogleContactIds,
|
|
235
|
+
googleSearchQuery,
|
|
236
|
+
invitationLink,
|
|
237
|
+
loadingContactIds,
|
|
238
|
+
loadingGoogleContactIds,
|
|
239
|
+
loadingEmailInvite,
|
|
240
|
+
loadingCopy,
|
|
241
|
+
loadingShare,
|
|
242
|
+
loadingInvitationLink,
|
|
243
|
+
lastInvalidEmail,
|
|
244
|
+
// Setters
|
|
245
|
+
setView,
|
|
246
|
+
setEmailInput,
|
|
247
|
+
setEmails,
|
|
248
|
+
setRole,
|
|
249
|
+
setCopySuccess,
|
|
250
|
+
setShareSuccess,
|
|
251
|
+
setSendSuccess,
|
|
252
|
+
setSearchQuery,
|
|
253
|
+
setInvitedContactIds,
|
|
254
|
+
setInvitedGoogleContactIds,
|
|
255
|
+
setGoogleSearchQuery,
|
|
256
|
+
// Handlers
|
|
257
|
+
handleClose,
|
|
258
|
+
handleSendInvitation,
|
|
259
|
+
handleCopyLink,
|
|
260
|
+
handleShare,
|
|
261
|
+
isValidEmail,
|
|
262
|
+
handleEmailSubmit,
|
|
263
|
+
handleRemoveEmail,
|
|
264
|
+
handleSelectFromGoogle,
|
|
265
|
+
handleSelectFromContacts,
|
|
266
|
+
handleAddByEmail,
|
|
267
|
+
handleShowQrCode,
|
|
268
|
+
handleBackToMain,
|
|
269
|
+
handleInviteContact,
|
|
270
|
+
handleInviteGoogleContact
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
export {
|
|
274
|
+
useInvitationFormLogic
|
|
275
|
+
};
|
|
276
|
+
//# sourceMappingURL=useInvitationFormLogic.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/useInvitationFormLogic.ts"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport { Platform } from 'react-native';\nimport { PlatformOperations } from '../types/platformOperations';\n\nexport type ViewType = 'main' | 'email' | 'contacts' | 'googleContacts' | 'qrcode';\n\nexport interface Contact {\n id: string;\n name: string;\n email: string;\n imageUri?: string;\n}\n\nexport function useInvitationFormLogic(\n platformOps: PlatformOperations,\n contacts?: Contact[],\n googleContacts?: Contact[],\n getShareableInviteLink?: () => Promise<string | undefined>\n) {\n const [view, setView] = useState<ViewType>('main');\n const [emailInput, setEmailInput] = useState('');\n const [emails, setEmails] = useState<string[]>([]);\n const [role, setRole] = useState<'member' | 'admin'>('member');\n const [copySuccess, setCopySuccess] = useState(false);\n const [shareSuccess, setShareSuccess] = useState(false);\n const [sendSuccess, setSendSuccess] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n const [invitedContactIds, setInvitedContactIds] = useState<Set<string>>(new Set());\n const [invitedGoogleContactIds, setInvitedGoogleContactIds] = useState<Set<string>>(new Set());\n const [googleSearchQuery, setGoogleSearchQuery] = useState('');\n const [loadingContactIds, setLoadingContactIds] = useState<Set<string>>(new Set());\n const [loadingGoogleContactIds, setLoadingGoogleContactIds] = useState<Set<string>>(new Set());\n const [loadingEmailInvite, setLoadingEmailInvite] = useState(false);\n const [loadingCopy, setLoadingCopy] = useState(false);\n const [loadingShare, setLoadingShare] = useState(false);\n const [invitationLink, setInvitationLink] = useState<string>('https://app.vortexsoftware.com/invite/abc123');\n const [loadingInvitationLink, setLoadingInvitationLink] = useState(false);\n const fetchedRef = useRef(false);\n\n // Fetch the actual invitation link when QR code view is shown\n // In web/preview mode, skip fetching and use the placeholder for demo purposes\n useEffect(() => {\n // If we're in web mode, don't fetch - just show the placeholder immediately\n if (Platform.OS === 'web') {\n console.log('[Vortex] Web preview mode: using placeholder QR code for demo');\n return;\n }\n\n if (view === 'qrcode' && getShareableInviteLink && !fetchedRef.current) {\n fetchedRef.current = true;\n setLoadingInvitationLink(true);\n getShareableInviteLink()\n .then((link) => {\n if (link) {\n setInvitationLink(link);\n console.log('[Vortex] QR code invitation link fetched:', link);\n } else {\n console.warn('[Vortex] No invitation link available for QR code');\n }\n })\n .catch((error) => {\n console.error('[Vortex] Failed to fetch invitation link for QR code:', error);\n fetchedRef.current = false; // Allow retry on error\n })\n .finally(() => {\n setLoadingInvitationLink(false);\n });\n }\n \n // Reset when leaving QR code view\n if (view !== 'qrcode') {\n fetchedRef.current = false;\n }\n }, [view, getShareableInviteLink]);\n\n const handleClose = () => {\n platformOps.close();\n };\n\n const handleSendInvitation = async () => {\n // First, process any pending email in the input field\n const trimmedEmail = emailInput.trim();\n let emailsToSend = [...emails];\n \n if (trimmedEmail && isValidEmail(trimmedEmail)) {\n // Add the pending email to the list\n emailsToSend = [...emails, trimmedEmail];\n setEmails(emailsToSend);\n }\n\n // If pending text exists but is invalid, show feedback instead of silently ignoring\n if (trimmedEmail && !isValidEmail(trimmedEmail)) {\n setLastInvalidEmail(trimmedEmail);\n setTimeout(() => setLastInvalidEmail(null), 1500);\n }\n\n // If there are no emails to send, don't proceed\n if (emailsToSend.length === 0) {\n return;\n }\n\n // De-duplicate before sending (user may have entered the same email twice)\n const uniqueEmails = [...new Set(emailsToSend)];\n\n setLoadingEmailInvite(true);\n try {\n // Send invites for all unique emails\n await Promise.all(uniqueEmails.map((email) => platformOps.invite(email)));\n\n console.log('[Vortex] Successfully sent invitations to:', emailsToSend);\n setSendSuccess(true);\n setEmails([]);\n setEmailInput('');\n setTimeout(() => setSendSuccess(false), 2000);\n } catch (error) {\n console.error('[Vortex] Failed to send invitations:', error);\n // Could add error state here if needed\n } finally {\n setLoadingEmailInvite(false);\n }\n };\n\n const handleCopyLink = async () => {\n setLoadingCopy(true);\n try {\n await platformOps.copyToClipboard();\n setCopySuccess(true);\n setTimeout(() => setCopySuccess(false), 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n // On error, loading state is cleared but success is not set\n } finally {\n setLoadingCopy(false);\n }\n };\n\n const handleShare = async () => {\n setLoadingShare(true);\n try {\n await platformOps.share();\n setShareSuccess(true);\n setTimeout(() => setShareSuccess(false), 2000);\n } catch (err) {\n console.error('Failed to share:', err);\n // On error, loading state is cleared but success is not set\n } finally {\n setLoadingShare(false);\n }\n };\n\n const isValidEmail = (email: string): boolean => {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email.trim());\n };\n\n // Track the last invalid email attempt so the UI can show feedback\n const [lastInvalidEmail, setLastInvalidEmail] = useState<string | null>(null);\n\n const handleEmailSubmit = (overrideEmail?: string) => {\n const trimmedEmail = (overrideEmail ?? emailInput).trim();\n if (!trimmedEmail) return;\n\n if (isValidEmail(trimmedEmail)) {\n // Allow duplicate emails — they will be de-duplicated before sending\n setEmails([...emails, trimmedEmail]);\n setEmailInput('');\n setLastInvalidEmail(null);\n } else {\n // Signal invalid email so the UI can show brief feedback (red border flash)\n setLastInvalidEmail(trimmedEmail);\n // Auto-clear the invalid state after a short delay\n setTimeout(() => setLastInvalidEmail(null), 1500);\n }\n };\n\n const handleRemoveEmail = (emailToRemove: string) => {\n setEmails(emails.filter((email) => email !== emailToRemove));\n };\n\n const handleSelectFromGoogle = () => {\n setView('googleContacts');\n };\n\n const handleSelectFromContacts = () => {\n setView('contacts');\n };\n\n const handleAddByEmail = () => {\n setView('email');\n };\n\n const handleShowQrCode = () => {\n setView('qrcode');\n };\n\n const handleBackToMain = () => {\n console.log('[Vortex] handleBackToMain called, returning to main view');\n console.log('[Vortex] Current view before setView:', view);\n setView('main');\n console.log('[Vortex] setView(\"main\") called');\n setSearchQuery('');\n setGoogleSearchQuery('');\n };\n\n const handleInviteContact = async (contactId: string) => {\n const contact = contacts?.find((c) => c.id === contactId);\n if (!contact) {\n console.error('[Vortex] Contact not found:', contactId);\n return;\n }\n\n // Add to loading set\n setLoadingContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.add(contactId);\n return newSet;\n });\n\n try {\n await platformOps.invite(contact.email, contact.name);\n\n setInvitedContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.add(contactId);\n return newSet;\n });\n } catch (error) {\n console.error('[Vortex] Failed to invite contact:', error);\n // On error, we don't add to invited set, just remove from loading\n } finally {\n // Remove from loading set\n setLoadingContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.delete(contactId);\n return newSet;\n });\n }\n };\n\n const handleInviteGoogleContact = async (contactId: string) => {\n const contact = googleContacts?.find((c) => c.id === contactId);\n if (!contact) {\n console.error('[Vortex] Google contact not found:', contactId);\n return;\n }\n\n // Add to loading set\n setLoadingGoogleContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.add(contactId);\n return newSet;\n });\n\n try {\n await platformOps.invite(contact.email, contact.name);\n\n setInvitedGoogleContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.add(contactId);\n return newSet;\n });\n } catch (error) {\n console.error('[Vortex] Failed to invite Google contact:', error);\n // On error, we don't add to invited set, just remove from loading\n } finally {\n // Remove from loading set\n setLoadingGoogleContactIds((prev) => {\n const newSet = new Set(prev);\n newSet.delete(contactId);\n return newSet;\n });\n }\n };\n\n return {\n // State\n view,\n emailInput,\n emails,\n role,\n copySuccess,\n shareSuccess,\n sendSuccess,\n searchQuery,\n invitedContactIds,\n invitedGoogleContactIds,\n googleSearchQuery,\n invitationLink,\n loadingContactIds,\n loadingGoogleContactIds,\n loadingEmailInvite,\n loadingCopy,\n loadingShare,\n loadingInvitationLink,\n lastInvalidEmail,\n // Setters\n setView,\n setEmailInput,\n setEmails,\n setRole,\n setCopySuccess,\n setShareSuccess,\n setSendSuccess,\n setSearchQuery,\n setInvitedContactIds,\n setInvitedGoogleContactIds,\n setGoogleSearchQuery,\n // Handlers\n handleClose,\n handleSendInvitation,\n handleCopyLink,\n handleShare,\n isValidEmail,\n handleEmailSubmit,\n handleRemoveEmail,\n handleSelectFromGoogle,\n handleSelectFromContacts,\n handleAddByEmail,\n handleShowQrCode,\n handleBackToMain,\n handleInviteContact,\n handleInviteGoogleContact,\n };\n}\n"],"mappings":"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","names":[]}
|