be-components 7.5.6 → 7.5.7

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 (142) hide show
  1. package/lib/commonjs/AdServer/api/index.js +4 -2
  2. package/lib/commonjs/AdServer/api/index.js.map +1 -1
  3. package/lib/commonjs/AdServer/index.js +26 -13
  4. package/lib/commonjs/AdServer/index.js.map +1 -1
  5. package/lib/commonjs/ApiOverrides/index.js +3 -2
  6. package/lib/commonjs/ApiOverrides/index.js.map +1 -1
  7. package/lib/commonjs/BetRouter/api/index.js +69 -0
  8. package/lib/commonjs/BetRouter/api/index.js.map +1 -1
  9. package/lib/commonjs/BetRouter/components/ContestLiquidity.js +72 -11
  10. package/lib/commonjs/BetRouter/components/ContestLiquidity.js.map +1 -1
  11. package/lib/commonjs/BetRouter/components/admin/LeagueInfo.js +233 -2
  12. package/lib/commonjs/BetRouter/components/admin/LeagueInfo.js.map +1 -1
  13. package/lib/commonjs/BetRouter/components/admin/RouterMarkets.js +1555 -0
  14. package/lib/commonjs/BetRouter/components/admin/RouterMarkets.js.map +1 -0
  15. package/lib/commonjs/BetRouter/layouts/DesktopAdminLayout.js +16 -3
  16. package/lib/commonjs/BetRouter/layouts/DesktopAdminLayout.js.map +1 -1
  17. package/lib/commonjs/BetRouter/layouts/MobileAdminLayout.js +31 -2
  18. package/lib/commonjs/BetRouter/layouts/MobileAdminLayout.js.map +1 -1
  19. package/lib/commonjs/BetRouter/types/api-contracts.js +77 -0
  20. package/lib/commonjs/BetRouter/types/api-contracts.js.map +1 -1
  21. package/lib/commonjs/BetRouter/types/credentials.js +4 -0
  22. package/lib/commonjs/BetRouter/types/credentials.js.map +1 -1
  23. package/lib/commonjs/Components/ViewportObserver.js +9 -0
  24. package/lib/commonjs/Components/ViewportObserver.js.map +1 -1
  25. package/lib/commonjs/ProfileManager/Components/DOBManager.js +38 -2
  26. package/lib/commonjs/ProfileManager/Components/DOBManager.js.map +1 -1
  27. package/lib/commonjs/ProfileManager/Components/EmailManager.js +40 -2
  28. package/lib/commonjs/ProfileManager/Components/EmailManager.js.map +1 -1
  29. package/lib/commonjs/ProfileManager/Components/PhoneManager.js +38 -1
  30. package/lib/commonjs/ProfileManager/Components/PhoneManager.js.map +1 -1
  31. package/lib/commonjs/ProfileManager/Components/VouchCard.js +13 -3
  32. package/lib/commonjs/ProfileManager/Components/VouchCard.js.map +1 -1
  33. package/lib/module/AdServer/api/index.js +4 -2
  34. package/lib/module/AdServer/api/index.js.map +1 -1
  35. package/lib/module/AdServer/index.js +25 -12
  36. package/lib/module/AdServer/index.js.map +1 -1
  37. package/lib/module/ApiOverrides/index.js +3 -2
  38. package/lib/module/ApiOverrides/index.js.map +1 -1
  39. package/lib/module/BetRouter/api/index.js +69 -0
  40. package/lib/module/BetRouter/api/index.js.map +1 -1
  41. package/lib/module/BetRouter/components/ContestLiquidity.js +72 -11
  42. package/lib/module/BetRouter/components/ContestLiquidity.js.map +1 -1
  43. package/lib/module/BetRouter/components/admin/LeagueInfo.js +233 -3
  44. package/lib/module/BetRouter/components/admin/LeagueInfo.js.map +1 -1
  45. package/lib/module/BetRouter/components/admin/RouterMarkets.js +1548 -0
  46. package/lib/module/BetRouter/components/admin/RouterMarkets.js.map +1 -0
  47. package/lib/module/BetRouter/layouts/DesktopAdminLayout.js +16 -3
  48. package/lib/module/BetRouter/layouts/DesktopAdminLayout.js.map +1 -1
  49. package/lib/module/BetRouter/layouts/MobileAdminLayout.js +31 -2
  50. package/lib/module/BetRouter/layouts/MobileAdminLayout.js.map +1 -1
  51. package/lib/module/BetRouter/types/api-contracts.js +77 -0
  52. package/lib/module/BetRouter/types/api-contracts.js.map +1 -1
  53. package/lib/module/BetRouter/types/credentials.js +4 -0
  54. package/lib/module/BetRouter/types/credentials.js.map +1 -1
  55. package/lib/module/Components/ViewportObserver.js +9 -0
  56. package/lib/module/Components/ViewportObserver.js.map +1 -1
  57. package/lib/module/ProfileManager/Components/DOBManager.js +38 -2
  58. package/lib/module/ProfileManager/Components/DOBManager.js.map +1 -1
  59. package/lib/module/ProfileManager/Components/EmailManager.js +40 -2
  60. package/lib/module/ProfileManager/Components/EmailManager.js.map +1 -1
  61. package/lib/module/ProfileManager/Components/PhoneManager.js +38 -1
  62. package/lib/module/ProfileManager/Components/PhoneManager.js.map +1 -1
  63. package/lib/module/ProfileManager/Components/VouchCard.js +13 -3
  64. package/lib/module/ProfileManager/Components/VouchCard.js.map +1 -1
  65. package/lib/typescript/lib/commonjs/AdServer/api/index.d.ts.map +1 -1
  66. package/lib/typescript/lib/commonjs/AdServer/index.d.ts +1 -0
  67. package/lib/typescript/lib/commonjs/AdServer/index.d.ts.map +1 -1
  68. package/lib/typescript/lib/commonjs/ApiOverrides/index.d.ts.map +1 -1
  69. package/lib/typescript/lib/commonjs/BetRouter/api/index.d.ts +6 -0
  70. package/lib/typescript/lib/commonjs/BetRouter/api/index.d.ts.map +1 -1
  71. package/lib/typescript/lib/commonjs/BetRouter/components/ContestLiquidity.d.ts.map +1 -1
  72. package/lib/typescript/lib/commonjs/BetRouter/components/admin/LeagueInfo.d.ts.map +1 -1
  73. package/lib/typescript/lib/commonjs/BetRouter/components/admin/RouterMarkets.d.ts +4 -0
  74. package/lib/typescript/lib/commonjs/BetRouter/components/admin/RouterMarkets.d.ts.map +1 -0
  75. package/lib/typescript/lib/commonjs/BetRouter/layouts/DesktopAdminLayout.d.ts.map +1 -1
  76. package/lib/typescript/lib/commonjs/BetRouter/layouts/MobileAdminLayout.d.ts.map +1 -1
  77. package/lib/typescript/lib/commonjs/BetRouter/types/api-contracts.d.ts +77 -0
  78. package/lib/typescript/lib/commonjs/BetRouter/types/credentials.d.ts.map +1 -1
  79. package/lib/typescript/lib/commonjs/Components/ViewportObserver.d.ts.map +1 -1
  80. package/lib/typescript/lib/commonjs/ProfileManager/Components/DOBManager.d.ts.map +1 -1
  81. package/lib/typescript/lib/commonjs/ProfileManager/Components/EmailManager.d.ts.map +1 -1
  82. package/lib/typescript/lib/commonjs/ProfileManager/Components/PhoneManager.d.ts.map +1 -1
  83. package/lib/typescript/lib/commonjs/ProfileManager/Components/VouchCard.d.ts.map +1 -1
  84. package/lib/typescript/lib/module/AdServer/api/index.d.ts.map +1 -1
  85. package/lib/typescript/lib/module/AdServer/index.d.ts +9 -0
  86. package/lib/typescript/lib/module/AdServer/index.d.ts.map +1 -1
  87. package/lib/typescript/lib/module/ApiOverrides/index.d.ts.map +1 -1
  88. package/lib/typescript/lib/module/BetRouter/api/index.d.ts +6 -0
  89. package/lib/typescript/lib/module/BetRouter/api/index.d.ts.map +1 -1
  90. package/lib/typescript/lib/module/BetRouter/components/ContestLiquidity.d.ts.map +1 -1
  91. package/lib/typescript/lib/module/BetRouter/components/admin/LeagueInfo.d.ts.map +1 -1
  92. package/lib/typescript/lib/module/BetRouter/components/admin/RouterMarkets.d.ts +4 -0
  93. package/lib/typescript/lib/module/BetRouter/components/admin/RouterMarkets.d.ts.map +1 -0
  94. package/lib/typescript/lib/module/BetRouter/layouts/DesktopAdminLayout.d.ts.map +1 -1
  95. package/lib/typescript/lib/module/BetRouter/layouts/MobileAdminLayout.d.ts.map +1 -1
  96. package/lib/typescript/lib/module/BetRouter/types/api-contracts.d.ts +77 -0
  97. package/lib/typescript/lib/module/BetRouter/types/api-contracts.d.ts.map +1 -1
  98. package/lib/typescript/lib/module/BetRouter/types/credentials.d.ts.map +1 -1
  99. package/lib/typescript/lib/module/Components/ViewportObserver.d.ts.map +1 -1
  100. package/lib/typescript/lib/module/ProfileManager/Components/DOBManager.d.ts.map +1 -1
  101. package/lib/typescript/lib/module/ProfileManager/Components/EmailManager.d.ts.map +1 -1
  102. package/lib/typescript/lib/module/ProfileManager/Components/PhoneManager.d.ts.map +1 -1
  103. package/lib/typescript/lib/module/ProfileManager/Components/VouchCard.d.ts.map +1 -1
  104. package/lib/typescript/src/AdServer/api/index.d.ts.map +1 -1
  105. package/lib/typescript/src/AdServer/index.d.ts +12 -3
  106. package/lib/typescript/src/AdServer/index.d.ts.map +1 -1
  107. package/lib/typescript/src/ApiOverrides/index.d.ts.map +1 -1
  108. package/lib/typescript/src/BetRouter/api/index.d.ts +23 -2
  109. package/lib/typescript/src/BetRouter/api/index.d.ts.map +1 -1
  110. package/lib/typescript/src/BetRouter/components/ContestLiquidity.d.ts.map +1 -1
  111. package/lib/typescript/src/BetRouter/components/admin/LeagueInfo.d.ts.map +1 -1
  112. package/lib/typescript/src/BetRouter/components/admin/RouterMarkets.d.ts +4 -0
  113. package/lib/typescript/src/BetRouter/components/admin/RouterMarkets.d.ts.map +1 -0
  114. package/lib/typescript/src/BetRouter/layouts/DesktopAdminLayout.d.ts.map +1 -1
  115. package/lib/typescript/src/BetRouter/layouts/MobileAdminLayout.d.ts.map +1 -1
  116. package/lib/typescript/src/BetRouter/types/api-contracts.d.ts +93 -4
  117. package/lib/typescript/src/BetRouter/types/api-contracts.d.ts.map +1 -1
  118. package/lib/typescript/src/BetRouter/types/credentials.d.ts +1 -5
  119. package/lib/typescript/src/BetRouter/types/credentials.d.ts.map +1 -1
  120. package/lib/typescript/src/Components/ViewportObserver.d.ts.map +1 -1
  121. package/lib/typescript/src/ProfileManager/Components/DOBManager.d.ts.map +1 -1
  122. package/lib/typescript/src/ProfileManager/Components/EmailManager.d.ts.map +1 -1
  123. package/lib/typescript/src/ProfileManager/Components/PhoneManager.d.ts.map +1 -1
  124. package/lib/typescript/src/ProfileManager/Components/VouchCard.d.ts.map +1 -1
  125. package/package.json +1 -1
  126. package/src/AdServer/api/index.ts +4 -2
  127. package/src/AdServer/index.tsx +64 -22
  128. package/src/ApiOverrides/index.ts +3 -2
  129. package/src/BetRouter/api/index.ts +101 -2
  130. package/src/BetRouter/components/ContestLiquidity.tsx +78 -11
  131. package/src/BetRouter/components/admin/LeagueInfo.tsx +231 -3
  132. package/src/BetRouter/components/admin/RouterMarkets.tsx +1238 -0
  133. package/src/BetRouter/layouts/DesktopAdminLayout.tsx +24 -1
  134. package/src/BetRouter/layouts/MobileAdminLayout.tsx +30 -2
  135. package/src/BetRouter/types/api-contracts.ts +100 -2
  136. package/src/BetRouter/types/credentials.ts +5 -6
  137. package/src/Components/ViewportObserver.tsx +13 -2
  138. package/src/ProfileManager/Components/DOBManager.tsx +14 -1
  139. package/src/ProfileManager/Components/EmailManager.tsx +16 -1
  140. package/src/ProfileManager/Components/PhoneManager.tsx +14 -0
  141. package/src/ProfileManager/Components/VouchCard.tsx +12 -4
  142. package/src/types.d.ts +3 -3
