be-components 7.5.6 → 7.5.8

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 (150) 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/BasicInfoManager.js +39 -3
  26. package/lib/commonjs/ProfileManager/Components/BasicInfoManager.js.map +1 -1
  27. package/lib/commonjs/ProfileManager/Components/DOBManager.js +38 -2
  28. package/lib/commonjs/ProfileManager/Components/DOBManager.js.map +1 -1
  29. package/lib/commonjs/ProfileManager/Components/EmailManager.js +40 -2
  30. package/lib/commonjs/ProfileManager/Components/EmailManager.js.map +1 -1
  31. package/lib/commonjs/ProfileManager/Components/PhoneManager.js +38 -1
  32. package/lib/commonjs/ProfileManager/Components/PhoneManager.js.map +1 -1
  33. package/lib/commonjs/ProfileManager/Components/VouchCard.js +13 -3
  34. package/lib/commonjs/ProfileManager/Components/VouchCard.js.map +1 -1
  35. package/lib/module/AdServer/api/index.js +4 -2
  36. package/lib/module/AdServer/api/index.js.map +1 -1
  37. package/lib/module/AdServer/index.js +25 -12
  38. package/lib/module/AdServer/index.js.map +1 -1
  39. package/lib/module/ApiOverrides/index.js +3 -2
  40. package/lib/module/ApiOverrides/index.js.map +1 -1
  41. package/lib/module/BetRouter/api/index.js +69 -0
  42. package/lib/module/BetRouter/api/index.js.map +1 -1
  43. package/lib/module/BetRouter/components/ContestLiquidity.js +72 -11
  44. package/lib/module/BetRouter/components/ContestLiquidity.js.map +1 -1
  45. package/lib/module/BetRouter/components/admin/LeagueInfo.js +233 -3
  46. package/lib/module/BetRouter/components/admin/LeagueInfo.js.map +1 -1
  47. package/lib/module/BetRouter/components/admin/RouterMarkets.js +1548 -0
  48. package/lib/module/BetRouter/components/admin/RouterMarkets.js.map +1 -0
  49. package/lib/module/BetRouter/layouts/DesktopAdminLayout.js +16 -3
  50. package/lib/module/BetRouter/layouts/DesktopAdminLayout.js.map +1 -1
  51. package/lib/module/BetRouter/layouts/MobileAdminLayout.js +31 -2
  52. package/lib/module/BetRouter/layouts/MobileAdminLayout.js.map +1 -1
  53. package/lib/module/BetRouter/types/api-contracts.js +77 -0
  54. package/lib/module/BetRouter/types/api-contracts.js.map +1 -1
  55. package/lib/module/BetRouter/types/credentials.js +4 -0
  56. package/lib/module/BetRouter/types/credentials.js.map +1 -1
  57. package/lib/module/Components/ViewportObserver.js +9 -0
  58. package/lib/module/Components/ViewportObserver.js.map +1 -1
  59. package/lib/module/ProfileManager/Components/BasicInfoManager.js +39 -3
  60. package/lib/module/ProfileManager/Components/BasicInfoManager.js.map +1 -1
  61. package/lib/module/ProfileManager/Components/DOBManager.js +38 -2
  62. package/lib/module/ProfileManager/Components/DOBManager.js.map +1 -1
  63. package/lib/module/ProfileManager/Components/EmailManager.js +40 -2
  64. package/lib/module/ProfileManager/Components/EmailManager.js.map +1 -1
  65. package/lib/module/ProfileManager/Components/PhoneManager.js +38 -1
  66. package/lib/module/ProfileManager/Components/PhoneManager.js.map +1 -1
  67. package/lib/module/ProfileManager/Components/VouchCard.js +13 -3
  68. package/lib/module/ProfileManager/Components/VouchCard.js.map +1 -1
  69. package/lib/typescript/lib/commonjs/AdServer/api/index.d.ts.map +1 -1
  70. package/lib/typescript/lib/commonjs/AdServer/index.d.ts +1 -0
  71. package/lib/typescript/lib/commonjs/AdServer/index.d.ts.map +1 -1
  72. package/lib/typescript/lib/commonjs/ApiOverrides/index.d.ts.map +1 -1
  73. package/lib/typescript/lib/commonjs/BetRouter/api/index.d.ts +6 -0
  74. package/lib/typescript/lib/commonjs/BetRouter/api/index.d.ts.map +1 -1
  75. package/lib/typescript/lib/commonjs/BetRouter/components/ContestLiquidity.d.ts.map +1 -1
  76. package/lib/typescript/lib/commonjs/BetRouter/components/admin/LeagueInfo.d.ts.map +1 -1
  77. package/lib/typescript/lib/commonjs/BetRouter/components/admin/RouterMarkets.d.ts +4 -0
  78. package/lib/typescript/lib/commonjs/BetRouter/components/admin/RouterMarkets.d.ts.map +1 -0
  79. package/lib/typescript/lib/commonjs/BetRouter/layouts/DesktopAdminLayout.d.ts.map +1 -1
  80. package/lib/typescript/lib/commonjs/BetRouter/layouts/MobileAdminLayout.d.ts.map +1 -1
  81. package/lib/typescript/lib/commonjs/BetRouter/types/api-contracts.d.ts +77 -0
  82. package/lib/typescript/lib/commonjs/BetRouter/types/credentials.d.ts.map +1 -1
  83. package/lib/typescript/lib/commonjs/Components/ViewportObserver.d.ts.map +1 -1
  84. package/lib/typescript/lib/commonjs/ProfileManager/Components/BasicInfoManager.d.ts.map +1 -1
  85. package/lib/typescript/lib/commonjs/ProfileManager/Components/DOBManager.d.ts.map +1 -1
  86. package/lib/typescript/lib/commonjs/ProfileManager/Components/EmailManager.d.ts.map +1 -1
  87. package/lib/typescript/lib/commonjs/ProfileManager/Components/PhoneManager.d.ts.map +1 -1
  88. package/lib/typescript/lib/commonjs/ProfileManager/Components/VouchCard.d.ts.map +1 -1
  89. package/lib/typescript/lib/module/AdServer/api/index.d.ts.map +1 -1
  90. package/lib/typescript/lib/module/AdServer/index.d.ts +9 -0
  91. package/lib/typescript/lib/module/AdServer/index.d.ts.map +1 -1
  92. package/lib/typescript/lib/module/ApiOverrides/index.d.ts.map +1 -1
  93. package/lib/typescript/lib/module/BetRouter/api/index.d.ts +6 -0
  94. package/lib/typescript/lib/module/BetRouter/api/index.d.ts.map +1 -1
  95. package/lib/typescript/lib/module/BetRouter/components/ContestLiquidity.d.ts.map +1 -1
  96. package/lib/typescript/lib/module/BetRouter/components/admin/LeagueInfo.d.ts.map +1 -1
  97. package/lib/typescript/lib/module/BetRouter/components/admin/RouterMarkets.d.ts +4 -0
  98. package/lib/typescript/lib/module/BetRouter/components/admin/RouterMarkets.d.ts.map +1 -0
  99. package/lib/typescript/lib/module/BetRouter/layouts/DesktopAdminLayout.d.ts.map +1 -1
  100. package/lib/typescript/lib/module/BetRouter/layouts/MobileAdminLayout.d.ts.map +1 -1
  101. package/lib/typescript/lib/module/BetRouter/types/api-contracts.d.ts +77 -0
  102. package/lib/typescript/lib/module/BetRouter/types/api-contracts.d.ts.map +1 -1
  103. package/lib/typescript/lib/module/BetRouter/types/credentials.d.ts.map +1 -1
  104. package/lib/typescript/lib/module/Components/ViewportObserver.d.ts.map +1 -1
  105. package/lib/typescript/lib/module/ProfileManager/Components/BasicInfoManager.d.ts.map +1 -1
  106. package/lib/typescript/lib/module/ProfileManager/Components/DOBManager.d.ts.map +1 -1
  107. package/lib/typescript/lib/module/ProfileManager/Components/EmailManager.d.ts.map +1 -1
  108. package/lib/typescript/lib/module/ProfileManager/Components/PhoneManager.d.ts.map +1 -1
  109. package/lib/typescript/lib/module/ProfileManager/Components/VouchCard.d.ts.map +1 -1
  110. package/lib/typescript/src/AdServer/api/index.d.ts.map +1 -1
  111. package/lib/typescript/src/AdServer/index.d.ts +12 -3
  112. package/lib/typescript/src/AdServer/index.d.ts.map +1 -1
  113. package/lib/typescript/src/ApiOverrides/index.d.ts.map +1 -1
  114. package/lib/typescript/src/BetRouter/api/index.d.ts +23 -2
  115. package/lib/typescript/src/BetRouter/api/index.d.ts.map +1 -1
  116. package/lib/typescript/src/BetRouter/components/ContestLiquidity.d.ts.map +1 -1
  117. package/lib/typescript/src/BetRouter/components/admin/LeagueInfo.d.ts.map +1 -1
  118. package/lib/typescript/src/BetRouter/components/admin/RouterMarkets.d.ts +4 -0
  119. package/lib/typescript/src/BetRouter/components/admin/RouterMarkets.d.ts.map +1 -0
  120. package/lib/typescript/src/BetRouter/layouts/DesktopAdminLayout.d.ts.map +1 -1
  121. package/lib/typescript/src/BetRouter/layouts/MobileAdminLayout.d.ts.map +1 -1
  122. package/lib/typescript/src/BetRouter/types/api-contracts.d.ts +93 -4
  123. package/lib/typescript/src/BetRouter/types/api-contracts.d.ts.map +1 -1
  124. package/lib/typescript/src/BetRouter/types/credentials.d.ts +1 -5
  125. package/lib/typescript/src/BetRouter/types/credentials.d.ts.map +1 -1
  126. package/lib/typescript/src/Components/ViewportObserver.d.ts.map +1 -1
  127. package/lib/typescript/src/ProfileManager/Components/BasicInfoManager.d.ts.map +1 -1
  128. package/lib/typescript/src/ProfileManager/Components/DOBManager.d.ts.map +1 -1
  129. package/lib/typescript/src/ProfileManager/Components/EmailManager.d.ts.map +1 -1
  130. package/lib/typescript/src/ProfileManager/Components/PhoneManager.d.ts.map +1 -1
  131. package/lib/typescript/src/ProfileManager/Components/VouchCard.d.ts.map +1 -1
  132. package/package.json +1 -1
  133. package/src/AdServer/api/index.ts +4 -2
  134. package/src/AdServer/index.tsx +64 -22
  135. package/src/ApiOverrides/index.ts +3 -2
  136. package/src/BetRouter/api/index.ts +101 -2
  137. package/src/BetRouter/components/ContestLiquidity.tsx +78 -11
  138. package/src/BetRouter/components/admin/LeagueInfo.tsx +231 -3
  139. package/src/BetRouter/components/admin/RouterMarkets.tsx +1238 -0
  140. package/src/BetRouter/layouts/DesktopAdminLayout.tsx +24 -1
  141. package/src/BetRouter/layouts/MobileAdminLayout.tsx +30 -2
  142. package/src/BetRouter/types/api-contracts.ts +100 -2
  143. package/src/BetRouter/types/credentials.ts +5 -6
  144. package/src/Components/ViewportObserver.tsx +13 -2
  145. package/src/ProfileManager/Components/BasicInfoManager.tsx +15 -2
  146. package/src/ProfileManager/Components/DOBManager.tsx +14 -1
  147. package/src/ProfileManager/Components/EmailManager.tsx +16 -1
  148. package/src/ProfileManager/Components/PhoneManager.tsx +14 -0
  149. package/src/ProfileManager/Components/VouchCard.tsx +12 -4
  150. package/src/types.d.ts +3 -3
