@teamvortexsoftware/vortex-react-native 0.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/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@teamvortexsoftware/vortex-react-native",
3
+ "description": "",
4
+ "author": "@teamvortexsoftware",
5
+ "version": "0.0.1",
6
+ "publishConfig": {
7
+ "access": "restricted"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "devDependencies": {
12
+ "@types/react": "18.2.14",
13
+ "tsup": "8.0.1",
14
+ "typescript": "5.5.4",
15
+ "@teamvortexsoftware/typescript-config": "0.0.0"
16
+ },
17
+ "dependencies": {
18
+ "react": "18.2.0",
19
+ "react-native": "0.74.5"
20
+ },
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "dev": "tsup --watch",
24
+ "clean": "rm -rf dist"
25
+ }
26
+ }
package/src/button.tsx ADDED
@@ -0,0 +1,42 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Pressable, StyleSheet, Text } from "react-native";
3
+
4
+ export interface ButtonProps {
5
+ text: string;
6
+ onClick?: (e: any) => void;
7
+ }
8
+
9
+ export function Button({ text, onClick }: ButtonProps) {
10
+ const [count, setCount] = useState(0);
11
+
12
+ useEffect(() => {
13
+ console.log("Current count:", count);
14
+ }, [count]);
15
+
16
+ const handlePress = (e: any) => {
17
+ console.log("handlePress called");
18
+ setCount((prevCount) => prevCount + 1);
19
+ if (onClick) {
20
+ onClick(e);
21
+ }
22
+ };
23
+
24
+ return <Text style={styles.text}>{text}</Text>;
25
+ }
26
+
27
+ const styles = StyleSheet.create({
28
+ button: {
29
+ maxWidth: 200,
30
+ textAlign: "center",
31
+ borderRadius: 10,
32
+ paddingTop: 14,
33
+ paddingBottom: 14,
34
+ paddingLeft: 30,
35
+ paddingRight: 30,
36
+ fontSize: 15,
37
+ backgroundColor: "#2f80ed",
38
+ },
39
+ text: {
40
+ color: "white",
41
+ },
42
+ });
package/src/index.tsx ADDED
@@ -0,0 +1,2 @@
1
+ export { Button, type ButtonProps } from "./button";
2
+ export { VortexInvite, type VortexInviteProps } from "./vortexInvite";
@@ -0,0 +1,24 @@
1
+ class VortexClient {
2
+ private host: string;
3
+
4
+ constructor(host: string) {
5
+ this.host = host;
6
+ }
7
+
8
+ async getWidgetConfiguration(widgetConfigurationId: string) {
9
+ const response = await fetch(
10
+ `${this.host}/api/v1/no-auth/components/widget-configuration/${widgetConfigurationId}`,
11
+ );
12
+
13
+ if (!response.ok) {
14
+ throw new Error(
15
+ `Error fetching widget configuration: ${response.statusText}`,
16
+ );
17
+ }
18
+
19
+ const data = await response.json();
20
+ return data;
21
+ }
22
+ }
23
+
24
+ export default VortexClient;
@@ -0,0 +1,453 @@
1
+ import React, { useEffect, useMemo, useState } from "react";
2
+ import {
3
+ View,
4
+ Text,
5
+ TextInput,
6
+ Button,
7
+ TouchableOpacity,
8
+ StyleSheet,
9
+ ActivityIndicator,
10
+ Alert,
11
+ Linking,
12
+ Share,
13
+ ScrollView,
14
+ Modal,
15
+ Pressable,
16
+ Animated,
17
+ } from "react-native";
18
+ import VortexClient from "./shared/api";
19
+ // import Clipboard from "@react-native-clipboard/clipboard";
20
+ // import QRCode from "react-native-qrcode-svg";
21
+ // import Icon from "react-native-vector-icons/FontAwesome";
22
+
23
+ interface WidgetConfiguration {
24
+ configuration?: {
25
+ props?: any;
26
+ styles?: any;
27
+ };
28
+ slug?: string;
29
+ [key: string]: any;
30
+ }
31
+
32
+ export interface VortexInviteProps {
33
+ widgetConfigurationId?: string;
34
+ widgetConfiguration?: WidgetConfiguration;
35
+ isLoading?: boolean;
36
+ }
37
+
38
+ export function VortexInvite({
39
+ widgetConfigurationId,
40
+ widgetConfiguration,
41
+ isLoading = false,
42
+ }: VortexInviteProps) {
43
+ // TODO - Remove this hardcoded host
44
+ // const host = "http://localhost:3003";
45
+ // if (host.indexOf("localhost") > -1) {
46
+ // console.warn("Vortex:Invite Using localhost as host");
47
+ // }
48
+
49
+ // const vortex = new VortexClient(host);
50
+
51
+ // const [widgetConfiguration_INTERNAL, setWidgetConfiguration] = useState<
52
+ // any | null
53
+ // >(widgetConfiguration ?? null);
54
+ // const [error, setError] = useState<{ message: string } | null>(null);
55
+ // const [fetching, setFetching] = useState(isLoading); // Start fetching if isLoading is true
56
+ // const [loading, setLoading] = useState(true);
57
+
58
+ // const [email, setEmail] = useState("");
59
+
60
+ // const opacity = new Animated.Value(0.3);
61
+
62
+ // useEffect(() => {
63
+ // const animation = Animated.loop(
64
+ // Animated.sequence([
65
+ // Animated.timing(opacity, {
66
+ // toValue: 1,
67
+ // duration: 1000,
68
+ // useNativeDriver: true,
69
+ // }),
70
+ // Animated.timing(opacity, {
71
+ // toValue: 0.3,
72
+ // duration: 1000,
73
+ // useNativeDriver: true,
74
+ // }),
75
+ // ]),
76
+ // );
77
+ // animation.start();
78
+
79
+ // setTimeout(() => {
80
+ // setLoading(false);
81
+ // animation.stop();
82
+ // }, 2000);
83
+ // }, []);
84
+
85
+ // useEffect(() => {
86
+ // if (widgetConfiguration && Object.keys(widgetConfiguration).length > 0) {
87
+ // console.debug("Vortex:Invite Using provided widgetConfiguration");
88
+ // setWidgetConfiguration(widgetConfiguration);
89
+ // setFetching(false);
90
+ // setError(null); // Clear any errors if valid data arrives
91
+ // setLoading(false);
92
+ // }
93
+ // }, [widgetConfiguration]);
94
+
95
+ // useEffect(() => {
96
+ // // Case: If `widgetConfiguration_INTERNAL` is already set, do nothing
97
+ // if (widgetConfiguration_INTERNAL) {
98
+ // console.debug(
99
+ // "Vortex:Invite Already has widgetConfiguration, skipping fetch",
100
+ // );
101
+ // return;
102
+ // }
103
+
104
+ // // Case: No `widgetConfigurationId` and no `widgetConfiguration`, WAIT for updates instead of erroring
105
+ // if (!widgetConfigurationId) {
106
+ // console.debug("Vortex:Invite Waiting for widgetConfigurationId...");
107
+ // return;
108
+ // }
109
+
110
+ // // **API Fetching Logic**
111
+ // const fetchData = async (widgetConfigurationId: any | string) => {
112
+ // console.debug("Vortex:Invite Fetching Data...");
113
+ // setFetching(true);
114
+ // setLoading(true);
115
+ // setError(null);
116
+
117
+ // try {
118
+ // const result = await vortex.getWidgetConfiguration(
119
+ // widgetConfigurationId,
120
+ // );
121
+ // if (result?.data?.widgetConfiguration) {
122
+ // setWidgetConfiguration(result.data.widgetConfiguration);
123
+ // console.debug(
124
+ // "Vortex:Invite Successfully fetched widgetConfiguration",
125
+ // );
126
+ // } else {
127
+ // const error = result?.error || "No configuration data found.";
128
+ // console.error(`Vortex:Invite ${error}`);
129
+ // throw new Error(error);
130
+ // }
131
+ // } catch (err) {
132
+ // setError({
133
+ // message: (err as Error).message || "Something went wrong!",
134
+ // });
135
+ // } finally {
136
+ // setFetching(false);
137
+ // setLoading(false);
138
+ // }
139
+ // };
140
+
141
+ // fetchData(widgetConfigurationId);
142
+ // }, [widgetConfigurationId]);
143
+
144
+ // const options = useMemo(() => {
145
+ // return widgetConfiguration_INTERNAL?.configuration?.props || {};
146
+ // }, [widgetConfiguration_INTERNAL]);
147
+
148
+ // const has = useMemo(() => {
149
+ // const features: string[] = Array.isArray(
150
+ // widgetConfiguration_INTERNAL?.configuration?.props?.features?.value,
151
+ // )
152
+ // ? widgetConfiguration_INTERNAL?.configuration?.props?.features?.value
153
+ // : [];
154
+
155
+ // const shareOptions: string[] = Array.isArray(
156
+ // widgetConfiguration_INTERNAL?.configuration?.props?.shareOptions?.value,
157
+ // )
158
+ // ? widgetConfiguration_INTERNAL?.configuration?.props?.shareOptions?.value
159
+ // : [];
160
+ // return {
161
+ // shareableLinks: features.includes("shareableLinks"),
162
+ // emailInvitations: features.includes("emailInvitations"),
163
+ // shareOptionsCopyLink: shareOptions.includes("copyLink"),
164
+ // shareOptionsSms: shareOptions.includes("sms"),
165
+ // shareOptionsFacebook: shareOptions.includes("facebook"),
166
+ // shareOptionsFacebookMessenger: shareOptions.includes("facebookMessenger"),
167
+ // shareOptionsWhatsApp: shareOptions.includes("whatsApp"),
168
+ // shareOptionsQrCode: shareOptions.includes("qrCode"),
169
+ // shareOptionsNativeShareSheet: shareOptions.includes("nativeShareSheet"),
170
+ // };
171
+ // }, [widgetConfiguration_INTERNAL]);
172
+
173
+ // const shareOptions: {
174
+ // condition: boolean;
175
+ // // tooltip: string | JSX.Element;
176
+ // // icon: JSX.Element;
177
+ // // eslint-disable-next-line no-unused-vars
178
+ // // onClick: (e: any) => void;
179
+ // label: string;
180
+ // }[] = [
181
+ // {
182
+ // condition: has.shareOptionsCopyLink,
183
+ // // tooltip: showCopiedToClipboardTooltip
184
+ // // ? "Copied to clipboard!"
185
+ // // : "Copy to clipboard",
186
+ // // icon: <LinkIcon />,
187
+ // // onClick: handleCopyToClipboard,
188
+ // label: "Copy Link",
189
+ // },
190
+ // {
191
+ // condition: has.shareOptionsSms,
192
+ // // tooltip: "Share via SMS",
193
+ // // // icon: <SmsIcon />,
194
+ // // onClick: (e: any) => {
195
+ // // e.preventDefault();
196
+ // // window.open(`sms:?body=${globallyShareableLink}`, "_blank");
197
+ // // },
198
+ // label: "SMS",
199
+ // },
200
+ // {
201
+ // condition: has.shareOptionsFacebook,
202
+ // // tooltip: "Share on Facebook",
203
+ // // icon: <FacebookIcon />,
204
+ // // onClick: (e: any) => {
205
+ // // e.preventDefault();
206
+ // // window.open(
207
+ // // `https://www.facebook.com/sharer/sharer.php?u=${globallyShareableLink}`,
208
+ // // "_blank",
209
+ // // );
210
+ // // },
211
+ // label: "Facebook",
212
+ // },
213
+ // {
214
+ // condition: has.shareOptionsFacebookMessenger,
215
+ // // tooltip: "Share on Facebook Messenger",
216
+ // // icon: <FacebookIcon />,
217
+ // // onClick: (e: any) => {
218
+ // // e.preventDefault();
219
+ // // window.open(`https://m.me/?text=${globallyShareableLink}`, "_blank");
220
+ // // },
221
+ // label: "Messenger",
222
+ // },
223
+ // {
224
+ // condition: has.shareOptionsWhatsApp,
225
+ // // tooltip: "Share on WhatsApp",
226
+ // // icon: <WhatsAppIcon />,
227
+ // // onClick: (e: any) => {
228
+ // // e.preventDefault();
229
+ // // window.open(`https://wa.me/?text=${globallyShareableLink}`, "_blank");
230
+ // // },
231
+ // label: "WhatsApp",
232
+ // },
233
+ // {
234
+ // condition: has.shareOptionsQrCode,
235
+ // // tooltip: globallyShareableLink ? (
236
+ // // <QRCode value={globallyShareableLink} size={100} />
237
+ // // ) : (
238
+ // // "No shareable link"
239
+ // // ),
240
+ // // icon: <QrCodeIcon />,
241
+ // // onClick: (e: any) => {
242
+ // // e.preventDefault();
243
+ // // },
244
+ // label: "QR Code",
245
+ // },
246
+ // {
247
+ // condition: has.shareOptionsNativeShareSheet,
248
+ // // tooltip: "Share via native share",
249
+ // // icon: <PendingIcon />,
250
+ // // onClick: handleShareSheetClick,
251
+ // label: "Native Share",
252
+ // },
253
+ // ];
254
+
255
+ // const handleInviteClick = async () => {
256
+ // try {
257
+ // const response = await fetch(
258
+ // `${options.host}/api/v1/no-auth/components/widget-configuration/${options.widgetConfigurationId}/invite`,
259
+ // {
260
+ // method: "POST",
261
+ // headers: {
262
+ // "Content-Type": "application/json",
263
+ // },
264
+ // body: JSON.stringify({ to: [{ email }] }),
265
+ // },
266
+ // );
267
+ // const body = await response.json();
268
+ // console.log(body);
269
+ // Alert.alert(
270
+ // "Invitation Sent",
271
+ // "Your invitation has been successfully sent.",
272
+ // );
273
+ // } catch (error) {
274
+ // console.error(error);
275
+ // Alert.alert("Error", "Failed to send invitation.");
276
+ // }
277
+ // };
278
+
279
+ return (
280
+ <View>
281
+ <pre>Chupacabra</pre>
282
+ </View>
283
+ );
284
+ // if (error?.message) {
285
+ // return <pre data-testid="error">{error.message}</pre>;
286
+ // }
287
+
288
+ // if (fetching || loading) {
289
+ // return <Animated.View style={[styles.skeleton, { opacity }]} />;
290
+ // }
291
+
292
+ // return (
293
+ // <>
294
+ // <View style={[styles.container, options.widget?.style]}>
295
+ // {has?.emailInvitations && (
296
+ // <View style={styles.inviteContainer}>
297
+ // {options.emailIntroCopy?.value && (
298
+ // <Text style={styles.introText}>
299
+ // {options.emailIntroCopy?.value}
300
+ // </Text>
301
+ // )}
302
+ // <TextInput
303
+ // style={styles.input}
304
+ // placeholder="Enter email"
305
+ // value={email}
306
+ // onChangeText={setEmail}
307
+ // {...(options?.emailInput?.attributes || {})}
308
+ // />
309
+ // <View style={styles.buttonContainer}>
310
+ // <TouchableOpacity
311
+ // style={[styles.submitButton, options.submitButton?.style]}
312
+ // onPress={handleInviteClick}
313
+ // >
314
+ // <Text style={styles.submitButtonText}>
315
+ // {options.submitButton?.value || "Send invitation"}
316
+ // </Text>
317
+ // </TouchableOpacity>
318
+ // </View>
319
+ // </View>
320
+ // )}
321
+
322
+ // {has?.shareableLinks && (
323
+ // <View style={styles.shareContainer}>
324
+ // {has?.emailInvitations ? (
325
+ // options.shareableInviteText ? (
326
+ // <Text style={styles.divider}>
327
+ // {options.shareableInviteText?.value}
328
+ // </Text>
329
+ // ) : (
330
+ // <Text style={styles.divider}>OR</Text>
331
+ // )
332
+ // ) : options.hasAnyShareableLinks ? (
333
+ // <Text style={styles.divider}>OR</Text>
334
+ // ) : null}
335
+
336
+ // <View style={styles.shareButtonsContainer}>
337
+ // {shareOptions
338
+ // ?.filter((_) => !!_.condition)
339
+ // .map(({ label }, index, arr) => (
340
+ // <View
341
+ // key={index}
342
+ // style={
343
+ // arr.length % 2 !== 0 && index === arr.length - 1
344
+ // ? styles.centeredShareButton
345
+ // : styles.shareButtonWrapper
346
+ // }
347
+ // >
348
+ // <TouchableOpacity
349
+ // style={styles.shareButton}
350
+ // // onPress={onClick}
351
+ // >
352
+ // <Text style={styles.shareButtonText}>{label}</Text>
353
+ // </TouchableOpacity>
354
+ // </View>
355
+ // ))}
356
+ // </View>
357
+ // </View>
358
+ // )}
359
+ // </View>
360
+ // </>
361
+ // );
362
+ }
363
+
364
+ const styles = StyleSheet.create({
365
+ container: {
366
+ padding: 15,
367
+ display: "flex",
368
+ flexDirection: "column",
369
+ },
370
+ inviteContainer: {
371
+ display: "flex",
372
+ flexDirection: "column",
373
+ justifyContent: "center",
374
+ alignItems: "center",
375
+ marginTop: 8,
376
+ },
377
+ introText: {
378
+ marginBottom: 8,
379
+ fontSize: 24,
380
+ fontWeight: "bold",
381
+ textAlign: "center",
382
+ },
383
+ input: {
384
+ width: "100%",
385
+ borderWidth: 1,
386
+ borderColor: "#ccc",
387
+ padding: 10,
388
+ borderRadius: 5,
389
+ marginBottom: 8,
390
+ },
391
+ buttonContainer: {
392
+ marginTop: 16,
393
+ marginBottom: 8,
394
+ width: "100%",
395
+ },
396
+ submitButton: {
397
+ // backgroundColor: "#007bff",
398
+ padding: 12,
399
+ borderRadius: 5,
400
+ alignItems: "center",
401
+ shadowColor: "rgba(0, 0, 0, 0.2)",
402
+ shadowOffset: { width: 0, height: 2 },
403
+ shadowOpacity: 0.5,
404
+ shadowRadius: 2,
405
+ },
406
+ submitButtonText: {
407
+ color: "white",
408
+ fontWeight: "500",
409
+ textTransform: "none",
410
+ },
411
+ skeleton: {
412
+ width: "100%",
413
+ height: 50,
414
+ backgroundColor: "#e0e0e0",
415
+ borderRadius: 5,
416
+ },
417
+ shareContainer: {
418
+ marginTop: 16,
419
+ alignItems: "center",
420
+ },
421
+ divider: {
422
+ marginVertical: 10,
423
+ fontSize: 16,
424
+ fontWeight: "bold",
425
+ textAlign: "center",
426
+ },
427
+ shareButtonsContainer: {
428
+ flexDirection: "row",
429
+ flexWrap: "wrap",
430
+ justifyContent: "center",
431
+ },
432
+ shareButtonWrapper: {
433
+ width: "48%",
434
+ margin: 5,
435
+ },
436
+ centeredShareButton: {
437
+ width: "100%",
438
+ alignItems: "center",
439
+ },
440
+ shareButton: {
441
+ flexDirection: "row",
442
+ alignItems: "center",
443
+ padding: 10,
444
+ borderWidth: 1,
445
+ borderColor: "#007bff",
446
+ borderRadius: 5,
447
+ justifyContent: "center",
448
+ },
449
+ shareButtonText: {
450
+ paddingLeft: 10,
451
+ color: "#007bff",
452
+ },
453
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "@teamvortexsoftware/typescript-config/react-native-library",
3
+ "include": ["."],
4
+ "exclude": ["dist", "build", "node_modules"],
5
+ "compilerOptions": {
6
+ "strict": true
7
+ }
8
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { defineConfig, Options } from "tsup";
2
+
3
+ export default defineConfig((options: Options) => ({
4
+ entry: {
5
+ index: "src/index.tsx",
6
+ },
7
+ banner: {
8
+ js: "'use client'",
9
+ },
10
+ clean: true,
11
+ format: ["cjs", "esm"],
12
+ external: ["react"],
13
+ dts: true,
14
+ ...options,
15
+ }));