@@ -0,0 +1,1238 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { View, Text, Button } from "../../../Components/Themed";
3
+ import { ActivityIndicator, TouchableOpacity, TextInput, Modal, ScrollView } from 'react-native';
4
+ import { useColors } from '../../../constants/useColors';
5
+ import { BetRouterApi } from '../../api';
6
+ import { Icons, SearchBox } from '../../../Components';
7
+ import type { RouterMarketProps, RouterMarketSideProps, RouterMarketVariableProps } from '../../types';
8
+
9
+ type RouterMarketsData = {
10
+ router_markets: RouterMarketProps[];
11
+ router_market_sides: RouterMarketSideProps[];
12
+ router_market_variables: RouterMarketVariableProps[];
13
+ loading: boolean;
14
+ searchValue: string;
15
+ showCreateMarketModal: boolean;
16
+ showEditMarketModal: boolean;
17
+ showDeleteMarketModal: boolean;
18
+ showCreateSideModal: boolean;
19
+ showEditSideModal: boolean;
20
+ showDeleteSideModal: boolean;
21
+ selectedMarket: RouterMarketProps | null;
22
+ selectedSide: RouterMarketSideProps | null;
23
+ expandedMarketId: string | null;
24
+ // Form state for router_market
25
+ formMarketKey: string;
26
+ formMarketLabel: string;
27
+ formMarketDescription: string;
28
+ formCategory: 'game_result' | 'team_stat' | 'player_stat' | 'game_stat';
29
+ formVariableRequired: boolean;
30
+ formDefaultVariableType: 'total' | 'spread';
31
+ formAllowMultipleParticipants: boolean;
32
+ formParticipantType: 'team' | 'player' | 'event';
33
+ formStatus: 'active' | 'inactive';
34
+ // Form state for router_market_side
35
+ formSideRouterMarketId: string;
36
+ formSideType: string;
37
+ formSideKey: string;
38
+ formRenderer: string;
39
+ };
40
+
41
+ const RouterMarkets = () => {
42
+ const Colors = useColors();
43
+
44
+ const [data, setData] = useState<RouterMarketsData>({
45
+ router_markets: [],
46
+ router_market_sides: [],
47
+ router_market_variables: [],
48
+ loading: true,
49
+ searchValue: '',
50
+ showCreateMarketModal: false,
51
+ showEditMarketModal: false,
52
+ showDeleteMarketModal: false,
53
+ showCreateSideModal: false,
54
+ showEditSideModal: false,
55
+ showDeleteSideModal: false,
56
+ selectedMarket: null,
57
+ selectedSide: null,
58
+ expandedMarketId: null,
59
+ formMarketKey: '',
60
+ formMarketLabel: '',
61
+ formMarketDescription: '',
62
+ formCategory: 'game_result',
63
+ formVariableRequired: false,
64
+ formDefaultVariableType: 'total',
65
+ formAllowMultipleParticipants: false,
66
+ formParticipantType: 'team',
67
+ formStatus: 'active',
68
+ formSideRouterMarketId: '',
69
+ formSideType: '',
70
+ formSideKey: '',
71
+ formRenderer: ''
72
+ });
73
+
74
+ useEffect(() => {
75
+ loadData();
76
+ }, []);
77
+
78
+ const loadData = async () => {
79
+ setData(prev => ({ ...prev, loading: true }));
80
+ try {
81
+ const [marketsResult, sidesResult, variablesResult] = await Promise.all([
82
+ BetRouterApi.BetRouter.MarketApi.getRouterMarkets(),
83
+ BetRouterApi.BetRouter.MarketApi.getMarketSides(),
84
+ BetRouterApi.BetRouter.MarketApi.getMarketVariables()
85
+ ]);
86
+
87
+ // API returns arrays directly, not objects with properties
88
+ setData(prev => ({
89
+ ...prev,
90
+ router_markets: Array.isArray(marketsResult) ? marketsResult : [],
91
+ router_market_sides: Array.isArray(sidesResult) ? sidesResult : [],
92
+ router_market_variables: Array.isArray(variablesResult) ? variablesResult : [],
93
+ loading: false
94
+ }));
95
+ } catch (error) {
96
+ console.error('Failed to load router markets:', error);
97
+ alert('Error loading router markets: ' + (error as any).message);
98
+ setData(prev => ({ ...prev, loading: false }));
99
+ }
100
+ };
101
+
102
+ // Market CRUD operations
103
+ const openCreateMarketModal = () => {
104
+ setData(prev => ({
105
+ ...prev,
106
+ showCreateMarketModal: true,
107
+ formMarketKey: '',
108
+ formMarketLabel: '',
109
+ formMarketDescription: '',
110
+ formCategory: 'game_result',
111
+ formVariableRequired: false,
112
+ formDefaultVariableType: 'total',
113
+ formAllowMultipleParticipants: false,
114
+ formParticipantType: 'team',
115
+ formStatus: 'active'
116
+ }));
117
+ };
118
+
119
+ const openEditMarketModal = (market: RouterMarketProps) => {
120
+ setData(prev => ({
121
+ ...prev,
122
+ showEditMarketModal: true,
123
+ selectedMarket: market,
124
+ formMarketKey: market.market_key,
125
+ formMarketLabel: market.market_label,
126
+ formMarketDescription: market.market_description,
127
+ formCategory: market.category,
128
+ formVariableRequired: market.variable_required,
129
+ formDefaultVariableType: market.default_variable_type,
130
+ formAllowMultipleParticipants: market.allow_multiple_participants,
131
+ formParticipantType: market.participant_type,
132
+ formStatus: market.status
133
+ }));
134
+ };
135
+
136
+ const openDeleteMarketModal = (market: RouterMarketProps) => {
137
+ setData(prev => ({
138
+ ...prev,
139
+ showDeleteMarketModal: true,
140
+ selectedMarket: market
141
+ }));
142
+ };
143
+
144
+ const handleCreateMarket = async () => {
145
+ if (!data.formMarketKey || !data.formMarketLabel || !data.formMarketDescription) {
146
+ alert('Please fill in all required fields');
147
+ return;
148
+ }
149
+
150
+ try {
151
+ setData(prev => ({ ...prev, loading: true }));
152
+ await BetRouterApi.BetRouter.MarketApi.createRouterMarket(
153
+ data.formMarketKey,
154
+ data.formMarketLabel,
155
+ data.formMarketDescription,
156
+ data.formCategory,
157
+ data.formVariableRequired,
158
+ data.formDefaultVariableType,
159
+ data.formAllowMultipleParticipants,
160
+ data.formParticipantType,
161
+ data.formStatus
162
+ );
163
+ closeModals();
164
+ await loadData();
165
+ } catch (error) {
166
+ console.error('Error creating router market:', error);
167
+ alert('Error creating router market: ' + (error as any).message);
168
+ setData(prev => ({ ...prev, loading: false }));
169
+ }
170
+ };
171
+
172
+ const handleUpdateMarket = async () => {
173
+ if (!data.selectedMarket) return;
174
+
175
+ try {
176
+ setData(prev => ({ ...prev, loading: true }));
177
+ await BetRouterApi.BetRouter.MarketApi.updateRouterMarket(
178
+ data.selectedMarket.router_market_id,
179
+ {
180
+ market_key: data.formMarketKey,
181
+ market_label: data.formMarketLabel,
182
+ market_description: data.formMarketDescription,
183
+ category: data.formCategory,
184
+ variable_required: data.formVariableRequired,
185
+ default_variable_type: data.formDefaultVariableType,
186
+ allow_multiple_participants: data.formAllowMultipleParticipants,
187
+ participant_type: data.formParticipantType,
188
+ status: data.formStatus
189
+ }
190
+ );
191
+ closeModals();
192
+ await loadData();
193
+ } catch (error) {
194
+ console.error('Error updating router market:', error);
195
+ alert('Error updating router market: ' + (error as any).message);
196
+ setData(prev => ({ ...prev, loading: false }));
197
+ }
198
+ };
199
+
200
+ const handleDeleteMarket = async () => {
201
+ if (!data.selectedMarket) return;
202
+
203
+ try {
204
+ setData(prev => ({ ...prev, loading: true }));
205
+ await BetRouterApi.BetRouter.MarketApi.deleteRouterMarket(data.selectedMarket.router_market_id);
206
+ closeModals();
207
+ await loadData();
208
+ } catch (error) {
209
+ console.error('Error deleting router market:', error);
210
+ alert('Error deleting router market: ' + (error as any).message);
211
+ setData(prev => ({ ...prev, loading: false }));
212
+ }
213
+ };
214
+
215
+ // Side CRUD operations
216
+ const openCreateSideModal = (router_market_id: string) => {
217
+ setData(prev => ({
218
+ ...prev,
219
+ showCreateSideModal: true,
220
+ formSideRouterMarketId: router_market_id,
221
+ formSideType: '',
222
+ formSideKey: '',
223
+ formRenderer: ''
224
+ }));
225
+ };
226
+
227
+ const openEditSideModal = (side: RouterMarketSideProps) => {
228
+ setData(prev => ({
229
+ ...prev,
230
+ showEditSideModal: true,
231
+ selectedSide: side,
232
+ formSideRouterMarketId: side.router_market_id,
233
+ formSideType: side.side_type,
234
+ formSideKey: side.side_key,
235
+ formRenderer: side.renderer
236
+ }));
237
+ };
238
+
239
+ const openDeleteSideModal = (side: RouterMarketSideProps) => {
240
+ setData(prev => ({
241
+ ...prev,
242
+ showDeleteSideModal: true,
243
+ selectedSide: side
244
+ }));
245
+ };
246
+
247
+ const handleCreateSide = async () => {
248
+ if (!data.formSideRouterMarketId || !data.formSideType || !data.formSideKey || !data.formRenderer) {
249
+ alert('Please fill in all required fields');
250
+ return;
251
+ }
252
+
253
+ try {
254
+ setData(prev => ({ ...prev, loading: true }));
255
+ await BetRouterApi.BetRouter.MarketApi.createMarketSide(
256
+ data.formSideRouterMarketId,
257
+ data.formSideType,
258
+ data.formSideKey,
259
+ data.formRenderer
260
+ );
261
+ closeModals();
262
+ await loadData();
263
+ } catch (error) {
264
+ console.error('Error creating market side:', error);
265
+ alert('Error creating market side: ' + (error as any).message);
266
+ setData(prev => ({ ...prev, loading: false }));
267
+ }
268
+ };
269
+
270
+ const handleUpdateSide = async () => {
271
+ if (!data.selectedSide) return;
272
+
273
+ try {
274
+ setData(prev => ({ ...prev, loading: true }));
275
+ await BetRouterApi.BetRouter.MarketApi.updateMarketSide(
276
+ data.selectedSide.market_side_id,
277
+ {
278
+ router_market_id: data.formSideRouterMarketId,
279
+ side_type: data.formSideType,
280
+ side_key: data.formSideKey,
281
+ renderer: data.formRenderer
282
+ }
283
+ );
284
+ closeModals();
285
+ await loadData();
286
+ } catch (error) {
287
+ console.error('Error updating market side:', error);
288
+ alert('Error updating market side: ' + (error as any).message);
289
+ setData(prev => ({ ...prev, loading: false }));
290
+ }
291
+ };
292
+
293
+ const handleDeleteSide = async () => {
294
+ if (!data.selectedSide) return;
295
+
296
+ try {
297
+ setData(prev => ({ ...prev, loading: true }));
298
+ await BetRouterApi.BetRouter.MarketApi.deleteMarketSide(data.selectedSide.market_side_id);
299
+ closeModals();
300
+ await loadData();
301
+ } catch (error) {
302
+ console.error('Error deleting market side:', error);
303
+ alert('Error deleting market side: ' + (error as any).message);
304
+ setData(prev => ({ ...prev, loading: false }));
305
+ }
306
+ };
307
+
308
+ const closeModals = () => {
309
+ setData(prev => ({
310
+ ...prev,
311
+ showCreateMarketModal: false,
312
+ showEditMarketModal: false,
313
+ showDeleteMarketModal: false,
314
+ showCreateSideModal: false,
315
+ showEditSideModal: false,
316
+ showDeleteSideModal: false,
317
+ selectedMarket: null,
318
+ selectedSide: null
319
+ }));
320
+ };
321
+
322
+ const toggleMarketExpansion = (router_market_id: string) => {
323
+ setData(prev => ({
324
+ ...prev,
325
+ expandedMarketId: prev.expandedMarketId === router_market_id ? null : router_market_id
326
+ }));
327
+ };
328
+
329
+ const filteredMarkets = data.router_markets.filter(market =>
330
+ market.market_label.toLowerCase().includes(data.searchValue.toLowerCase()) ||
331
+ market.market_key.toLowerCase().includes(data.searchValue.toLowerCase())
332
+ );
333
+
334
+ const getSidesForMarket = (router_market_id: string) => {
335
+ return data.router_market_sides.filter(side => side.router_market_id === router_market_id);
336
+ };
337
+
338
+ const getVariablesForMarket = (router_market_id: string) => {
339
+ return data.router_market_variables.filter(variable => variable.router_market_id === router_market_id);
340
+ };
341
+
342
+ return (
343
+ <View transparent style={{ flex: 1, padding: 20 }}>
344
+ {/* Header */}
345
+ <View transparent style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20 }}>
346
+ <View transparent>
347
+ <Text theme="h1" size={24}>Router Markets</Text>
348
+ <Text theme="description" size={14}>
349
+ Manage router market types, sides, and variables
350
+ </Text>
351
+ </View>
352
+ <Button
353
+ type='success'
354
+ title='+ Create Market'
355
+ onPress={openCreateMarketModal}
356
+ />
357
+ </View>
358
+
359
+ {/* Search */}
360
+ <View transparent style={{ marginBottom: 20 }}>
361
+ <SearchBox
362
+ placeholder="Search markets..."
363
+ onChange={(text) => setData(prev => ({ ...prev, searchValue: text }))}
364
+ hide_search_button
365
+ />
366
+ </View>
367
+
368
+ {/* Markets List */}
369
+ {data.loading ? (
370
+ <View transparent style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
371
+ <ActivityIndicator size="large" color={Colors.text.h1} />
372
+ </View>
373
+ ) : (
374
+ <ScrollView style={{ flex: 1 }}>
375
+ <View transparent style={{ paddingBottom: 40 }}>
376
+ {filteredMarkets.length === 0 ? (
377
+ <View transparent style={{ padding: 40, alignItems: 'center' }}>
378
+ <Text theme="description" size={14}>
379
+ No router markets found
380
+ </Text>
381
+ </View>
382
+ ) : (
383
+ filteredMarkets.map((market) => {
384
+ const isExpanded = data.expandedMarketId === market.router_market_id;
385
+ const sides = getSidesForMarket(market.router_market_id);
386
+ const variables = getVariablesForMarket(market.router_market_id);
387
+
388
+ return (
389
+ <View
390
+ key={market.router_market_id}
391
+ style={{
392
+ backgroundColor: Colors.views.body,
393
+ borderRadius: 8,
394
+ marginBottom: 12,
395
+ overflow: 'hidden'
396
+ }}
397
+ >
398
+ {/* Market Header */}
399
+ <TouchableOpacity
400
+ onPress={() => toggleMarketExpansion(market.router_market_id)}
401
+ style={{
402
+ padding: 16,
403
+ flexDirection: 'row',
404
+ alignItems: 'center',
405
+ justifyContent: 'space-between'
406
+ }}
407
+ >
408
+ <View transparent style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
409
+ <Icons.ChevronIcon
410
+ direction={isExpanded ? 'down' : 'right'}
411
+ size={8}
412
+ color={Colors.text.h1}
413
+ />
414
+ <View transparent style={{ flex: 1, marginLeft: 12 }}>
415
+ <View transparent style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
416
+ <Text theme="h2" size={16}>
417
+ {market.market_label}
418
+ </Text>
419
+ <View
420
+ style={{
421
+ backgroundColor: market.status === 'active'
422
+ ? Colors.text.success
423
+ : Colors.views.header,
424
+ paddingHorizontal: 8,
425
+ paddingVertical: 2,
426
+ borderRadius: 4
427
+ }}
428
+ >
429
+ <Text theme="h2" size={10}>
430
+ {market.status.toUpperCase()}
431
+ </Text>
432
+ </View>
433
+ </View>
434
+ <Text theme="description" size={12} style={{ marginTop: 4 }}>
435
+ {market.market_key} • {market.category} • {market.participant_type}
436
+ </Text>
437
+ <Text theme="description" size={12} style={{ marginTop: 2 }}>
438
+ {market.market_description}
439
+ </Text>
440
+ </View>
441
+ </View>
442
+ <View transparent style={{ flexDirection: 'row', gap: 8, marginLeft: 12 }}>
443
+ <TouchableOpacity
444
+ onPress={(e) => {
445
+ e.stopPropagation();
446
+ openEditMarketModal(market);
447
+ }}
448
+ style={{ padding: 8 }}
449
+ >
450
+ <Icons.EditIcon size={16} color={Colors.text.description} />
451
+ </TouchableOpacity>
452
+ <TouchableOpacity
453
+ onPress={(e) => {
454
+ e.stopPropagation();
455
+ openDeleteMarketModal(market);
456
+ }}
457
+ style={{
458
+ paddingHorizontal: 12,
459
+ paddingVertical: 6,
460
+ backgroundColor: Colors.text.error,
461
+ borderRadius: 4
462
+ }}
463
+ >
464
+ <Text theme="h2" size={11}>Delete</Text>
465
+ </TouchableOpacity>
466
+ </View>
467
+ </TouchableOpacity>
468
+
469
+ {/* Expanded Content */}
470
+ {isExpanded && (
471
+ <View style={{ backgroundColor: Colors.views.header, padding: 16 }}>
472
+ {/* Market Properties */}
473
+ <View transparent style={{ marginBottom: 16 }}>
474
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>
475
+ Properties
476
+ </Text>
477
+ <View transparent style={{ gap: 4 }}>
478
+ <Text theme="description" size={12}>
479
+ Variable Required: {market.variable_required ? 'Yes' : 'No'}
480
+ </Text>
481
+ <Text theme="description" size={12}>
482
+ Default Variable Type: {market.default_variable_type}
483
+ </Text>
484
+ <Text theme="description" size={12}>
485
+ Allow Multiple Participants: {market.allow_multiple_participants ? 'Yes' : 'No'}
486
+ </Text>
487
+ </View>
488
+ </View>
489
+
490
+ {/* Market Sides */}
491
+ <View transparent style={{ marginBottom: 16 }}>
492
+ <View transparent style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
493
+ <Text theme="h2" size={14}>
494
+ Sides ({sides.length})
495
+ </Text>
496
+ <TouchableOpacity
497
+ onPress={() => openCreateSideModal(market.router_market_id)}
498
+ style={{
499
+ backgroundColor: Colors.views.body,
500
+ paddingHorizontal: 12,
501
+ paddingVertical: 6,
502
+ borderRadius: 4
503
+ }}
504
+ >
505
+ <Text theme="h2" size={12}>+ Add Side</Text>
506
+ </TouchableOpacity>
507
+ </View>
508
+ {sides.length === 0 ? (
509
+ <Text theme="description" size={12}>No sides defined</Text>
510
+ ) : (
511
+ <View transparent style={{ gap: 8 }}>
512
+ {sides.map((side) => (
513
+ <View
514
+ key={side.market_side_id}
515
+ style={{
516
+ backgroundColor: Colors.views.body,
517
+ padding: 12,
518
+ borderRadius: 6,
519
+ flexDirection: 'row',
520
+ justifyContent: 'space-between',
521
+ alignItems: 'center'
522
+ }}
523
+ >
524
+ <View transparent style={{ flex: 1 }}>
525
+ <Text theme="h2" size={13}>
526
+ {side.side_key}
527
+ </Text>
528
+ <Text theme="description" size={11} style={{ marginTop: 2 }}>
529
+ Type: {side.side_type}
530
+ </Text>
531
+ <Text theme="description" size={11} style={{ marginTop: 2 }}>
532
+ Renderer: {side.renderer}
533
+ </Text>
534
+ </View>
535
+ <View transparent style={{ flexDirection: 'row', gap: 8 }}>
536
+ <TouchableOpacity
537
+ onPress={() => openEditSideModal(side)}
538
+ style={{ padding: 6 }}
539
+ >
540
+ <Icons.EditIcon size={14} color={Colors.text.description} />
541
+ </TouchableOpacity>
542
+ <TouchableOpacity
543
+ onPress={() => openDeleteSideModal(side)}
544
+ style={{
545
+ paddingHorizontal: 8,
546
+ paddingVertical: 4,
547
+ backgroundColor: Colors.text.error,
548
+ borderRadius: 4
549
+ }}
550
+ >
551
+ <Text theme="h2" size={10}>Del</Text>
552
+ </TouchableOpacity>
553
+ </View>
554
+ </View>
555
+ ))}
556
+ </View>
557
+ )}
558
+ </View>
559
+
560
+ {/* Market Variables */}
561
+ <View transparent>
562
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>
563
+ Variables ({variables.length})
564
+ </Text>
565
+ {variables.length === 0 ? (
566
+ <Text theme="description" size={12}>No variables defined</Text>
567
+ ) : (
568
+ <View transparent style={{ gap: 4 }}>
569
+ {variables.map((variable) => (
570
+ <Text key={variable.router_market_variable_id} theme="description" size={12}>
571
+ {variable.variable} ({variable.variable_type})
572
+ </Text>
573
+ ))}
574
+ </View>
575
+ )}
576
+ </View>
577
+ </View>
578
+ )}
579
+ </View>
580
+ );
581
+ })
582
+ )}
583
+ </View>
584
+ </ScrollView>
585
+ )}
586
+
587
+ {/* Create Market Modal */}
588
+ <Modal
589
+ visible={data.showCreateMarketModal}
590
+ transparent
591
+ animationType="fade"
592
+ onRequestClose={closeModals}
593
+ >
594
+ <View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', alignItems: 'center' }}>
595
+ <View style={{ backgroundColor: Colors.views.body, borderRadius: 12, padding: 24, width: '90%', maxWidth: 500 }}>
596
+ <Text theme="h1" size={20} style={{ marginBottom: 20 }}>Create Router Market</Text>
597
+
598
+ <ScrollView style={{ maxHeight: 500 }}>
599
+ <View transparent style={{ gap: 16 }}>
600
+ <View transparent>
601
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Market Key *</Text>
602
+ <TextInput
603
+ style={{
604
+ backgroundColor: Colors.views.header,
605
+ borderRadius: 6,
606
+ padding: 12,
607
+ color: Colors.text.h1,
608
+ fontSize: 14
609
+ }}
610
+ value={data.formMarketKey}
611
+ onChangeText={(text) => setData(prev => ({ ...prev, formMarketKey: text }))}
612
+ placeholder="e.g., moneyline"
613
+ placeholderTextColor={Colors.text.description}
614
+ />
615
+ </View>
616
+
617
+ <View transparent>
618
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Market Label *</Text>
619
+ <TextInput
620
+ style={{
621
+ backgroundColor: Colors.views.header,
622
+ borderRadius: 6,
623
+ padding: 12,
624
+ color: Colors.text.h1,
625
+ fontSize: 14
626
+ }}
627
+ value={data.formMarketLabel}
628
+ onChangeText={(text) => setData(prev => ({ ...prev, formMarketLabel: text }))}
629
+ placeholder="e.g., Moneyline"
630
+ placeholderTextColor={Colors.text.description}
631
+ />
632
+ </View>
633
+
634
+ <View transparent>
635
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Description *</Text>
636
+ <TextInput
637
+ style={{
638
+ backgroundColor: Colors.views.header,
639
+ borderRadius: 6,
640
+ padding: 12,
641
+ color: Colors.text.h1,
642
+ fontSize: 14,
643
+ minHeight: 80
644
+ }}
645
+ value={data.formMarketDescription}
646
+ onChangeText={(text) => setData(prev => ({ ...prev, formMarketDescription: text }))}
647
+ placeholder="Market description"
648
+ placeholderTextColor={Colors.text.description}
649
+ multiline
650
+ />
651
+ </View>
652
+
653
+ <View transparent>
654
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Category</Text>
655
+ <View transparent style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 8 }}>
656
+ {(['game_result', 'team_stat', 'player_stat', 'game_stat'] as const).map((cat) => (
657
+ <TouchableOpacity
658
+ key={cat}
659
+ onPress={() => setData(prev => ({ ...prev, formCategory: cat }))}
660
+ style={{
661
+ backgroundColor: data.formCategory === cat ? Colors.views.body : Colors.views.header,
662
+ paddingHorizontal: 12,
663
+ paddingVertical: 8,
664
+ borderRadius: 6
665
+ }}
666
+ >
667
+ <Text theme="h2" size={12}>{cat}</Text>
668
+ </TouchableOpacity>
669
+ ))}
670
+ </View>
671
+ </View>
672
+
673
+ <View transparent>
674
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Participant Type</Text>
675
+ <View transparent style={{ flexDirection: 'row', gap: 8 }}>
676
+ {(['team', 'player', 'event'] as const).map((type) => (
677
+ <TouchableOpacity
678
+ key={type}
679
+ onPress={() => setData(prev => ({ ...prev, formParticipantType: type }))}
680
+ style={{
681
+ backgroundColor: data.formParticipantType === type ? Colors.views.body : Colors.views.header,
682
+ paddingHorizontal: 12,
683
+ paddingVertical: 8,
684
+ borderRadius: 6
685
+ }}
686
+ >
687
+ <Text theme="h2" size={12}>{type}</Text>
688
+ </TouchableOpacity>
689
+ ))}
690
+ </View>
691
+ </View>
692
+
693
+ <View transparent>
694
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Default Variable Type</Text>
695
+ <View transparent style={{ flexDirection: 'row', gap: 8 }}>
696
+ {(['total', 'spread'] as const).map((type) => (
697
+ <TouchableOpacity
698
+ key={type}
699
+ onPress={() => setData(prev => ({ ...prev, formDefaultVariableType: type }))}
700
+ style={{
701
+ backgroundColor: data.formDefaultVariableType === type ? Colors.views.body : Colors.views.header,
702
+ paddingHorizontal: 12,
703
+ paddingVertical: 8,
704
+ borderRadius: 6
705
+ }}
706
+ >
707
+ <Text theme="h2" size={12}>{type}</Text>
708
+ </TouchableOpacity>
709
+ ))}
710
+ </View>
711
+ </View>
712
+
713
+ <View transparent style={{ gap: 12 }}>
714
+ <TouchableOpacity
715
+ onPress={() => setData(prev => ({ ...prev, formVariableRequired: !prev.formVariableRequired }))}
716
+ style={{
717
+ flexDirection: 'row',
718
+ alignItems: 'center',
719
+ gap: 8
720
+ }}
721
+ >
722
+ <View
723
+ style={{
724
+ width: 20,
725
+ height: 20,
726
+ borderRadius: 4,
727
+ borderWidth: 2,
728
+ borderColor: data.formVariableRequired ? Colors.views.body : Colors.text.description,
729
+ backgroundColor: data.formVariableRequired ? Colors.views.body : 'transparent',
730
+ justifyContent: 'center',
731
+ alignItems: 'center'
732
+ }}
733
+ >
734
+ {data.formVariableRequired && <Text theme="h2" size={12}>✓</Text>}
735
+ </View>
736
+ <Text theme="h2" size={14}>Variable Required</Text>
737
+ </TouchableOpacity>
738
+
739
+ <TouchableOpacity
740
+ onPress={() => setData(prev => ({ ...prev, formAllowMultipleParticipants: !prev.formAllowMultipleParticipants }))}
741
+ style={{
742
+ flexDirection: 'row',
743
+ alignItems: 'center',
744
+ gap: 8
745
+ }}
746
+ >
747
+ <View
748
+ style={{
749
+ width: 20,
750
+ height: 20,
751
+ borderRadius: 4,
752
+ borderWidth: 2,
753
+ borderColor: data.formAllowMultipleParticipants ? Colors.views.body : Colors.text.description,
754
+ backgroundColor: data.formAllowMultipleParticipants ? Colors.views.body : 'transparent',
755
+ justifyContent: 'center',
756
+ alignItems: 'center'
757
+ }}
758
+ >
759
+ {data.formAllowMultipleParticipants && <Text theme="h2" size={12}>✓</Text>}
760
+ </View>
761
+ <Text theme="h2" size={14}>Allow Multiple Participants</Text>
762
+ </TouchableOpacity>
763
+ </View>
764
+
765
+ <View transparent>
766
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Status</Text>
767
+ <View transparent style={{ flexDirection: 'row', gap: 8 }}>
768
+ {(['active', 'inactive'] as const).map((status) => (
769
+ <TouchableOpacity
770
+ key={status}
771
+ onPress={() => setData(prev => ({ ...prev, formStatus: status }))}
772
+ style={{
773
+ backgroundColor: data.formStatus === status ? Colors.views.body : Colors.views.header,
774
+ paddingHorizontal: 12,
775
+ paddingVertical: 8,
776
+ borderRadius: 6
777
+ }}
778
+ >
779
+ <Text theme="h2" size={12}>{status}</Text>
780
+ </TouchableOpacity>
781
+ ))}
782
+ </View>
783
+ </View>
784
+ </View>
785
+ </ScrollView>
786
+
787
+ <View transparent style={{ flexDirection: 'row', gap: 12, marginTop: 24 }}>
788
+ <Button
789
+ title="Cancel"
790
+ onPress={closeModals}
791
+ type="close"
792
+ style={{ flex: 1 }}
793
+ />
794
+ <Button
795
+ title="Create"
796
+ onPress={handleCreateMarket}
797
+ style={{ flex: 1 }}
798
+ />
799
+ </View>
800
+ </View>
801
+ </View>
802
+ </Modal>
803
+
804
+ {/* Edit Market Modal */}
805
+ <Modal
806
+ visible={data.showEditMarketModal}
807
+ transparent
808
+ animationType="fade"
809
+ onRequestClose={closeModals}
810
+ >
811
+ <View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', alignItems: 'center' }}>
812
+ <View style={{ backgroundColor: Colors.views.body, borderRadius: 12, padding: 24, width: '90%', maxWidth: 500 }}>
813
+ <Text theme="h1" size={20} style={{ marginBottom: 20 }}>Edit Router Market</Text>
814
+
815
+ <ScrollView style={{ maxHeight: 500 }}>
816
+ <View transparent style={{ gap: 16 }}>
817
+ <View transparent>
818
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Market Key *</Text>
819
+ <TextInput
820
+ style={{
821
+ backgroundColor: Colors.views.header,
822
+ borderRadius: 6,
823
+ padding: 12,
824
+ color: Colors.text.h1,
825
+ fontSize: 14
826
+ }}
827
+ value={data.formMarketKey}
828
+ onChangeText={(text) => setData(prev => ({ ...prev, formMarketKey: text }))}
829
+ />
830
+ </View>
831
+
832
+ <View transparent>
833
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Market Label *</Text>
834
+ <TextInput
835
+ style={{
836
+ backgroundColor: Colors.views.header,
837
+ borderRadius: 6,
838
+ padding: 12,
839
+ color: Colors.text.h1,
840
+ fontSize: 14
841
+ }}
842
+ value={data.formMarketLabel}
843
+ onChangeText={(text) => setData(prev => ({ ...prev, formMarketLabel: text }))}
844
+ />
845
+ </View>
846
+
847
+ <View transparent>
848
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Description *</Text>
849
+ <TextInput
850
+ style={{
851
+ backgroundColor: Colors.views.header,
852
+ borderRadius: 6,
853
+ padding: 12,
854
+ color: Colors.text.h1,
855
+ fontSize: 14,
856
+ minHeight: 80
857
+ }}
858
+ value={data.formMarketDescription}
859
+ onChangeText={(text) => setData(prev => ({ ...prev, formMarketDescription: text }))}
860
+ multiline
861
+ />
862
+ </View>
863
+
864
+ <View transparent>
865
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Category</Text>
866
+ <View transparent style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 8 }}>
867
+ {(['game_result', 'team_stat', 'player_stat', 'game_stat'] as const).map((cat) => (
868
+ <TouchableOpacity
869
+ key={cat}
870
+ onPress={() => setData(prev => ({ ...prev, formCategory: cat }))}
871
+ style={{
872
+ backgroundColor: data.formCategory === cat ? Colors.views.body : Colors.views.header,
873
+ paddingHorizontal: 12,
874
+ paddingVertical: 8,
875
+ borderRadius: 6
876
+ }}
877
+ >
878
+ <Text theme="h2" size={12}>{cat}</Text>
879
+ </TouchableOpacity>
880
+ ))}
881
+ </View>
882
+ </View>
883
+
884
+ <View transparent>
885
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Participant Type</Text>
886
+ <View transparent style={{ flexDirection: 'row', gap: 8 }}>
887
+ {(['team', 'player', 'event'] as const).map((type) => (
888
+ <TouchableOpacity
889
+ key={type}
890
+ onPress={() => setData(prev => ({ ...prev, formParticipantType: type }))}
891
+ style={{
892
+ backgroundColor: data.formParticipantType === type ? Colors.views.body : Colors.views.header,
893
+ paddingHorizontal: 12,
894
+ paddingVertical: 8,
895
+ borderRadius: 6
896
+ }}
897
+ >
898
+ <Text theme="h2" size={12}>{type}</Text>
899
+ </TouchableOpacity>
900
+ ))}
901
+ </View>
902
+ </View>
903
+
904
+ <View transparent>
905
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Default Variable Type</Text>
906
+ <View transparent style={{ flexDirection: 'row', gap: 8 }}>
907
+ {(['total', 'spread'] as const).map((type) => (
908
+ <TouchableOpacity
909
+ key={type}
910
+ onPress={() => setData(prev => ({ ...prev, formDefaultVariableType: type }))}
911
+ style={{
912
+ backgroundColor: data.formDefaultVariableType === type ? Colors.views.body : Colors.views.header,
913
+ paddingHorizontal: 12,
914
+ paddingVertical: 8,
915
+ borderRadius: 6
916
+ }}
917
+ >
918
+ <Text theme="h2" size={12}>{type}</Text>
919
+ </TouchableOpacity>
920
+ ))}
921
+ </View>
922
+ </View>
923
+
924
+ <View transparent style={{ gap: 12 }}>
925
+ <TouchableOpacity
926
+ onPress={() => setData(prev => ({ ...prev, formVariableRequired: !prev.formVariableRequired }))}
927
+ style={{
928
+ flexDirection: 'row',
929
+ alignItems: 'center',
930
+ gap: 8
931
+ }}
932
+ >
933
+ <View
934
+ style={{
935
+ width: 20,
936
+ height: 20,
937
+ borderRadius: 4,
938
+ borderWidth: 2,
939
+ borderColor: data.formVariableRequired ? Colors.views.body : Colors.text.description,
940
+ backgroundColor: data.formVariableRequired ? Colors.views.body : 'transparent',
941
+ justifyContent: 'center',
942
+ alignItems: 'center'
943
+ }}
944
+ >
945
+ {data.formVariableRequired && <Text theme="h2" size={12}>✓</Text>}
946
+ </View>
947
+ <Text theme="h2" size={14}>Variable Required</Text>
948
+ </TouchableOpacity>
949
+
950
+ <TouchableOpacity
951
+ onPress={() => setData(prev => ({ ...prev, formAllowMultipleParticipants: !prev.formAllowMultipleParticipants }))}
952
+ style={{
953
+ flexDirection: 'row',
954
+ alignItems: 'center',
955
+ gap: 8
956
+ }}
957
+ >
958
+ <View
959
+ style={{
960
+ width: 20,
961
+ height: 20,
962
+ borderRadius: 4,
963
+ borderWidth: 2,
964
+ borderColor: data.formAllowMultipleParticipants ? Colors.views.body : Colors.text.description,
965
+ backgroundColor: data.formAllowMultipleParticipants ? Colors.views.body : 'transparent',
966
+ justifyContent: 'center',
967
+ alignItems: 'center'
968
+ }}
969
+ >
970
+ {data.formAllowMultipleParticipants && <Text theme="h2" size={12}>✓</Text>}
971
+ </View>
972
+ <Text theme="h2" size={14}>Allow Multiple Participants</Text>
973
+ </TouchableOpacity>
974
+ </View>
975
+
976
+ <View transparent>
977
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Status</Text>
978
+ <View transparent style={{ flexDirection: 'row', gap: 8 }}>
979
+ {(['active', 'inactive'] as const).map((status) => (
980
+ <TouchableOpacity
981
+ key={status}
982
+ onPress={() => setData(prev => ({ ...prev, formStatus: status }))}
983
+ style={{
984
+ backgroundColor: data.formStatus === status ? Colors.views.body : Colors.views.header,
985
+ paddingHorizontal: 12,
986
+ paddingVertical: 8,
987
+ borderRadius: 6
988
+ }}
989
+ >
990
+ <Text theme="h2" size={12}>{status}</Text>
991
+ </TouchableOpacity>
992
+ ))}
993
+ </View>
994
+ </View>
995
+ </View>
996
+ </ScrollView>
997
+
998
+ <View transparent style={{ flexDirection: 'row', gap: 12, marginTop: 24 }}>
999
+ <Button
1000
+ title="Cancel"
1001
+ onPress={closeModals}
1002
+ type="close"
1003
+ style={{ flex: 1 }}
1004
+ />
1005
+ <Button
1006
+ title="Update"
1007
+ onPress={handleUpdateMarket}
1008
+ style={{ flex: 1 }}
1009
+ />
1010
+ </View>
1011
+ </View>
1012
+ </View>
1013
+ </Modal>
1014
+
1015
+ {/* Delete Market Modal */}
1016
+ <Modal
1017
+ visible={data.showDeleteMarketModal}
1018
+ transparent
1019
+ animationType="fade"
1020
+ onRequestClose={closeModals}
1021
+ >
1022
+ <View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', alignItems: 'center' }}>
1023
+ <View style={{ backgroundColor: Colors.views.body, borderRadius: 12, padding: 24, width: '90%', maxWidth: 400 }}>
1024
+ <Text theme="h1" size={20} style={{ marginBottom: 12 }}>Delete Router Market</Text>
1025
+ <Text theme="description" size={14} style={{ marginBottom: 24 }}>
1026
+ Are you sure you want to delete "{data.selectedMarket?.market_label}"? This action cannot be undone.
1027
+ </Text>
1028
+ <View transparent style={{ flexDirection: 'row', gap: 12 }}>
1029
+ <Button
1030
+ title="Cancel"
1031
+ onPress={closeModals}
1032
+ type="close"
1033
+ style={{ flex: 1 }}
1034
+ />
1035
+ <Button
1036
+ title="Delete"
1037
+ onPress={handleDeleteMarket}
1038
+ style={{ flex: 1, backgroundColor: Colors.text.error }}
1039
+ />
1040
+ </View>
1041
+ </View>
1042
+ </View>
1043
+ </Modal>
1044
+
1045
+ {/* Create Side Modal */}
1046
+ <Modal
1047
+ visible={data.showCreateSideModal}
1048
+ transparent
1049
+ animationType="fade"
1050
+ onRequestClose={closeModals}
1051
+ >
1052
+ <View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', alignItems: 'center' }}>
1053
+ <View style={{ backgroundColor: Colors.views.body, borderRadius: 12, padding: 24, width: '90%', maxWidth: 500 }}>
1054
+ <Text theme="h1" size={20} style={{ marginBottom: 20 }}>Create Market Side</Text>
1055
+
1056
+ <View transparent style={{ gap: 16 }}>
1057
+ <View transparent>
1058
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Side Type *</Text>
1059
+ <TextInput
1060
+ style={{
1061
+ backgroundColor: Colors.views.header,
1062
+ borderRadius: 6,
1063
+ padding: 12,
1064
+ color: Colors.text.h1,
1065
+ fontSize: 14
1066
+ }}
1067
+ value={data.formSideType}
1068
+ onChangeText={(text) => setData(prev => ({ ...prev, formSideType: text }))}
1069
+ placeholder="e.g., team, athlete, side"
1070
+ placeholderTextColor={Colors.text.description}
1071
+ />
1072
+ </View>
1073
+
1074
+ <View transparent>
1075
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Side Key *</Text>
1076
+ <TextInput
1077
+ style={{
1078
+ backgroundColor: Colors.views.header,
1079
+ borderRadius: 6,
1080
+ padding: 12,
1081
+ color: Colors.text.h1,
1082
+ fontSize: 14
1083
+ }}
1084
+ value={data.formSideKey}
1085
+ onChangeText={(text) => setData(prev => ({ ...prev, formSideKey: text }))}
1086
+ placeholder="e.g., home, away, over, under"
1087
+ placeholderTextColor={Colors.text.description}
1088
+ />
1089
+ </View>
1090
+
1091
+ <View transparent>
1092
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Renderer *</Text>
1093
+ <TextInput
1094
+ style={{
1095
+ backgroundColor: Colors.views.header,
1096
+ borderRadius: 6,
1097
+ padding: 12,
1098
+ color: Colors.text.h1,
1099
+ fontSize: 14,
1100
+ minHeight: 80
1101
+ }}
1102
+ value={data.formRenderer}
1103
+ onChangeText={(text) => setData(prev => ({ ...prev, formRenderer: text }))}
1104
+ placeholder="Template for rendering titles"
1105
+ placeholderTextColor={Colors.text.description}
1106
+ multiline
1107
+ />
1108
+ </View>
1109
+ </View>
1110
+
1111
+ <View transparent style={{ flexDirection: 'row', gap: 12, marginTop: 24 }}>
1112
+ <Button
1113
+ title="Cancel"
1114
+ onPress={closeModals}
1115
+ type="close"
1116
+ style={{ flex: 1 }}
1117
+ />
1118
+ <Button
1119
+ title="Create"
1120
+ onPress={handleCreateSide}
1121
+ style={{ flex: 1 }}
1122
+ />
1123
+ </View>
1124
+ </View>
1125
+ </View>
1126
+ </Modal>
1127
+
1128
+ {/* Edit Side Modal */}
1129
+ <Modal
1130
+ visible={data.showEditSideModal}
1131
+ transparent
1132
+ animationType="fade"
1133
+ onRequestClose={closeModals}
1134
+ >
1135
+ <View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', alignItems: 'center' }}>
1136
+ <View style={{ backgroundColor: Colors.views.body, borderRadius: 12, padding: 24, width: '90%', maxWidth: 500 }}>
1137
+ <Text theme="h1" size={20} style={{ marginBottom: 20 }}>Edit Market Side</Text>
1138
+
1139
+ <View transparent style={{ gap: 16 }}>
1140
+ <View transparent>
1141
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Side Type *</Text>
1142
+ <TextInput
1143
+ style={{
1144
+ backgroundColor: Colors.views.header,
1145
+ borderRadius: 6,
1146
+ padding: 12,
1147
+ color: Colors.text.h1,
1148
+ fontSize: 14
1149
+ }}
1150
+ value={data.formSideType}
1151
+ onChangeText={(text) => setData(prev => ({ ...prev, formSideType: text }))}
1152
+ />
1153
+ </View>
1154
+
1155
+ <View transparent>
1156
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Side Key *</Text>
1157
+ <TextInput
1158
+ style={{
1159
+ backgroundColor: Colors.views.header,
1160
+ borderRadius: 6,
1161
+ padding: 12,
1162
+ color: Colors.text.h1,
1163
+ fontSize: 14
1164
+ }}
1165
+ value={data.formSideKey}
1166
+ onChangeText={(text) => setData(prev => ({ ...prev, formSideKey: text }))}
1167
+ />
1168
+ </View>
1169
+
1170
+ <View transparent>
1171
+ <Text theme="h2" size={14} style={{ marginBottom: 8 }}>Renderer *</Text>
1172
+ <TextInput
1173
+ style={{
1174
+ backgroundColor: Colors.views.header,
1175
+ borderRadius: 6,
1176
+ padding: 12,
1177
+ color: Colors.text.h1,
1178
+ fontSize: 14,
1179
+ minHeight: 80
1180
+ }}
1181
+ value={data.formRenderer}
1182
+ onChangeText={(text) => setData(prev => ({ ...prev, formRenderer: text }))}
1183
+ multiline
1184
+ />
1185
+ </View>
1186
+ </View>
1187
+
1188
+ <View transparent style={{ flexDirection: 'row', gap: 12, marginTop: 24 }}>
1189
+ <Button
1190
+ title="Cancel"
1191
+ onPress={closeModals}
1192
+ type="close"
1193
+ style={{ flex: 1 }}
1194
+ />
1195
+ <Button
1196
+ title="Update"
1197
+ onPress={handleUpdateSide}
1198
+ style={{ flex: 1 }}
1199
+ />
1200
+ </View>
1201
+ </View>
1202
+ </View>
1203
+ </Modal>
1204
+
1205
+ {/* Delete Side Modal */}
1206
+ <Modal
1207
+ visible={data.showDeleteSideModal}
1208
+ transparent
1209
+ animationType="fade"
1210
+ onRequestClose={closeModals}
1211
+ >
1212
+ <View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', alignItems: 'center' }}>
1213
+ <View style={{ backgroundColor: Colors.views.body, borderRadius: 12, padding: 24, width: '90%', maxWidth: 400 }}>
1214
+ <Text theme="h1" size={20} style={{ marginBottom: 12 }}>Delete Market Side</Text>
1215
+ <Text theme="description" size={14} style={{ marginBottom: 24 }}>
1216
+ Are you sure you want to delete this market side? This action cannot be undone.
1217
+ </Text>
1218
+ <View transparent style={{ flexDirection: 'row', gap: 12 }}>
1219
+ <Button
1220
+ title="Cancel"
1221
+ onPress={closeModals}
1222
+ type="close"
1223
+ style={{ flex: 1 }}
1224
+ />
1225
+ <Button
1226
+ title="Delete"
1227
+ onPress={handleDeleteSide}
1228
+ style={{ flex: 1, backgroundColor: Colors.text.error }}
1229
+ />
1230
+ </View>
1231
+ </View>
1232
+ </View>
1233
+ </Modal>
1234
+ </View>
1235
+ );
1236
+ };
1237
+
1238
+ export default RouterMarkets;