@@ -67,6 +67,7 @@ const ContestLiquidity = ({
67
67
 
68
68
  const [selectedMarketId, setSelectedMarketId] = useState<string>('');
69
69
  const [selectedVariableId, setSelectedVariableId] = useState<string>('');
70
+ const [inverseVariableId, setInverseVariableId] = useState<string>('');
70
71
  const [selectedOpportunity, setSelectedOpportunity] = useState<BuyOpportunity | null>(null);
71
72
  const [modalVisible, setModalVisible] = useState(false);
72
73
 
@@ -144,7 +145,7 @@ const ContestLiquidity = ({
144
145
  // For spread markets, only show home side variables
145
146
  // For total markets, only show under side variables
146
147
  const linkedVariableIds = new Set<string>();
147
- const uniqueVariableValues = new Map<number, string>(); // absolute value -> variable_id
148
+ const uniqueVariableValues = new Map<number, string>(); // variable value (with sign) -> variable_id
148
149
 
149
150
  // First, find the home side and under side for this market
150
151
  const homeSide = sides.find(s => s.side_key.toLowerCase() === 'home');
@@ -166,9 +167,10 @@ const ContestLiquidity = ({
166
167
  : true;
167
168
 
168
169
  if (isCorrectSide) {
169
- const absValue = Math.abs(variable.variable);
170
- if (!uniqueVariableValues.has(absValue)) {
171
- uniqueVariableValues.set(absValue, variable.router_market_variable_id);
170
+ // Use the actual variable value (with sign) as the key to preserve both positive and negative values
171
+ const variableValue = variable.variable;
172
+ if (!uniqueVariableValues.has(variableValue)) {
173
+ uniqueVariableValues.set(variableValue, variable.router_market_variable_id);
172
174
  }
173
175
  }
174
176
  }
@@ -180,11 +182,30 @@ const ContestLiquidity = ({
180
182
  .map(id => data.router_market_variables.find(v => v.router_market_variable_id === id))
181
183
  .filter(v => v !== undefined) as RouterMarketVariableProps[];
182
184
 
185
+ // Sort variables ascending by value
186
+ variables.sort((a, b) => Number(a.variable) - Number(b.variable));
187
+
183
188
  // Auto-select first variable if not selected
184
189
  let currentVariableId = selectedVariableId;
190
+ let currentInverseVariableId = inverseVariableId;
185
191
  if (variables[0] && router_market.variable_required && variables.length > 0 && !currentVariableId) {
186
192
  currentVariableId = variables[0].router_market_variable_id;
187
193
  setSelectedVariableId(currentVariableId);
194
+
195
+ // For spread markets, find and store the inverse variable
196
+ const selectedVar = data.router_market_variables.find(v => v.router_market_variable_id === currentVariableId);
197
+ if (selectedVar && selectedVar.variable_type === 'spread') {
198
+ const inverseValue = -Number(selectedVar.variable);
199
+ const inverseVar = data.router_market_variables.find(v =>
200
+ v.router_market_id === selectedMarketId &&
201
+ Number(v.variable) === inverseValue &&
202
+ v.variable_type === 'spread'
203
+ );
204
+ if (inverseVar) {
205
+ currentInverseVariableId = inverseVar.router_market_variable_id;
206
+ setInverseVariableId(currentInverseVariableId);
207
+ }
208
+ }
188
209
  }
189
210
 
190
211
  // Build partner rows
@@ -200,14 +221,27 @@ const ContestLiquidity = ({
200
221
  const currentVariable = data.router_market_variables.find(v => v.router_market_variable_id === partner_market.router_market_variable_id);
201
222
 
202
223
  if (selectedVariable && currentVariable) {
203
- // For spread markets, match both +/- versions (e.g., -7 and +7)
204
224
  if (selectedVariable.variable_type === 'spread') {
205
- if (Math.abs(selectedVariable.variable) !== Math.abs(currentVariable.variable)) {
206
- return; // Different absolute values, skip
225
+ // For spread markets, match using stored variable IDs
226
+ // Get the side for this partner market
227
+ const currentSide = sides.find(s => s.market_side_id === partner_market.market_side_id);
228
+ const homeSide = sides.find(s => s.side_key.toLowerCase() === 'home');
229
+ const isHomeSide = currentSide?.market_side_id === homeSide?.market_side_id;
230
+
231
+ if (isHomeSide) {
232
+ // For home side, must match selected variable ID
233
+ if (partner_market.router_market_variable_id !== currentVariableId) {
234
+ return;
235
+ }
236
+ } else {
237
+ // For away side, must match inverse variable ID
238
+ if (!currentInverseVariableId || partner_market.router_market_variable_id !== currentInverseVariableId) {
239
+ return;
240
+ }
207
241
  }
208
242
  } else {
209
- // For totals, must match exactly
210
- if (selectedVariable.variable !== currentVariable.variable) {
243
+ // For totals and other markets, must match exactly by variable ID
244
+ if (partner_market.router_market_variable_id !== currentVariableId) {
211
245
  return;
212
246
  }
213
247
  }
@@ -217,6 +251,9 @@ const ContestLiquidity = ({
217
251
  const partner = data.partners.find(p => p.partner_id === partner_market.partner_id);
218
252
  if (!partner) return;
219
253
 
254
+ // Use the title from the liquidity object
255
+ const title = liq.title;
256
+
220
257
  if (!partnerRowsMap.has(partner.partner_id)) {
221
258
  partnerRowsMap.set(partner.partner_id, {
222
259
  partner,
@@ -226,7 +263,7 @@ const ContestLiquidity = ({
226
263
 
227
264
  partnerRowsMap.get(partner.partner_id)!.sidePrices.set(
228
265
  partner_market.market_side_id,
229
- { title: liq.title, price: liq.price, available: liq.available }
266
+ { title, price: liq.price, available: liq.available }
230
267
  );
231
268
  });
232
269
 
@@ -463,6 +500,7 @@ const ContestLiquidity = ({
463
500
  if (market) {
464
501
  setSelectedMarketId(market.router_market_id);
465
502
  setSelectedVariableId(''); // Reset variable selection
503
+ setInverseVariableId(''); // Reset inverse variable
466
504
  }
467
505
  }}
468
506
  />
@@ -499,7 +537,36 @@ const ContestLiquidity = ({
499
537
  borderColor: isSelected ? Colors.text.success : Colors.borders.light,
500
538
  backgroundColor: isSelected ? Colors.views.header : 'transparent'
501
539
  }}
502
- onPress={() => setSelectedVariableId(variable.router_market_variable_id)}
540
+ onPress={() => {
541
+ console.log('Variable button clicked:', variable);
542
+ setSelectedVariableId(variable.router_market_variable_id);
543
+
544
+ // For spread markets, find and store the inverse variable
545
+ if (variable.variable_type === 'spread' && data) {
546
+ const inverseValue = -Number(variable.variable);
547
+ console.log('Button click - Looking for inverse:', { selectedValue: variable.variable, inverseValue });
548
+ console.log('Button click - All market variables:', data.router_market_variables.filter(v => v.router_market_id === variable.router_market_id).map(v => ({
549
+ id: v.router_market_variable_id,
550
+ value: v.variable,
551
+ type: v.variable_type
552
+ })));
553
+ const inverseVar = data.router_market_variables.find(v =>
554
+ v.router_market_id === variable.router_market_id &&
555
+ Number(v.variable) === inverseValue &&
556
+ v.variable_type === 'spread'
557
+ );
558
+ console.log('Button click - Found inverse var?', inverseVar);
559
+ if (inverseVar) {
560
+ console.log('Setting inverse variable ID:', inverseVar.router_market_variable_id);
561
+ setInverseVariableId(inverseVar.router_market_variable_id);
562
+ } else {
563
+ console.warn('Button click - Inverse variable NOT found!');
564
+ setInverseVariableId('');
565
+ }
566
+ } else {
567
+ setInverseVariableId('');
568
+ }
569
+ }}
503
570
  >
504
571
  <Text
505
572
  theme='h2'
@@ -1,16 +1,19 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import { View, Text, Button } from "../../../Components/Themed";
3
- import { ActivityIndicator } from 'react-native';
3
+ import { ActivityIndicator, Modal, ScrollView, TouchableOpacity } from 'react-native';
4
4
  import { useColors } from '../../../constants/useColors';
5
5
  import { getPartners, getContests, getParticipants } from '../../api';
6
6
  import { BetRouterApi } from '../../api';
7
+ import { SearchBox } from '../../../Components';
8
+ import Pagination from '../../../Components/Pagination';
7
9
  import type {
8
10
  RouterLeagueProps,
9
11
  RouterPartnerProps,
10
12
  RouterContestProps,
11
13
  RouterParticipantProps,
12
14
  //PartnerContestProps,
13
- PartnerLeagueProps
15
+ PartnerLeagueProps,
16
+ RawLeagueProps
14
17
  } from '../../types';
15
18
 
16
19
  type LeagueInfoProps = {
@@ -23,8 +26,15 @@ const LeagueInfo = ({ league }: LeagueInfoProps) => {
23
26
  const [loading, setLoading] = useState(true);
24
27
  const [partners, setPartners] = useState<RouterPartnerProps[]>([]);
25
28
  const [partnerLeagues, setPartnerLeagues] = useState<PartnerLeagueProps[]>([]);
29
+ const [rawLeagues, setRawLeagues] = useState<RawLeagueProps[]>([]);
26
30
  const [contests, setContests] = useState<RouterContestProps[]>([]);
27
31
  const [participants, setParticipants] = useState<RouterParticipantProps[]>([]);
32
+ const [showLinkModal, setShowLinkModal] = useState(false);
33
+ const [selectedPartner, setSelectedPartner] = useState<RouterPartnerProps | null>(null);
34
+ const [selectedRawLeagues, setSelectedRawLeagues] = useState<string[]>([]);
35
+ const [linkModalSearch, setLinkModalSearch] = useState('');
36
+ const [linkModalPage, setLinkModalPage] = useState(0);
37
+ const ITEMS_PER_PAGE = 10;
28
38
 
29
39
  useEffect(() => {
30
40
  loadLeagueData();
@@ -52,6 +62,11 @@ const LeagueInfo = ({ league }: LeagueInfoProps) => {
52
62
  setPartnerLeagues(filteredPartnerLeagues);
53
63
  }
54
64
 
65
+ // Store raw leagues
66
+ if (leaguesDataRes && leaguesDataRes.raw_leagues) {
67
+ setRawLeagues(leaguesDataRes.raw_leagues);
68
+ }
69
+
55
70
  if (Array.isArray(contestsRes)) {
56
71
  setContests(contestsRes.filter(c => c.router_league_id === league.router_league_id));
57
72
  }
@@ -77,6 +92,48 @@ const LeagueInfo = ({ league }: LeagueInfoProps) => {
77
92
  }
78
93
  };
79
94
 
95
+ const openLinkModal = (partner: RouterPartnerProps) => {
96
+ setSelectedPartner(partner);
97
+ setShowLinkModal(true);
98
+ setSelectedRawLeagues([]);
99
+ setLinkModalSearch('');
100
+ setLinkModalPage(0);
101
+ };
102
+
103
+ const handleLinkLeagues = async () => {
104
+ if (!selectedPartner || selectedRawLeagues.length === 0) {
105
+ alert('Please select at least one league to link');
106
+ return;
107
+ }
108
+
109
+ try {
110
+ setLoading(true);
111
+ const result = await BetRouterApi.BetRouter.LeagueApi.linkLeague(
112
+ selectedRawLeagues,
113
+ league.router_league_id
114
+ );
115
+ alert(`Successfully linked ${result.partnerLeagues.length} league(s) for ${selectedPartner.name}`);
116
+ setShowLinkModal(false);
117
+ setSelectedRawLeagues([]);
118
+ // Reload to show updated counts
119
+ await loadLeagueData();
120
+ } catch (error) {
121
+ console.error('Failed to link leagues:', error);
122
+ alert('Error linking leagues: ' + (error as any).message);
123
+ setLoading(false);
124
+ }
125
+ };
126
+
127
+ const toggleRawLeagueSelection = (rawLeagueId: string) => {
128
+ setSelectedRawLeagues(prev => {
129
+ if (prev.includes(rawLeagueId)) {
130
+ return prev.filter(id => id !== rawLeagueId);
131
+ } else {
132
+ return [...prev, rawLeagueId];
133
+ }
134
+ });
135
+ };
136
+
80
137
  if (loading) {
81
138
  return (
82
139
  <View transparent style={{ padding: 40, alignItems: 'center' }}>
@@ -204,7 +261,7 @@ const LeagueInfo = ({ league }: LeagueInfoProps) => {
204
261
  <Button
205
262
  type='action'
206
263
  title='Link'
207
- onPress={() => alert(`Link raw leagues for ${partner.name} - Coming soon!`)}
264
+ onPress={() => openLinkModal(partner)}
208
265
  style={{ paddingHorizontal: 12, paddingVertical: 6 }}
209
266
  />
210
267
  </View>
@@ -246,6 +303,177 @@ const LeagueInfo = ({ league }: LeagueInfoProps) => {
246
303
  </View>
247
304
  </View>
248
305
  </View>
306
+
307
+ {/* Link Leagues Modal */}
308
+ <Modal
309
+ visible={showLinkModal}
310
+ transparent
311
+ animationType="fade"
312
+ onRequestClose={() => setShowLinkModal(false)}
313
+ >
314
+ <View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', alignItems: 'center' }}>
315
+ <View style={{ backgroundColor: Colors.views.body, borderRadius: 12, padding: 24, width: '90%', maxWidth: 600 }}>
316
+ <Text theme="h1" size={20} style={{ marginBottom: 12 }}>
317
+ Link Leagues - {selectedPartner?.name}
318
+ </Text>
319
+ <Text theme="description" size={14} style={{ marginBottom: 16 }}>
320
+ Select raw leagues from {selectedPartner?.name} to link to {league.name}
321
+ </Text>
322
+
323
+ {/* Search Box */}
324
+ <View transparent style={{ marginBottom: 16 }}>
325
+ <SearchBox
326
+ placeholder="Search leagues..."
327
+ onChange={(text) => {
328
+ setLinkModalSearch(text);
329
+ setLinkModalPage(0); // Reset to first page on search
330
+ }}
331
+ hide_search_button
332
+ />
333
+ </View>
334
+
335
+ {(() => {
336
+ // Filter raw leagues by selected partner
337
+ let partnerRawLeagues = rawLeagues.filter(rl => rl.partner_id === selectedPartner?.partner_id);
338
+
339
+ // Apply search filter
340
+ if (linkModalSearch) {
341
+ partnerRawLeagues = partnerRawLeagues.filter(rl =>
342
+ rl.name.toLowerCase().includes(linkModalSearch.toLowerCase()) ||
343
+ rl.external_id.toLowerCase().includes(linkModalSearch.toLowerCase())
344
+ );
345
+ }
346
+
347
+ if (partnerRawLeagues.length === 0) {
348
+ return (
349
+ <View transparent style={{ padding: 40, alignItems: 'center' }}>
350
+ <Text theme="description" size={14}>
351
+ {linkModalSearch
352
+ ? `No leagues found matching "${linkModalSearch}"`
353
+ : `No raw leagues found for ${selectedPartner?.name}. Try loading raw leagues first from the partner.`
354
+ }
355
+ </Text>
356
+ </View>
357
+ );
358
+ }
359
+
360
+ // Calculate pagination
361
+ const totalPages = Math.ceil(partnerRawLeagues.length / ITEMS_PER_PAGE);
362
+ const startIndex = linkModalPage * ITEMS_PER_PAGE;
363
+ const endIndex = startIndex + ITEMS_PER_PAGE;
364
+ const paginatedLeagues = partnerRawLeagues.slice(startIndex, endIndex);
365
+
366
+ return (
367
+ <>
368
+ <ScrollView style={{ maxHeight: 400 }}>
369
+ <View transparent style={{ gap: 8 }}>
370
+ {paginatedLeagues.map((rawLeague) => {
371
+ const isSelected = selectedRawLeagues.includes(rawLeague.raw_league_id);
372
+ const isAlreadyLinked = partnerLeagues.some(
373
+ pl => pl.raw_league_id === rawLeague.raw_league_id && pl.router_league_id === league.router_league_id
374
+ );
375
+
376
+ return (
377
+ <TouchableOpacity
378
+ key={rawLeague.raw_league_id}
379
+ onPress={() => !isAlreadyLinked && toggleRawLeagueSelection(rawLeague.raw_league_id)}
380
+ disabled={isAlreadyLinked}
381
+ style={{
382
+ padding: 12,
383
+ backgroundColor: isAlreadyLinked ? Colors.views.header : (isSelected ? Colors.views.body : Colors.views.header),
384
+ borderRadius: 6,
385
+ borderWidth: 2,
386
+ borderColor: isAlreadyLinked ? Colors.borders.light : (isSelected ? Colors.views.body : Colors.borders.light),
387
+ opacity: isAlreadyLinked ? 0.5 : 1,
388
+ flexDirection: 'row',
389
+ alignItems: 'center',
390
+ justifyContent: 'space-between'
391
+ }}
392
+ >
393
+ <View transparent style={{ flex: 1 }}>
394
+ <Text theme="h2" size={14}>
395
+ {rawLeague.name}
396
+ </Text>
397
+ <Text theme="description" size={11} style={{ marginTop: 2 }}>
398
+ {rawLeague.external_id}
399
+ </Text>
400
+ </View>
401
+ {isAlreadyLinked && (
402
+ <View
403
+ transparent
404
+ style={{
405
+ paddingHorizontal: 8,
406
+ paddingVertical: 4,
407
+ borderRadius: 4,
408
+ backgroundColor: Colors.text.success
409
+ }}
410
+ >
411
+ <Text theme="h2" size={10} style={{ color: '#fff' }}>
412
+ Already Linked
413
+ </Text>
414
+ </View>
415
+ )}
416
+ {isSelected && !isAlreadyLinked && (
417
+ <View
418
+ transparent
419
+ style={{
420
+ width: 20,
421
+ height: 20,
422
+ borderRadius: 10,
423
+ backgroundColor: '#fff',
424
+ justifyContent: 'center',
425
+ alignItems: 'center'
426
+ }}
427
+ >
428
+ <Text theme="h2" size={12}>✓</Text>
429
+ </View>
430
+ )}
431
+ </TouchableOpacity>
432
+ );
433
+ })}
434
+ </View>
435
+ </ScrollView>
436
+
437
+ {/* Pagination */}
438
+ {totalPages > 1 && (
439
+ <View transparent style={{ marginTop: 16 }}>
440
+ <Pagination
441
+ offset={linkModalPage}
442
+ pages={totalPages}
443
+ onPrevious={() => setLinkModalPage(prev => Math.max(0, prev - 1))}
444
+ onNext={() => setLinkModalPage(prev => Math.min(totalPages - 1, prev + 1))}
445
+ onSelectPage={(page) => setLinkModalPage(page)}
446
+ />
447
+ </View>
448
+ )}
449
+
450
+ {/* Results count */}
451
+ <View transparent style={{ marginTop: 8, alignItems: 'center' }}>
452
+ <Text theme="description" size={12}>
453
+ Showing {startIndex + 1}-{Math.min(endIndex, partnerRawLeagues.length)} of {partnerRawLeagues.length} league(s)
454
+ </Text>
455
+ </View>
456
+ </>
457
+ );
458
+ })()}
459
+
460
+ <View transparent style={{ flexDirection: 'row', gap: 12, marginTop: 24 }}>
461
+ <Button
462
+ type="close"
463
+ title="Cancel"
464
+ onPress={() => setShowLinkModal(false)}
465
+ style={{ flex: 1 }}
466
+ />
467
+ <Button
468
+ type="success"
469
+ title={`Link ${selectedRawLeagues.length} League(s)`}
470
+ onPress={handleLinkLeagues}
471
+ style={{ flex: 1 }}
472
+ />
473
+ </View>
474
+ </View>
475
+ </View>
476
+ </Modal>
249
477
  </View>
250
478
  );
251
479
  };