be-components 7.4.3 → 7.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/lib/commonjs/ApiOverrides/index.js +0 -2
  2. package/lib/commonjs/ApiOverrides/index.js.map +1 -1
  3. package/lib/commonjs/NotificationManager/api/index.js +448 -0
  4. package/lib/commonjs/NotificationManager/api/index.js.map +1 -0
  5. package/lib/commonjs/NotificationManager/index.js +1159 -0
  6. package/lib/commonjs/NotificationManager/index.js.map +1 -0
  7. package/lib/commonjs/index.js +20 -0
  8. package/lib/commonjs/index.js.map +1 -1
  9. package/lib/commonjs/types.d.js.map +1 -1
  10. package/lib/module/ApiOverrides/index.js +0 -2
  11. package/lib/module/ApiOverrides/index.js.map +1 -1
  12. package/lib/module/NotificationManager/api/index.js +441 -0
  13. package/lib/module/NotificationManager/api/index.js.map +1 -0
  14. package/lib/module/NotificationManager/index.js +1140 -0
  15. package/lib/module/NotificationManager/index.js.map +1 -0
  16. package/lib/module/index.js +3 -1
  17. package/lib/module/index.js.map +1 -1
  18. package/lib/module/types.d.js.map +1 -1
  19. package/lib/typescript/lib/commonjs/ApiOverrides/index.d.ts.map +1 -1
  20. package/lib/typescript/lib/commonjs/NotificationManager/api/index.d.ts +804 -0
  21. package/lib/typescript/lib/commonjs/NotificationManager/api/index.d.ts.map +1 -0
  22. package/lib/typescript/lib/commonjs/NotificationManager/index.d.ts +815 -0
  23. package/lib/typescript/lib/commonjs/NotificationManager/index.d.ts.map +1 -0
  24. package/lib/typescript/lib/commonjs/index.d.ts +803 -0
  25. package/lib/typescript/lib/commonjs/index.d.ts.map +1 -1
  26. package/lib/typescript/lib/module/ApiOverrides/index.d.ts.map +1 -1
  27. package/lib/typescript/lib/module/NotificationManager/api/index.d.ts +803 -0
  28. package/lib/typescript/lib/module/NotificationManager/api/index.d.ts.map +1 -0
  29. package/lib/typescript/lib/module/NotificationManager/index.d.ts +16 -0
  30. package/lib/typescript/lib/module/NotificationManager/index.d.ts.map +1 -0
  31. package/lib/typescript/lib/module/index.d.ts +4 -1
  32. package/lib/typescript/lib/module/index.d.ts.map +1 -1
  33. package/lib/typescript/src/ApiOverrides/index.d.ts.map +1 -1
  34. package/lib/typescript/src/NotificationManager/api/index.d.ts +822 -0
  35. package/lib/typescript/src/NotificationManager/api/index.d.ts.map +1 -0
  36. package/lib/typescript/src/NotificationManager/index.d.ts +17 -0
  37. package/lib/typescript/src/NotificationManager/index.d.ts.map +1 -0
  38. package/lib/typescript/src/index.d.ts +3 -1
  39. package/lib/typescript/src/index.d.ts.map +1 -1
  40. package/package.json +1 -1
  41. package/src/ApiOverrides/index.ts +0 -2
  42. package/src/NotificationManager/api/index.ts +134 -0
  43. package/src/NotificationManager/index.tsx +894 -0
  44. package/src/index.tsx +6 -1
  45. package/src/types.d.ts +70 -0
@@ -0,0 +1,1140 @@
1
+ import React, { useEffect, useState, useMemo } from 'react';
2
+ import { FlatList, TouchableOpacity, ActivityIndicator } from 'react-native';
3
+ import { View, Text, Button, TextInput } from '../Components/Themed';
4
+ import { useColors } from '../constants/useColors';
5
+ import { NotificationApi, NotificationHelpers } from './api';
6
+ import { Icons } from '../Components';
7
+ import DropDown from '../Components/Dropdown';
8
+ import { showConfirmAlert } from '../Components/ConfirmAlert';
9
+ const notification_types = [{
10
+ label: 'Order Notifications',
11
+ value: 'order_notifications'
12
+ }, {
13
+ label: 'Competition Notifications',
14
+ value: 'competition_notifications'
15
+ }, {
16
+ label: 'Social Notifications',
17
+ value: 'social_notifications'
18
+ }];
19
+ const sections = ['header', 'top_row', 'preview', 'second_row'];
20
+ const NotificationManager = ({
21
+ player_ids,
22
+ me,
23
+ notification_type,
24
+ default_path_name,
25
+ onFocusPosition,
26
+ default_params,
27
+ onComplete,
28
+ onClose
29
+ }) => {
30
+ const Colors = useColors();
31
+ const [loading, setLoading] = useState(false);
32
+ const [loadingGroups, setLoadingGroups] = useState(false);
33
+ const [notificationGroups, setNotificationGroups] = useState([]);
34
+ const [selectedGroup, setSelectedGroup] = useState(null);
35
+ const [showGroupsModal, setShowGroupsModal] = useState(false);
36
+ const [groupMemberIds, setGroupMemberIds] = useState([]);
37
+ const [showEditCustomGroupModal, setShowEditCustomGroupModal] = useState(false);
38
+ const [customGroupCsv, setCustomGroupCsv] = useState('');
39
+ const [sendingProgress, setSendingProgress] = useState(null);
40
+
41
+ // Create a custom group from initial player_ids
42
+ const customGroup = player_ids.length > 0 ? {
43
+ notification_group_id: 'custom_group',
44
+ name: 'Custom Recipients',
45
+ description: `${player_ids.length} selected recipients`,
46
+ status: 'active',
47
+ grouping_function: '',
48
+ player_count: player_ids.length,
49
+ create_datetime: new Date().toISOString(),
50
+ last_update_datetime: new Date().toISOString()
51
+ } : null;
52
+
53
+ // Initialize selectedPath based on default_path_name if provided
54
+ const initialPath = default_path_name ? NotificationHelpers.app_paths.find(p => p.path_name === default_path_name) || NotificationHelpers.app_paths[0] : NotificationHelpers.app_paths[0];
55
+ const [selectedPath, setSelectedPath] = useState(initialPath);
56
+ const [customPathName, setCustomPathName] = useState('');
57
+ const [pathParams, setPathParams] = useState(default_params || {});
58
+ const [pathSearch, setPathSearch] = useState('');
59
+ const [notification, setNotification] = useState({
60
+ type: notification_type || 'order_notifications',
61
+ notify_body_type: 'custom',
62
+ title: '',
63
+ body: '',
64
+ status: 'pending',
65
+ expire_time: Date.now() + 7 * 24 * 60 * 60 * 1000 // 7 days from now
66
+ });
67
+ useEffect(() => {
68
+ startUp();
69
+ // Auto-select custom group if initial player_ids provided
70
+ if (customGroup) {
71
+ setSelectedGroup(customGroup);
72
+ setGroupMemberIds(player_ids);
73
+ }
74
+ }, []);
75
+ useEffect(() => {
76
+ // Initialize pathParams when selectedPath changes, merging with default_params
77
+ const mergedParams = {
78
+ ...selectedPath?.params,
79
+ ...(default_params || {})
80
+ };
81
+ setPathParams(mergedParams);
82
+ }, [selectedPath]);
83
+ const startUp = () => {
84
+ NotificationApi.setEnvironment();
85
+ };
86
+ const loadNotificationGroups = async () => {
87
+ setLoadingGroups(true);
88
+ const groups = await NotificationApi.getActiveNotificationGroups();
89
+ setNotificationGroups(groups);
90
+ setLoadingGroups(false);
91
+ };
92
+ const handleSelectGroup = async group_id => {
93
+ setLoadingGroups(true);
94
+
95
+ // Check if it's the custom group
96
+ if (group_id === 'custom_group' && customGroup) {
97
+ setSelectedGroup(customGroup);
98
+ setGroupMemberIds(player_ids);
99
+ setLoadingGroups(false);
100
+ setShowGroupsModal(false);
101
+ return;
102
+ }
103
+ const group = notificationGroups.find(g => g.notification_group_id === group_id);
104
+ setSelectedGroup(group || null);
105
+
106
+ // Fetch all members for this group
107
+ const members = await NotificationApi.getNotificationGroupMembersByGroup(group_id);
108
+
109
+ // Flatten all player_ids arrays from all member objects
110
+ const memberPlayerIds = members.flatMap(m => m.player_ids);
111
+ setGroupMemberIds(memberPlayerIds);
112
+ setLoadingGroups(false);
113
+ setShowGroupsModal(false);
114
+ };
115
+ const handleRemoveGroup = () => {
116
+ setSelectedGroup(null);
117
+ setGroupMemberIds([]);
118
+ };
119
+ const handleOpenEditCustomGroup = () => {
120
+ // Populate CSV with current groupMemberIds
121
+ setCustomGroupCsv(groupMemberIds.join(','));
122
+ setShowEditCustomGroupModal(true);
123
+ };
124
+ const handleSaveCustomGroup = () => {
125
+ // Parse CSV and update groupMemberIds
126
+ const ids = customGroupCsv.split(',').map(id => id.trim()).filter(id => id.length > 0);
127
+ setGroupMemberIds(ids);
128
+
129
+ // Update the custom group description
130
+ if (customGroup && selectedGroup?.notification_group_id === 'custom_group') {
131
+ const updatedGroup = {
132
+ ...customGroup,
133
+ description: `${ids.length} selected recipients`,
134
+ player_count: ids.length
135
+ };
136
+ setSelectedGroup(updatedGroup);
137
+ }
138
+ setShowEditCustomGroupModal(false);
139
+ };
140
+
141
+ // Filter and sort paths: primary first (alphabetically), then others (alphabetically), limited by search
142
+ const filteredPaths = useMemo(() => {
143
+ let filtered = NotificationHelpers.app_paths;
144
+
145
+ // Apply search filter
146
+ if (pathSearch) {
147
+ filtered = filtered.filter(path => path.label.toLowerCase().includes(pathSearch.toLowerCase()) || path.path_name.toLowerCase().includes(pathSearch.toLowerCase()));
148
+ }
149
+
150
+ // Sort: primary paths first (alphabetically), then non-primary (alphabetically)
151
+ const sorted = [...filtered].sort((a, b) => {
152
+ if (a.primary && !b.primary) return -1;
153
+ if (!a.primary && b.primary) return 1;
154
+ return a.label.localeCompare(b.label);
155
+ });
156
+
157
+ // Limit to 15 results
158
+ return sorted.slice(0, 15);
159
+ }, [pathSearch]);
160
+ const isValid = () => {
161
+ const errors = [];
162
+ if (!notification.title || notification.title.trim() === '') {
163
+ errors.push('Notification title is required');
164
+ }
165
+ if (!notification.body || notification.body.trim() === '') {
166
+ errors.push('Notification body is required');
167
+ }
168
+ if (groupMemberIds.length === 0) {
169
+ errors.push('At least one recipient is required');
170
+ }
171
+
172
+ // Check required params
173
+ if (selectedPath?.requiredParams && selectedPath.requiredParams.length > 0) {
174
+ selectedPath.requiredParams.forEach(paramKey => {
175
+ if (!pathParams[paramKey] || pathParams[paramKey].trim() === '') {
176
+ errors.push(`Required parameter "${paramKey}" is missing`);
177
+ }
178
+ });
179
+ }
180
+
181
+ // Check custom path name
182
+ if (selectedPath?.path_name === 'custom' && (!customPathName || customPathName.trim() === '')) {
183
+ errors.push('Custom path name is required');
184
+ }
185
+ return errors;
186
+ };
187
+ const confirmSendNotification = options => {
188
+ const errors = isValid();
189
+ if (errors.length > 0) {
190
+ const errorMessage = 'Please fix the following errors:\n\n' + errors.map((err, idx) => `${idx + 1}. ${err}`).join('\n');
191
+ alert(errorMessage);
192
+ return;
193
+ }
194
+ showConfirmAlert('Are you sure?', options?.test ? 'This will send a test notification to you only' : 'This will send a notification to all users selected', () => handleSendNotification(options), () => console.log('Done'));
195
+ };
196
+ const handleSendNotification = async options => {
197
+ // Use only group member IDs (no individual player_ids)
198
+ let player_ids_to_send = [...groupMemberIds];
199
+ if (options?.test) {
200
+ //Change to the admin
201
+ player_ids_to_send = [me.player_id];
202
+ }
203
+ setLoading(true);
204
+ try {
205
+ // Determine final path_name
206
+ const finalPathName = selectedPath?.path_name === 'custom' ? customPathName : selectedPath?.path_name;
207
+
208
+ // Construct the complete notification object with all required fields
209
+ const completeNotification = {
210
+ player_notification_id: '',
211
+ // Will be generated by backend
212
+ player_id: me.player_id,
213
+ type: notification.type,
214
+ notify_body_type: notification.notify_body_type || 'custom',
215
+ title: notification.title,
216
+ body: notification.body,
217
+ options: {
218
+ id: Date.now().toString(),
219
+ body: notification.body,
220
+ icon: 'default',
221
+ type: notification.type || 'order_notifications',
222
+ data: {
223
+ id: Date.now().toString(),
224
+ player_id: me.player_id,
225
+ pageStack: 'MainStack',
226
+ page: 'Notifications',
227
+ pageParams: {},
228
+ url: notification.link_override,
229
+ path_name: finalPathName,
230
+ params: pathParams
231
+ }
232
+ },
233
+ status: 'unread',
234
+ link_override: notification.link_override,
235
+ expire_time: 0,
236
+ create_datetime: new Date().toISOString(),
237
+ last_update_datetime: new Date().toISOString()
238
+ };
239
+
240
+ // Split into batches of 500
241
+ const BATCH_SIZE = 500;
242
+ const batches = [];
243
+ for (let i = 0; i < player_ids_to_send.length; i += BATCH_SIZE) {
244
+ batches.push(player_ids_to_send.slice(i, i + BATCH_SIZE));
245
+ }
246
+
247
+ // Send notifications in batches
248
+ for (let i = 0; i < batches.length; i++) {
249
+ const batch = batches[i];
250
+ if (!batch) continue;
251
+ setSendingProgress({
252
+ current: i + 1,
253
+ total: batches.length
254
+ });
255
+ await NotificationApi.broadcastNotifications(completeNotification, batch);
256
+ }
257
+ setSendingProgress(null);
258
+ if (onComplete) {
259
+ onComplete(completeNotification);
260
+ }
261
+
262
+ // Only reset form if not a test send
263
+ if (!options?.test) {
264
+ setNotification({
265
+ type: 'order_notifications',
266
+ notify_body_type: 'custom',
267
+ title: '',
268
+ body: '',
269
+ status: 'pending',
270
+ expire_time: Date.now() + 7 * 24 * 60 * 60 * 1000
271
+ });
272
+ }
273
+ const recipientCount = options?.test ? 1 : groupMemberIds.length;
274
+ const recipientMessage = options?.test ? 'Test notification sent to you!' : `Notification sent successfully to ${recipientCount} user${recipientCount !== 1 ? 's' : ''}!`;
275
+ alert(recipientMessage);
276
+ } catch (error) {
277
+ console.error('Error sending notification:', error);
278
+ alert('Failed to send notification. Please try again.');
279
+ }
280
+ setLoading(false);
281
+ };
282
+ const renderSections = data => {
283
+ switch (data.item) {
284
+ case 'header':
285
+ const headerTotalRecipients = groupMemberIds.length;
286
+ return /*#__PURE__*/React.createElement(View, {
287
+ type: "header",
288
+ style: {
289
+ flexDirection: 'row',
290
+ alignItems: 'center',
291
+ padding: 10,
292
+ borderTopRightRadius: 8,
293
+ borderTopLeftRadius: 8
294
+ }
295
+ }, /*#__PURE__*/React.createElement(View, {
296
+ transparent: true,
297
+ style: {
298
+ flex: 1
299
+ }
300
+ }, /*#__PURE__*/React.createElement(Text, {
301
+ theme: "h1"
302
+ }, "Send Notification"), /*#__PURE__*/React.createElement(Text, {
303
+ theme: "description",
304
+ style: {
305
+ marginTop: 3
306
+ }
307
+ }, "Sending to ", headerTotalRecipients, " users")), onClose && /*#__PURE__*/React.createElement(Button, {
308
+ transparent: true,
309
+ onPress: onClose
310
+ }, /*#__PURE__*/React.createElement(Icons.CloseIcon, {
311
+ size: 16,
312
+ color: Colors.text.h1
313
+ })));
314
+ case 'preview':
315
+ return /*#__PURE__*/React.createElement(View, {
316
+ float: true,
317
+ style: {
318
+ margin: 5
319
+ }
320
+ }, /*#__PURE__*/React.createElement(View, {
321
+ type: "header",
322
+ style: {
323
+ flexDirection: 'row',
324
+ alignItems: 'center',
325
+ padding: 10,
326
+ borderTopRightRadius: 8,
327
+ borderTopLeftRadius: 8
328
+ }
329
+ }, /*#__PURE__*/React.createElement(View, {
330
+ transparent: true,
331
+ style: {
332
+ flex: 1
333
+ }
334
+ }, /*#__PURE__*/React.createElement(Text, {
335
+ theme: "h1"
336
+ }, "Preview"), /*#__PURE__*/React.createElement(Text, {
337
+ theme: "description",
338
+ style: {
339
+ marginTop: 3
340
+ }
341
+ }, "What will this notification look like?"))), /*#__PURE__*/React.createElement(View, {
342
+ float: true,
343
+ style: {
344
+ padding: 15,
345
+ margin: 10,
346
+ borderRadius: 8,
347
+ borderWidth: 1,
348
+ borderColor: Colors.borders.light
349
+ }
350
+ }, /*#__PURE__*/React.createElement(View, {
351
+ transparent: true,
352
+ style: {
353
+ flexDirection: 'row',
354
+ alignItems: 'center'
355
+ }
356
+ }, /*#__PURE__*/React.createElement(View, {
357
+ style: {
358
+ width: 40,
359
+ height: 40,
360
+ borderRadius: 8,
361
+ justifyContent: 'center',
362
+ alignItems: 'center',
363
+ marginRight: 12
364
+ }
365
+ }, /*#__PURE__*/React.createElement(Icons.NotificationIcon, {
366
+ size: 20,
367
+ color: Colors.text.h1
368
+ })), /*#__PURE__*/React.createElement(View, {
369
+ transparent: true,
370
+ style: {
371
+ flex: 1
372
+ }
373
+ }, /*#__PURE__*/React.createElement(Text, {
374
+ theme: "h1"
375
+ }, notification.title || 'Notification Title'), /*#__PURE__*/React.createElement(Text, {
376
+ theme: "description",
377
+ style: {
378
+ marginTop: 4
379
+ }
380
+ }, notification.body || 'Notification message will appear here')))));
381
+ case 'top_row':
382
+ const totalRecipients = groupMemberIds.length;
383
+ return /*#__PURE__*/React.createElement(View, {
384
+ style: {
385
+ flexDirection: 'row',
386
+ flexWrap: 'wrap'
387
+ }
388
+ }, /*#__PURE__*/React.createElement(View, {
389
+ float: true,
390
+ style: {
391
+ flexGrow: 1,
392
+ minWidth: 300,
393
+ padding: 10,
394
+ margin: 5
395
+ }
396
+ }, /*#__PURE__*/React.createElement(View, {
397
+ transparent: true,
398
+ style: {
399
+ flexDirection: 'row',
400
+ alignItems: 'center',
401
+ justifyContent: 'space-between',
402
+ marginBottom: 10
403
+ }
404
+ }, /*#__PURE__*/React.createElement(View, {
405
+ transparent: true,
406
+ style: {
407
+ flex: 1
408
+ }
409
+ }, /*#__PURE__*/React.createElement(Text, {
410
+ theme: "h2"
411
+ }, "Recipients (", totalRecipients, ")"), /*#__PURE__*/React.createElement(Text, {
412
+ theme: "description",
413
+ style: {
414
+ marginTop: 4
415
+ }
416
+ }, totalRecipients === 0 ? 'No recipients selected' : 'Selected group')), /*#__PURE__*/React.createElement(Button, {
417
+ type: "action",
418
+ onPress: () => {
419
+ loadNotificationGroups();
420
+ setShowGroupsModal(true);
421
+ },
422
+ style: {
423
+ padding: 8
424
+ }
425
+ }, /*#__PURE__*/React.createElement(Text, {
426
+ theme: "h1",
427
+ color: Colors.text.white
428
+ }, "Select Group"))), selectedGroup && /*#__PURE__*/React.createElement(View, {
429
+ float: true,
430
+ style: {
431
+ flexDirection: 'row',
432
+ alignItems: 'center',
433
+ justifyContent: 'space-between',
434
+ padding: 12,
435
+ borderRadius: 8,
436
+ marginTop: 5
437
+ }
438
+ }, /*#__PURE__*/React.createElement(View, {
439
+ transparent: true,
440
+ style: {
441
+ flex: 1
442
+ }
443
+ }, /*#__PURE__*/React.createElement(Text, {
444
+ theme: "h1"
445
+ }, selectedGroup.name), /*#__PURE__*/React.createElement(Text, {
446
+ theme: "description",
447
+ style: {
448
+ marginTop: 2
449
+ }
450
+ }, groupMemberIds.length, " members")), /*#__PURE__*/React.createElement(View, {
451
+ transparent: true,
452
+ style: {
453
+ flexDirection: 'row'
454
+ }
455
+ }, selectedGroup.notification_group_id === 'custom_group' && /*#__PURE__*/React.createElement(Button, {
456
+ type: "action",
457
+ onPress: handleOpenEditCustomGroup,
458
+ style: {
459
+ padding: 8,
460
+ marginRight: 8
461
+ }
462
+ }, /*#__PURE__*/React.createElement(Icons.EditIcon, {
463
+ size: 16,
464
+ color: Colors.text.white
465
+ })), /*#__PURE__*/React.createElement(Button, {
466
+ type: "error",
467
+ onPress: handleRemoveGroup,
468
+ style: {
469
+ padding: 8
470
+ }
471
+ }, /*#__PURE__*/React.createElement(Icons.CloseIcon, {
472
+ size: 16,
473
+ color: Colors.text.white
474
+ }))))));
475
+ case 'second_row':
476
+ return /*#__PURE__*/React.createElement(View, {
477
+ style: {
478
+ flexDirection: 'row',
479
+ flexWrap: 'wrap'
480
+ }
481
+ }, /*#__PURE__*/React.createElement(View, {
482
+ float: true,
483
+ style: {
484
+ minWidth: 300,
485
+ flexGrow: 1,
486
+ margin: 5
487
+ }
488
+ }, /*#__PURE__*/React.createElement(View, {
489
+ type: "header",
490
+ style: {
491
+ flexDirection: 'row',
492
+ alignItems: 'center',
493
+ padding: 10,
494
+ borderTopRightRadius: 8,
495
+ borderTopLeftRadius: 8
496
+ }
497
+ }, /*#__PURE__*/React.createElement(View, {
498
+ transparent: true,
499
+ style: {
500
+ flex: 1
501
+ }
502
+ }, /*#__PURE__*/React.createElement(Text, {
503
+ theme: "h1"
504
+ }, "Notification Message"), /*#__PURE__*/React.createElement(Text, {
505
+ theme: "description",
506
+ style: {
507
+ marginTop: 3
508
+ }
509
+ }, "Update notification message below"))), /*#__PURE__*/React.createElement(View, {
510
+ transparent: true,
511
+ type: "body"
512
+ }, /*#__PURE__*/React.createElement(View, {
513
+ transparent: true,
514
+ style: {
515
+ padding: 10
516
+ }
517
+ }, /*#__PURE__*/React.createElement(Text, {
518
+ theme: "h2",
519
+ style: {
520
+ marginBottom: 10
521
+ }
522
+ }, "Notification Title"), /*#__PURE__*/React.createElement(TextInput, {
523
+ value: notification.title,
524
+ onFocusPosition: onFocusPosition,
525
+ placeholder: "Enter notification title",
526
+ onChangeText: title => setNotification({
527
+ ...notification,
528
+ title
529
+ })
530
+ })), /*#__PURE__*/React.createElement(View, {
531
+ transparent: true,
532
+ style: {
533
+ padding: 10
534
+ }
535
+ }, /*#__PURE__*/React.createElement(Text, {
536
+ theme: "h2",
537
+ style: {
538
+ marginBottom: 10
539
+ }
540
+ }, "Notification Body"), /*#__PURE__*/React.createElement(TextInput, {
541
+ value: notification.body,
542
+ onFocusPosition: onFocusPosition,
543
+ placeholder: "Enter notification message",
544
+ onChangeText: body => setNotification({
545
+ ...notification,
546
+ body
547
+ }),
548
+ multiline: true,
549
+ numberOfLines: 6,
550
+ style: {
551
+ padding: 12,
552
+ borderRadius: 8,
553
+ minHeight: 120
554
+ }
555
+ })))), /*#__PURE__*/React.createElement(View, {
556
+ float: true,
557
+ style: {
558
+ flexGrow: 1,
559
+ minWidth: 300,
560
+ margin: 5
561
+ }
562
+ }, /*#__PURE__*/React.createElement(View, {
563
+ type: "header",
564
+ style: {
565
+ flexDirection: 'row',
566
+ alignItems: 'center',
567
+ padding: 10,
568
+ borderTopRightRadius: 8,
569
+ borderTopLeftRadius: 8
570
+ }
571
+ }, /*#__PURE__*/React.createElement(View, {
572
+ transparent: true,
573
+ style: {
574
+ flex: 1
575
+ }
576
+ }, /*#__PURE__*/React.createElement(Text, {
577
+ theme: "h1"
578
+ }, "Notification Settings"), /*#__PURE__*/React.createElement(Text, {
579
+ theme: "description",
580
+ style: {
581
+ marginTop: 3
582
+ }
583
+ }, "Manage settigns below"))), /*#__PURE__*/React.createElement(View, {
584
+ transparent: true,
585
+ type: "body"
586
+ }, /*#__PURE__*/React.createElement(View, {
587
+ type: "row",
588
+ style: {
589
+ padding: 10
590
+ }
591
+ }, /*#__PURE__*/React.createElement(Text, {
592
+ theme: "h2",
593
+ style: {
594
+ flex: 1
595
+ }
596
+ }, "Notification Type"), /*#__PURE__*/React.createElement(DropDown, {
597
+ selected_value: notification_types.find(t => t.value === notification.type)?.label ?? '',
598
+ dropdown_options: [{
599
+ value: 'type',
600
+ eligible_options: notification_types.map(t => t.label)
601
+ }],
602
+ onOptionSelect: selected => {
603
+ const type = notification_types.find(t => t.label === selected)?.value;
604
+ setNotification({
605
+ ...notification,
606
+ type: type
607
+ });
608
+ }
609
+ })), /*#__PURE__*/React.createElement(View, {
610
+ transparent: true,
611
+ style: {
612
+ padding: 10
613
+ }
614
+ }, /*#__PURE__*/React.createElement(Text, {
615
+ theme: "h2",
616
+ style: {
617
+ marginBottom: 10
618
+ }
619
+ }, "Link Override (Optional)"), /*#__PURE__*/React.createElement(TextInput, {
620
+ value: notification.link_override || '',
621
+ onFocusPosition: onFocusPosition,
622
+ placeholder: "https://example.com",
623
+ onChangeText: link_override => setNotification({
624
+ ...notification,
625
+ link_override
626
+ }),
627
+ style: {
628
+ padding: 12,
629
+ borderRadius: 8
630
+ }
631
+ })), /*#__PURE__*/React.createElement(View, {
632
+ transparent: true,
633
+ style: {
634
+ padding: 10
635
+ }
636
+ }, /*#__PURE__*/React.createElement(Text, {
637
+ theme: "h2",
638
+ style: {
639
+ marginBottom: 10
640
+ }
641
+ }, "Deep Link Path"), /*#__PURE__*/React.createElement(View, {
642
+ type: "header",
643
+ style: {
644
+ padding: 12,
645
+ borderRadius: 8,
646
+ marginBottom: 8,
647
+ flexDirection: 'row',
648
+ alignItems: 'center',
649
+ justifyContent: 'space-between'
650
+ }
651
+ }, /*#__PURE__*/React.createElement(View, {
652
+ transparent: true,
653
+ style: {
654
+ flex: 1
655
+ }
656
+ }, /*#__PURE__*/React.createElement(Text, {
657
+ theme: "h1",
658
+ style: {
659
+ marginBottom: 2
660
+ }
661
+ }, selectedPath?.label), /*#__PURE__*/React.createElement(Text, {
662
+ theme: "description",
663
+ style: {
664
+ fontSize: 12
665
+ }
666
+ }, selectedPath?.path_name)), selectedPath?.primary && /*#__PURE__*/React.createElement(View, {
667
+ transparent: true,
668
+ style: {
669
+ paddingHorizontal: 8,
670
+ paddingVertical: 4,
671
+ borderRadius: 4
672
+ }
673
+ }, /*#__PURE__*/React.createElement(Text, {
674
+ theme: "description",
675
+ color: Colors.text.white,
676
+ style: {
677
+ fontSize: 10
678
+ }
679
+ }, "Primary"))), /*#__PURE__*/React.createElement(TextInput, {
680
+ value: pathSearch,
681
+ placeholder: "Search paths to change...",
682
+ onFocusPosition: onFocusPosition,
683
+ onChangeText: setPathSearch,
684
+ style: {
685
+ padding: 12,
686
+ borderRadius: 8,
687
+ marginBottom: 8
688
+ }
689
+ }), pathSearch && /*#__PURE__*/React.createElement(View, {
690
+ float: true,
691
+ style: {
692
+ maxHeight: 300,
693
+ borderRadius: 8,
694
+ borderWidth: 1,
695
+ borderColor: Colors.borders.light
696
+ }
697
+ }, /*#__PURE__*/React.createElement(FlatList, {
698
+ data: filteredPaths,
699
+ keyExtractor: item => item.path_name,
700
+ renderItem: ({
701
+ item
702
+ }) => /*#__PURE__*/React.createElement(TouchableOpacity, {
703
+ onPress: () => {
704
+ setSelectedPath(item);
705
+ setPathSearch('');
706
+ },
707
+ style: {
708
+ padding: 12,
709
+ borderBottomWidth: 1,
710
+ borderColor: Colors.borders.light
711
+ }
712
+ }, /*#__PURE__*/React.createElement(View, {
713
+ transparent: true,
714
+ style: {
715
+ flexDirection: 'row',
716
+ alignItems: 'center',
717
+ justifyContent: 'space-between'
718
+ }
719
+ }, /*#__PURE__*/React.createElement(View, {
720
+ transparent: true,
721
+ style: {
722
+ flex: 1
723
+ }
724
+ }, /*#__PURE__*/React.createElement(Text, {
725
+ theme: "h2",
726
+ style: {
727
+ marginBottom: 2
728
+ }
729
+ }, item.label), /*#__PURE__*/React.createElement(Text, {
730
+ theme: "description",
731
+ style: {
732
+ fontSize: 11
733
+ }
734
+ }, item.path_name)), item.primary && /*#__PURE__*/React.createElement(View, {
735
+ transparent: true,
736
+ style: {
737
+ paddingHorizontal: 6,
738
+ paddingVertical: 2,
739
+ borderRadius: 4,
740
+ marginLeft: 8
741
+ }
742
+ }, /*#__PURE__*/React.createElement(Text, {
743
+ theme: "description",
744
+ color: Colors.text.white,
745
+ style: {
746
+ fontSize: 9
747
+ }
748
+ }, "Primary")))),
749
+ ListEmptyComponent: /*#__PURE__*/React.createElement(View, {
750
+ style: {
751
+ padding: 20,
752
+ alignItems: 'center'
753
+ }
754
+ }, /*#__PURE__*/React.createElement(Text, {
755
+ theme: "description"
756
+ }, "No paths found"))
757
+ }))), Object.keys(selectedPath?.params ?? {}).length > 0 && /*#__PURE__*/React.createElement(View, {
758
+ style: {
759
+ padding: 10
760
+ }
761
+ }, /*#__PURE__*/React.createElement(Text, {
762
+ theme: "h2",
763
+ style: {
764
+ marginBottom: 8
765
+ }
766
+ }, "Path Parameters"), /*#__PURE__*/React.createElement(View, {
767
+ type: "header",
768
+ style: {
769
+ padding: 12,
770
+ borderRadius: 8
771
+ }
772
+ }, Object.keys(selectedPath?.params ?? {}).map(paramKey => {
773
+ const isRequired = selectedPath?.requiredParams.includes(paramKey);
774
+ return /*#__PURE__*/React.createElement(View, {
775
+ key: paramKey,
776
+ transparent: true,
777
+ style: {
778
+ marginBottom: 12
779
+ }
780
+ }, /*#__PURE__*/React.createElement(View, {
781
+ transparent: true,
782
+ style: {
783
+ flexDirection: 'row',
784
+ alignItems: 'center',
785
+ marginBottom: 4
786
+ }
787
+ }, /*#__PURE__*/React.createElement(Text, {
788
+ theme: "description"
789
+ }, paramKey), isRequired ? /*#__PURE__*/React.createElement(View, {
790
+ transparent: true,
791
+ style: {
792
+ marginLeft: 4,
793
+ paddingHorizontal: 6,
794
+ paddingVertical: 2,
795
+ backgroundColor: Colors.text.error,
796
+ borderRadius: 4
797
+ }
798
+ }, /*#__PURE__*/React.createElement(Text, {
799
+ theme: "description",
800
+ color: Colors.text.white,
801
+ style: {
802
+ fontSize: 10
803
+ }
804
+ }, "Required")) : /*#__PURE__*/React.createElement(View, {
805
+ transparent: true,
806
+ style: {
807
+ marginLeft: 4,
808
+ paddingHorizontal: 6,
809
+ paddingVertical: 2,
810
+ backgroundColor: Colors.borders.light,
811
+ borderRadius: 4
812
+ }
813
+ }, /*#__PURE__*/React.createElement(Text, {
814
+ theme: "description",
815
+ style: {
816
+ fontSize: 10
817
+ }
818
+ }, "Optional"))), /*#__PURE__*/React.createElement(TextInput, {
819
+ value: pathParams[paramKey] || '',
820
+ onFocusPosition: onFocusPosition,
821
+ placeholder: `Enter ${paramKey}${isRequired ? ' (required)' : ' (optional)'}`,
822
+ onChangeText: value => setPathParams({
823
+ ...pathParams,
824
+ [paramKey]: value
825
+ }),
826
+ style: {
827
+ padding: 10,
828
+ borderRadius: 8,
829
+ borderWidth: isRequired ? 2 : 1,
830
+ borderColor: isRequired && !pathParams[paramKey] ? Colors.text.error : Colors.borders.light
831
+ }
832
+ }));
833
+ })))), selectedPath?.path_name === 'custom' && /*#__PURE__*/React.createElement(View, {
834
+ style: {
835
+ marginBottom: 20
836
+ }
837
+ }, /*#__PURE__*/React.createElement(Text, {
838
+ theme: "h2",
839
+ style: {
840
+ marginBottom: 8
841
+ }
842
+ }, "Custom Path Name"), /*#__PURE__*/React.createElement(TextInput, {
843
+ value: customPathName,
844
+ onFocusPosition: onFocusPosition,
845
+ placeholder: "/your/custom/path",
846
+ onChangeText: setCustomPathName,
847
+ style: {
848
+ padding: 12,
849
+ borderRadius: 8
850
+ }
851
+ }))));
852
+ default:
853
+ return /*#__PURE__*/React.createElement(React.Fragment, null);
854
+ }
855
+ };
856
+ return /*#__PURE__*/React.createElement(View, {
857
+ style: {
858
+ flex: 1
859
+ }
860
+ }, /*#__PURE__*/React.createElement(View, {
861
+ transparent: true,
862
+ style: {
863
+ flex: 1
864
+ }
865
+ }, /*#__PURE__*/React.createElement(FlatList, {
866
+ data: sections,
867
+ keyExtractor: item => item,
868
+ key: 'notification_manager_list',
869
+ renderItem: renderSections
870
+ })), /*#__PURE__*/React.createElement(View, {
871
+ type: "footer",
872
+ style: {
873
+ flexDirection: 'row',
874
+ alignItems: 'center',
875
+ padding: 10,
876
+ borderBottomRightRadius: 8,
877
+ borderBottomLeftRadius: 8
878
+ }
879
+ }, /*#__PURE__*/React.createElement(Button, {
880
+ type: "action",
881
+ disabled: loading,
882
+ loading: loading,
883
+ onPress: () => confirmSendNotification({
884
+ test: true
885
+ }),
886
+ style: {
887
+ flex: 1,
888
+ opacity: loading || isValid().length > 0 ? 0.5 : 1
889
+ }
890
+ }, /*#__PURE__*/React.createElement(Text, {
891
+ textAlign: "center",
892
+ theme: "h1",
893
+ color: Colors.text.white
894
+ }, loading ? sendingProgress ? `Sending ${sendingProgress.current}/${sendingProgress.total}` : 'Sending...' : 'Send Test')), /*#__PURE__*/React.createElement(Button, {
895
+ type: "success",
896
+ disabled: loading,
897
+ loading: loading,
898
+ onPress: () => confirmSendNotification(),
899
+ style: {
900
+ flex: 2,
901
+ marginLeft: 5,
902
+ opacity: loading || isValid().length > 0 ? 0.5 : 1
903
+ }
904
+ }, /*#__PURE__*/React.createElement(Text, {
905
+ textAlign: "center",
906
+ theme: "h1",
907
+ color: Colors.text.white
908
+ }, loading ? sendingProgress ? `Sending batch ${sendingProgress.current} of ${sendingProgress.total}` : 'Sending...' : 'Send Notification'))), showGroupsModal && /*#__PURE__*/React.createElement(View, {
909
+ type: "blur",
910
+ style: {
911
+ position: 'absolute',
912
+ top: 0,
913
+ left: 0,
914
+ right: 0,
915
+ bottom: 0,
916
+ padding: 20
917
+ }
918
+ }, /*#__PURE__*/React.createElement(View, {
919
+ float: true,
920
+ style: {
921
+ flex: 1
922
+ }
923
+ }, /*#__PURE__*/React.createElement(View, {
924
+ type: "header",
925
+ style: {
926
+ flexDirection: 'row',
927
+ alignItems: 'center',
928
+ padding: 10,
929
+ borderTopRightRadius: 8,
930
+ borderTopLeftRadius: 8
931
+ }
932
+ }, /*#__PURE__*/React.createElement(View, {
933
+ transparent: true,
934
+ style: {
935
+ flex: 1
936
+ }
937
+ }, /*#__PURE__*/React.createElement(Text, {
938
+ theme: "h1"
939
+ }, "Notification Groups"), /*#__PURE__*/React.createElement(Text, {
940
+ theme: "description",
941
+ style: {
942
+ marginTop: 3
943
+ }
944
+ }, "Select a group to send to"))), /*#__PURE__*/React.createElement(View, {
945
+ style: {
946
+ flex: 1
947
+ }
948
+ }, loadingGroups ? /*#__PURE__*/React.createElement(View, {
949
+ style: {
950
+ padding: 40,
951
+ alignItems: 'center'
952
+ }
953
+ }, /*#__PURE__*/React.createElement(ActivityIndicator, {
954
+ size: "large",
955
+ color: Colors.text.action
956
+ })) : /*#__PURE__*/React.createElement(FlatList, {
957
+ data: customGroup ? [customGroup, ...notificationGroups] : notificationGroups,
958
+ keyExtractor: item => item.notification_group_id,
959
+ renderItem: ({
960
+ item
961
+ }) => /*#__PURE__*/React.createElement(TouchableOpacity, {
962
+ onPress: () => handleSelectGroup(item.notification_group_id),
963
+ style: {
964
+ padding: 15,
965
+ borderBottomWidth: 1,
966
+ borderColor: Colors.borders.light,
967
+ backgroundColor: item.notification_group_id === 'custom_group' ? Colors.views.header : 'transparent'
968
+ }
969
+ }, /*#__PURE__*/React.createElement(View, {
970
+ transparent: true
971
+ }, /*#__PURE__*/React.createElement(View, {
972
+ transparent: true,
973
+ style: {
974
+ flexDirection: 'row',
975
+ alignItems: 'center',
976
+ justifyContent: 'space-between'
977
+ }
978
+ }, /*#__PURE__*/React.createElement(View, {
979
+ transparent: true,
980
+ style: {
981
+ flexDirection: 'row',
982
+ alignItems: 'center',
983
+ flex: 1
984
+ }
985
+ }, /*#__PURE__*/React.createElement(Text, {
986
+ theme: "h1"
987
+ }, item.name), item.notification_group_id === 'custom_group' && /*#__PURE__*/React.createElement(View, {
988
+ transparent: true,
989
+ style: {
990
+ marginLeft: 8,
991
+ paddingHorizontal: 6,
992
+ paddingVertical: 2,
993
+ backgroundColor: Colors.buttons.background.action,
994
+ borderRadius: 4
995
+ }
996
+ }, /*#__PURE__*/React.createElement(Text, {
997
+ theme: "description",
998
+ color: Colors.text.white,
999
+ style: {
1000
+ fontSize: 10
1001
+ }
1002
+ }, "CUSTOM"))), item.player_count !== undefined && /*#__PURE__*/React.createElement(View, {
1003
+ transparent: true,
1004
+ style: {
1005
+ marginLeft: 8,
1006
+ paddingHorizontal: 8,
1007
+ paddingVertical: 4,
1008
+ backgroundColor: Colors.views.header,
1009
+ borderRadius: 4
1010
+ }
1011
+ }, /*#__PURE__*/React.createElement(Text, {
1012
+ theme: "description",
1013
+ style: {
1014
+ fontSize: 12,
1015
+ fontWeight: '600'
1016
+ }
1017
+ }, item.player_count.toLocaleString(), " users"))), item.description && /*#__PURE__*/React.createElement(Text, {
1018
+ theme: "description",
1019
+ style: {
1020
+ marginTop: 4
1021
+ }
1022
+ }, item.description))),
1023
+ ListEmptyComponent: /*#__PURE__*/React.createElement(View, {
1024
+ style: {
1025
+ padding: 40,
1026
+ alignItems: 'center'
1027
+ }
1028
+ }, /*#__PURE__*/React.createElement(Text, {
1029
+ theme: "description"
1030
+ }, "No groups found"))
1031
+ })), /*#__PURE__*/React.createElement(View, {
1032
+ type: "footer",
1033
+ style: {
1034
+ flexDirection: 'row',
1035
+ alignItems: 'center',
1036
+ padding: 10,
1037
+ borderBottomRightRadius: 8,
1038
+ borderBottomLeftRadius: 8
1039
+ }
1040
+ }, /*#__PURE__*/React.createElement(Button, {
1041
+ style: {
1042
+ flex: 1
1043
+ },
1044
+ type: "close",
1045
+ title: "CLOSE",
1046
+ onPress: () => setShowGroupsModal(false)
1047
+ })))), showEditCustomGroupModal && /*#__PURE__*/React.createElement(View, {
1048
+ type: "blur",
1049
+ style: {
1050
+ position: 'absolute',
1051
+ top: 0,
1052
+ left: 0,
1053
+ right: 0,
1054
+ bottom: 0,
1055
+ padding: 20
1056
+ }
1057
+ }, /*#__PURE__*/React.createElement(View, {
1058
+ float: true,
1059
+ style: {
1060
+ maxHeight: '80%',
1061
+ minHeight: 400
1062
+ }
1063
+ }, /*#__PURE__*/React.createElement(View, {
1064
+ type: "header",
1065
+ style: {
1066
+ flexDirection: 'row',
1067
+ alignItems: 'center',
1068
+ padding: 10,
1069
+ borderTopRightRadius: 8,
1070
+ borderTopLeftRadius: 8
1071
+ }
1072
+ }, /*#__PURE__*/React.createElement(View, {
1073
+ transparent: true,
1074
+ style: {
1075
+ flex: 1
1076
+ }
1077
+ }, /*#__PURE__*/React.createElement(Text, {
1078
+ theme: "h1"
1079
+ }, "Edit Custom Recipients"), /*#__PURE__*/React.createElement(Text, {
1080
+ theme: "description",
1081
+ style: {
1082
+ marginTop: 3
1083
+ }
1084
+ }, "Paste comma-separated player IDs"))), /*#__PURE__*/React.createElement(View, {
1085
+ style: {
1086
+ flex: 1,
1087
+ padding: 15
1088
+ }
1089
+ }, /*#__PURE__*/React.createElement(Text, {
1090
+ theme: "h2",
1091
+ style: {
1092
+ marginBottom: 10
1093
+ }
1094
+ }, "Player IDs (CSV format)"), /*#__PURE__*/React.createElement(TextInput, {
1095
+ value: customGroupCsv,
1096
+ onFocusPosition: onFocusPosition,
1097
+ placeholder: "98,100,2485,etc",
1098
+ onChangeText: setCustomGroupCsv,
1099
+ multiline: true,
1100
+ numberOfLines: 10,
1101
+ style: {
1102
+ padding: 12,
1103
+ borderRadius: 8,
1104
+ minHeight: 200,
1105
+ textAlignVertical: 'top'
1106
+ }
1107
+ }), /*#__PURE__*/React.createElement(Text, {
1108
+ theme: "description",
1109
+ style: {
1110
+ marginTop: 8
1111
+ }
1112
+ }, "Current count: ", customGroupCsv.split(',').filter(id => id.trim().length > 0).length, " IDs")), /*#__PURE__*/React.createElement(View, {
1113
+ type: "footer",
1114
+ style: {
1115
+ flexDirection: 'row',
1116
+ alignItems: 'center',
1117
+ padding: 10,
1118
+ borderBottomRightRadius: 8,
1119
+ borderBottomLeftRadius: 8
1120
+ }
1121
+ }, /*#__PURE__*/React.createElement(Button, {
1122
+ style: {
1123
+ flex: 1,
1124
+ marginRight: 5
1125
+ },
1126
+ type: "close",
1127
+ title: "CANCEL",
1128
+ onPress: () => setShowEditCustomGroupModal(false)
1129
+ }), /*#__PURE__*/React.createElement(Button, {
1130
+ style: {
1131
+ flex: 1
1132
+ },
1133
+ type: "success",
1134
+ title: "SAVE",
1135
+ onPress: handleSaveCustomGroup
1136
+ })))));
1137
+ };
1138
+ export default NotificationManager;
1139
+ export { NotificationApi, NotificationHelpers };
1140
+ //# sourceMappingURL=index.js.map