be-components 7.4.7 → 7.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (596) hide show
  1. package/lib/commonjs/ApiOverrides/index.js +4 -0
  2. package/lib/commonjs/ApiOverrides/index.js.map +1 -1
  3. package/lib/commonjs/BetRouter/api/index.js +884 -0
  4. package/lib/commonjs/BetRouter/api/index.js.map +1 -0
  5. package/lib/commonjs/BetRouter/api/types.js +2 -0
  6. package/lib/commonjs/BetRouter/api/types.js.map +1 -0
  7. package/lib/commonjs/BetRouter/components/AccountManager.js +592 -0
  8. package/lib/commonjs/BetRouter/components/AccountManager.js.map +1 -0
  9. package/lib/commonjs/BetRouter/components/AdminPortal.js +51 -0
  10. package/lib/commonjs/BetRouter/components/AdminPortal.js.map +1 -0
  11. package/lib/commonjs/BetRouter/components/BuyOpportunities.js +550 -0
  12. package/lib/commonjs/BetRouter/components/BuyOpportunities.js.map +1 -0
  13. package/lib/commonjs/BetRouter/components/BuyOpportunityCard.js +320 -0
  14. package/lib/commonjs/BetRouter/components/BuyOpportunityCard.js.map +1 -0
  15. package/lib/commonjs/BetRouter/components/ContestLiquidity.js +666 -0
  16. package/lib/commonjs/BetRouter/components/ContestLiquidity.js.map +1 -0
  17. package/lib/commonjs/BetRouter/components/ContestSelector.js +193 -0
  18. package/lib/commonjs/BetRouter/components/ContestSelector.js.map +1 -0
  19. package/lib/commonjs/BetRouter/components/MyOpportunities.js +332 -0
  20. package/lib/commonjs/BetRouter/components/MyOpportunities.js.map +1 -0
  21. package/lib/commonjs/BetRouter/components/MyOpportunities.tsx.bak +440 -0
  22. package/lib/commonjs/BetRouter/components/OpportunityDetailModal.js +545 -0
  23. package/lib/commonjs/BetRouter/components/OpportunityDetailModal.js.map +1 -0
  24. package/lib/commonjs/BetRouter/components/OpportunityHistory.js +489 -0
  25. package/lib/commonjs/BetRouter/components/OpportunityHistory.js.map +1 -0
  26. package/lib/commonjs/BetRouter/components/PartnerCredentials.js +229 -0
  27. package/lib/commonjs/BetRouter/components/PartnerCredentials.js.map +1 -0
  28. package/lib/commonjs/BetRouter/components/PlacedOpportunityModal.js +262 -0
  29. package/lib/commonjs/BetRouter/components/PlacedOpportunityModal.js.map +1 -0
  30. package/lib/commonjs/BetRouter/components/admin/AutoFillView.js +380 -0
  31. package/lib/commonjs/BetRouter/components/admin/AutoFillView.js.map +1 -0
  32. package/lib/commonjs/BetRouter/components/admin/ConfigManager.js +814 -0
  33. package/lib/commonjs/BetRouter/components/admin/ConfigManager.js.map +1 -0
  34. package/lib/commonjs/BetRouter/components/admin/JobManager.js +895 -0
  35. package/lib/commonjs/BetRouter/components/admin/JobManager.js.map +1 -0
  36. package/lib/commonjs/BetRouter/components/admin/LeagueContests.js +2844 -0
  37. package/lib/commonjs/BetRouter/components/admin/LeagueContests.js.map +1 -0
  38. package/lib/commonjs/BetRouter/components/admin/LeagueInfo.js +378 -0
  39. package/lib/commonjs/BetRouter/components/admin/LeagueInfo.js.map +1 -0
  40. package/lib/commonjs/BetRouter/components/admin/LeagueParticipants.js +795 -0
  41. package/lib/commonjs/BetRouter/components/admin/LeagueParticipants.js.map +1 -0
  42. package/lib/commonjs/BetRouter/index.js +411 -0
  43. package/lib/commonjs/BetRouter/index.js.map +1 -0
  44. package/lib/commonjs/BetRouter/layouts/DesktopAdminLayout.js +312 -0
  45. package/lib/commonjs/BetRouter/layouts/DesktopAdminLayout.js.map +1 -0
  46. package/lib/commonjs/BetRouter/layouts/DesktopLayout.js +271 -0
  47. package/lib/commonjs/BetRouter/layouts/DesktopLayout.js.map +1 -0
  48. package/lib/commonjs/BetRouter/layouts/MobileAdminLayout.js +435 -0
  49. package/lib/commonjs/BetRouter/layouts/MobileAdminLayout.js.map +1 -0
  50. package/lib/commonjs/BetRouter/layouts/MobileLayout.js +293 -0
  51. package/lib/commonjs/BetRouter/layouts/MobileLayout.js.map +1 -0
  52. package/lib/commonjs/BetRouter/types/ADMIN_PORTAL.md +863 -0
  53. package/lib/commonjs/BetRouter/types/ADMIN_PORTAL_SIMPLIFIED.md +1881 -0
  54. package/lib/commonjs/BetRouter/types/CREDENTIALS_EXAMPLE.md +350 -0
  55. package/lib/commonjs/BetRouter/types/LIQUIDITY_CLIENT_GUIDE.md +399 -0
  56. package/lib/commonjs/BetRouter/types/MARKET_LINKING_WORKFLOW.md +682 -0
  57. package/lib/commonjs/BetRouter/types/MARKET_LINKING_WORKFLOW_V2.md +627 -0
  58. package/lib/commonjs/BetRouter/types/README.md +249 -0
  59. package/lib/commonjs/BetRouter/types/accounts.js +2 -0
  60. package/lib/commonjs/BetRouter/types/accounts.js.map +1 -0
  61. package/lib/commonjs/BetRouter/types/api-contracts.js +776 -0
  62. package/lib/commonjs/BetRouter/types/api-contracts.js.map +1 -0
  63. package/lib/commonjs/BetRouter/types/config.js +2 -0
  64. package/lib/commonjs/BetRouter/types/config.js.map +1 -0
  65. package/lib/commonjs/BetRouter/types/contests.js +2 -0
  66. package/lib/commonjs/BetRouter/types/contests.js.map +1 -0
  67. package/lib/commonjs/BetRouter/types/credentials.js +90 -0
  68. package/lib/commonjs/BetRouter/types/credentials.js.map +1 -0
  69. package/lib/commonjs/BetRouter/types/index.js +149 -0
  70. package/lib/commonjs/BetRouter/types/index.js.map +1 -0
  71. package/lib/commonjs/BetRouter/types/jobs.js +2 -0
  72. package/lib/commonjs/BetRouter/types/jobs.js.map +1 -0
  73. package/lib/commonjs/BetRouter/types/leagues.js +2 -0
  74. package/lib/commonjs/BetRouter/types/leagues.js.map +1 -0
  75. package/lib/commonjs/BetRouter/types/liquidity.js +2 -0
  76. package/lib/commonjs/BetRouter/types/liquidity.js.map +1 -0
  77. package/lib/commonjs/BetRouter/types/markets.js +2 -0
  78. package/lib/commonjs/BetRouter/types/markets.js.map +1 -0
  79. package/lib/commonjs/BetRouter/types/opportunities.js +6 -0
  80. package/lib/commonjs/BetRouter/types/opportunities.js.map +1 -0
  81. package/lib/commonjs/BetRouter/types/orders.js +2 -0
  82. package/lib/commonjs/BetRouter/types/orders.js.map +1 -0
  83. package/lib/commonjs/BetRouter/types/participants.js +2 -0
  84. package/lib/commonjs/BetRouter/types/participants.js.map +1 -0
  85. package/lib/commonjs/BetRouter/types/partners.js +2 -0
  86. package/lib/commonjs/BetRouter/types/partners.js.map +1 -0
  87. package/lib/commonjs/Charts/README.md +310 -0
  88. package/lib/commonjs/Charts/adapters/TradeChartAdapter.js +406 -0
  89. package/lib/commonjs/Charts/adapters/TradeChartAdapter.js.map +1 -0
  90. package/lib/commonjs/Charts/components/BaseLineChart.js +285 -0
  91. package/lib/commonjs/Charts/components/BaseLineChart.js.map +1 -0
  92. package/lib/commonjs/Charts/components/LivePriceChart.js +504 -0
  93. package/lib/commonjs/Charts/components/LivePriceChart.js.map +1 -0
  94. package/lib/commonjs/Charts/index.js +126 -0
  95. package/lib/commonjs/Charts/index.js.map +1 -0
  96. package/lib/commonjs/Charts/themes/chartTheme.js +141 -0
  97. package/lib/commonjs/Charts/themes/chartTheme.js.map +1 -0
  98. package/lib/commonjs/Charts/types.js +2 -0
  99. package/lib/commonjs/Charts/types.js.map +1 -0
  100. package/lib/commonjs/Charts/utils/formatters.js +194 -0
  101. package/lib/commonjs/Charts/utils/formatters.js.map +1 -0
  102. package/lib/commonjs/Components/Dropdown.js +5 -3
  103. package/lib/commonjs/Components/Dropdown.js.map +1 -1
  104. package/lib/commonjs/Components/Icons.js +24 -0
  105. package/lib/commonjs/Components/Icons.js.map +1 -1
  106. package/lib/commonjs/Components/index.js +34 -0
  107. package/lib/commonjs/Components/index.js.map +1 -1
  108. package/lib/commonjs/LocationTracker/LocationStatus.js +5 -2
  109. package/lib/commonjs/LocationTracker/LocationStatus.js.map +1 -1
  110. package/lib/commonjs/LocationTracker/api/index.js +2 -2
  111. package/lib/commonjs/LocationTracker/api/index.js.map +1 -1
  112. package/lib/commonjs/index.js +28 -0
  113. package/lib/commonjs/index.js.map +1 -1
  114. package/lib/commonjs/types.d.js +16 -0
  115. package/lib/commonjs/types.d.js.map +1 -1
  116. package/lib/module/ApiOverrides/index.js +4 -0
  117. package/lib/module/ApiOverrides/index.js.map +1 -1
  118. package/lib/module/BetRouter/api/index.js +873 -0
  119. package/lib/module/BetRouter/api/index.js.map +1 -0
  120. package/lib/module/BetRouter/api/types.js +2 -0
  121. package/lib/module/BetRouter/api/types.js.map +1 -0
  122. package/lib/module/BetRouter/components/AccountManager.js +584 -0
  123. package/lib/module/BetRouter/components/AccountManager.js.map +1 -0
  124. package/lib/module/BetRouter/components/AdminPortal.js +43 -0
  125. package/lib/module/BetRouter/components/AdminPortal.js.map +1 -0
  126. package/lib/module/BetRouter/components/BuyOpportunities.js +542 -0
  127. package/lib/module/BetRouter/components/BuyOpportunities.js.map +1 -0
  128. package/lib/module/BetRouter/components/BuyOpportunityCard.js +313 -0
  129. package/lib/module/BetRouter/components/BuyOpportunityCard.js.map +1 -0
  130. package/lib/module/BetRouter/components/ContestLiquidity.js +658 -0
  131. package/lib/module/BetRouter/components/ContestLiquidity.js.map +1 -0
  132. package/lib/module/BetRouter/components/ContestSelector.js +185 -0
  133. package/lib/module/BetRouter/components/ContestSelector.js.map +1 -0
  134. package/lib/module/BetRouter/components/MyOpportunities.js +324 -0
  135. package/lib/module/BetRouter/components/MyOpportunities.js.map +1 -0
  136. package/lib/module/BetRouter/components/MyOpportunities.tsx.bak +440 -0
  137. package/lib/module/BetRouter/components/OpportunityDetailModal.js +538 -0
  138. package/lib/module/BetRouter/components/OpportunityDetailModal.js.map +1 -0
  139. package/lib/module/BetRouter/components/OpportunityHistory.js +481 -0
  140. package/lib/module/BetRouter/components/OpportunityHistory.js.map +1 -0
  141. package/lib/module/BetRouter/components/PartnerCredentials.js +222 -0
  142. package/lib/module/BetRouter/components/PartnerCredentials.js.map +1 -0
  143. package/lib/module/BetRouter/components/PlacedOpportunityModal.js +255 -0
  144. package/lib/module/BetRouter/components/PlacedOpportunityModal.js.map +1 -0
  145. package/lib/module/BetRouter/components/admin/AutoFillView.js +372 -0
  146. package/lib/module/BetRouter/components/admin/AutoFillView.js.map +1 -0
  147. package/lib/module/BetRouter/components/admin/ConfigManager.js +806 -0
  148. package/lib/module/BetRouter/components/admin/ConfigManager.js.map +1 -0
  149. package/lib/module/BetRouter/components/admin/JobManager.js +888 -0
  150. package/lib/module/BetRouter/components/admin/JobManager.js.map +1 -0
  151. package/lib/module/BetRouter/components/admin/LeagueContests.js +2836 -0
  152. package/lib/module/BetRouter/components/admin/LeagueContests.js.map +1 -0
  153. package/lib/module/BetRouter/components/admin/LeagueInfo.js +372 -0
  154. package/lib/module/BetRouter/components/admin/LeagueInfo.js.map +1 -0
  155. package/lib/module/BetRouter/components/admin/LeagueParticipants.js +787 -0
  156. package/lib/module/BetRouter/components/admin/LeagueParticipants.js.map +1 -0
  157. package/lib/module/BetRouter/index.js +399 -0
  158. package/lib/module/BetRouter/index.js.map +1 -0
  159. package/lib/module/BetRouter/layouts/DesktopAdminLayout.js +304 -0
  160. package/lib/module/BetRouter/layouts/DesktopAdminLayout.js.map +1 -0
  161. package/lib/module/BetRouter/layouts/DesktopLayout.js +263 -0
  162. package/lib/module/BetRouter/layouts/DesktopLayout.js.map +1 -0
  163. package/lib/module/BetRouter/layouts/MobileAdminLayout.js +427 -0
  164. package/lib/module/BetRouter/layouts/MobileAdminLayout.js.map +1 -0
  165. package/lib/module/BetRouter/layouts/MobileLayout.js +285 -0
  166. package/lib/module/BetRouter/layouts/MobileLayout.js.map +1 -0
  167. package/lib/module/BetRouter/types/ADMIN_PORTAL.md +863 -0
  168. package/lib/module/BetRouter/types/ADMIN_PORTAL_SIMPLIFIED.md +1881 -0
  169. package/lib/module/BetRouter/types/CREDENTIALS_EXAMPLE.md +350 -0
  170. package/lib/module/BetRouter/types/LIQUIDITY_CLIENT_GUIDE.md +399 -0
  171. package/lib/module/BetRouter/types/MARKET_LINKING_WORKFLOW.md +682 -0
  172. package/lib/module/BetRouter/types/MARKET_LINKING_WORKFLOW_V2.md +627 -0
  173. package/lib/module/BetRouter/types/README.md +249 -0
  174. package/lib/module/BetRouter/types/accounts.js +2 -0
  175. package/lib/module/BetRouter/types/accounts.js.map +1 -0
  176. package/lib/module/BetRouter/types/api-contracts.js +770 -0
  177. package/lib/module/BetRouter/types/api-contracts.js.map +1 -0
  178. package/lib/module/BetRouter/types/config.js +2 -0
  179. package/lib/module/BetRouter/types/config.js.map +1 -0
  180. package/lib/module/BetRouter/types/contests.js +2 -0
  181. package/lib/module/BetRouter/types/contests.js.map +1 -0
  182. package/lib/module/BetRouter/types/credentials.js +78 -0
  183. package/lib/module/BetRouter/types/credentials.js.map +1 -0
  184. package/lib/module/BetRouter/types/index.js +17 -0
  185. package/lib/module/BetRouter/types/index.js.map +1 -0
  186. package/lib/module/BetRouter/types/jobs.js +2 -0
  187. package/lib/module/BetRouter/types/jobs.js.map +1 -0
  188. package/lib/module/BetRouter/types/leagues.js +2 -0
  189. package/lib/module/BetRouter/types/leagues.js.map +1 -0
  190. package/lib/module/BetRouter/types/liquidity.js +2 -0
  191. package/lib/module/BetRouter/types/liquidity.js.map +1 -0
  192. package/lib/module/BetRouter/types/markets.js +2 -0
  193. package/lib/module/BetRouter/types/markets.js.map +1 -0
  194. package/lib/module/BetRouter/types/opportunities.js +2 -0
  195. package/lib/module/BetRouter/types/opportunities.js.map +1 -0
  196. package/lib/module/BetRouter/types/orders.js +2 -0
  197. package/lib/module/BetRouter/types/orders.js.map +1 -0
  198. package/lib/module/BetRouter/types/participants.js +2 -0
  199. package/lib/module/BetRouter/types/participants.js.map +1 -0
  200. package/lib/module/BetRouter/types/partners.js +2 -0
  201. package/lib/module/BetRouter/types/partners.js.map +1 -0
  202. package/lib/module/Charts/README.md +310 -0
  203. package/lib/module/Charts/adapters/TradeChartAdapter.js +400 -0
  204. package/lib/module/Charts/adapters/TradeChartAdapter.js.map +1 -0
  205. package/lib/module/Charts/components/BaseLineChart.js +281 -0
  206. package/lib/module/Charts/components/BaseLineChart.js.map +1 -0
  207. package/lib/module/Charts/components/LivePriceChart.js +497 -0
  208. package/lib/module/Charts/components/LivePriceChart.js.map +1 -0
  209. package/lib/module/Charts/index.js +36 -0
  210. package/lib/module/Charts/index.js.map +1 -0
  211. package/lib/module/Charts/themes/chartTheme.js +134 -0
  212. package/lib/module/Charts/themes/chartTheme.js.map +1 -0
  213. package/lib/module/Charts/types.js +2 -0
  214. package/lib/module/Charts/types.js.map +1 -0
  215. package/lib/module/Charts/utils/formatters.js +178 -0
  216. package/lib/module/Charts/utils/formatters.js.map +1 -0
  217. package/lib/module/Components/Dropdown.js +5 -3
  218. package/lib/module/Components/Dropdown.js.map +1 -1
  219. package/lib/module/Components/Icons.js +24 -1
  220. package/lib/module/Components/Icons.js.map +1 -1
  221. package/lib/module/Components/index.js +3 -0
  222. package/lib/module/Components/index.js.map +1 -1
  223. package/lib/module/LocationTracker/LocationStatus.js +5 -2
  224. package/lib/module/LocationTracker/LocationStatus.js.map +1 -1
  225. package/lib/module/LocationTracker/api/index.js +2 -2
  226. package/lib/module/LocationTracker/api/index.js.map +1 -1
  227. package/lib/module/index.js +5 -1
  228. package/lib/module/index.js.map +1 -1
  229. package/lib/module/types.d.js +16 -0
  230. package/lib/module/types.d.js.map +1 -1
  231. package/lib/typescript/lib/commonjs/ApiOverrides/index.d.ts.map +1 -1
  232. package/lib/typescript/lib/commonjs/BetRouter/api/index.d.ts +109 -0
  233. package/lib/typescript/lib/commonjs/BetRouter/api/index.d.ts.map +1 -0
  234. package/lib/typescript/lib/commonjs/BetRouter/api/types.d.ts +2 -0
  235. package/lib/typescript/lib/commonjs/BetRouter/api/types.d.ts.map +1 -0
  236. package/lib/typescript/lib/commonjs/BetRouter/components/AccountManager.d.ts +16 -0
  237. package/lib/typescript/lib/commonjs/BetRouter/components/AccountManager.d.ts.map +1 -0
  238. package/lib/typescript/lib/commonjs/BetRouter/components/AdminPortal.d.ts +9 -0
  239. package/lib/typescript/lib/commonjs/BetRouter/components/AdminPortal.d.ts.map +1 -0
  240. package/lib/typescript/lib/commonjs/BetRouter/components/BuyOpportunities.d.ts +16 -0
  241. package/lib/typescript/lib/commonjs/BetRouter/components/BuyOpportunities.d.ts.map +1 -0
  242. package/lib/typescript/lib/commonjs/BetRouter/components/BuyOpportunityCard.d.ts +14 -0
  243. package/lib/typescript/lib/commonjs/BetRouter/components/BuyOpportunityCard.d.ts.map +1 -0
  244. package/lib/typescript/lib/commonjs/BetRouter/components/ContestLiquidity.d.ts +11 -0
  245. package/lib/typescript/lib/commonjs/BetRouter/components/ContestLiquidity.d.ts.map +1 -0
  246. package/lib/typescript/lib/commonjs/BetRouter/components/ContestSelector.d.ts +11 -0
  247. package/lib/typescript/lib/commonjs/BetRouter/components/ContestSelector.d.ts.map +1 -0
  248. package/lib/typescript/lib/commonjs/BetRouter/components/MyOpportunities.d.ts +8 -0
  249. package/lib/typescript/lib/commonjs/BetRouter/components/MyOpportunities.d.ts.map +1 -0
  250. package/lib/typescript/lib/commonjs/BetRouter/components/OpportunityDetailModal.d.ts +14 -0
  251. package/lib/typescript/lib/commonjs/BetRouter/components/OpportunityDetailModal.d.ts.map +1 -0
  252. package/lib/typescript/lib/commonjs/BetRouter/components/OpportunityHistory.d.ts +9 -0
  253. package/lib/typescript/lib/commonjs/BetRouter/components/OpportunityHistory.d.ts.map +1 -0
  254. package/lib/typescript/lib/commonjs/BetRouter/components/PartnerCredentials.d.ts +10 -0
  255. package/lib/typescript/lib/commonjs/BetRouter/components/PartnerCredentials.d.ts.map +1 -0
  256. package/lib/typescript/lib/commonjs/BetRouter/components/PlacedOpportunityModal.d.ts +11 -0
  257. package/lib/typescript/lib/commonjs/BetRouter/components/PlacedOpportunityModal.d.ts.map +1 -0
  258. package/lib/typescript/lib/commonjs/BetRouter/components/admin/AutoFillView.d.ts +4 -0
  259. package/lib/typescript/lib/commonjs/BetRouter/components/admin/AutoFillView.d.ts.map +1 -0
  260. package/lib/typescript/lib/commonjs/BetRouter/components/admin/ConfigManager.d.ts +4 -0
  261. package/lib/typescript/lib/commonjs/BetRouter/components/admin/ConfigManager.d.ts.map +1 -0
  262. package/lib/typescript/lib/commonjs/BetRouter/components/admin/JobManager.d.ts +4 -0
  263. package/lib/typescript/lib/commonjs/BetRouter/components/admin/JobManager.d.ts.map +1 -0
  264. package/lib/typescript/lib/commonjs/BetRouter/components/admin/LeagueContests.d.ts +7 -0
  265. package/lib/typescript/lib/commonjs/BetRouter/components/admin/LeagueContests.d.ts.map +1 -0
  266. package/lib/typescript/lib/commonjs/BetRouter/components/admin/LeagueInfo.d.ts +6 -0
  267. package/lib/typescript/lib/commonjs/BetRouter/components/admin/LeagueInfo.d.ts.map +1 -0
  268. package/lib/typescript/lib/commonjs/BetRouter/components/admin/LeagueParticipants.d.ts +6 -0
  269. package/lib/typescript/lib/commonjs/BetRouter/components/admin/LeagueParticipants.d.ts.map +1 -0
  270. package/lib/typescript/lib/commonjs/BetRouter/index.d.ts +8 -0
  271. package/lib/typescript/lib/commonjs/BetRouter/index.d.ts.map +1 -0
  272. package/lib/typescript/lib/commonjs/BetRouter/layouts/DesktopAdminLayout.d.ts +9 -0
  273. package/lib/typescript/lib/commonjs/BetRouter/layouts/DesktopAdminLayout.d.ts.map +1 -0
  274. package/lib/typescript/lib/commonjs/BetRouter/layouts/DesktopLayout.d.ts +20 -0
  275. package/lib/typescript/lib/commonjs/BetRouter/layouts/DesktopLayout.d.ts.map +1 -0
  276. package/lib/typescript/lib/commonjs/BetRouter/layouts/MobileAdminLayout.d.ts +9 -0
  277. package/lib/typescript/lib/commonjs/BetRouter/layouts/MobileAdminLayout.d.ts.map +1 -0
  278. package/lib/typescript/lib/commonjs/BetRouter/layouts/MobileLayout.d.ts +20 -0
  279. package/lib/typescript/lib/commonjs/BetRouter/layouts/MobileLayout.d.ts.map +1 -0
  280. package/lib/typescript/lib/commonjs/BetRouter/types/accounts.d.ts +2 -0
  281. package/lib/typescript/lib/commonjs/BetRouter/types/accounts.d.ts.map +1 -0
  282. package/lib/typescript/lib/commonjs/BetRouter/types/api-contracts.d.ts +743 -0
  283. package/lib/typescript/lib/commonjs/BetRouter/types/api-contracts.d.ts.map +1 -0
  284. package/lib/typescript/lib/commonjs/BetRouter/types/config.d.ts +2 -0
  285. package/lib/typescript/lib/commonjs/BetRouter/types/config.d.ts.map +1 -0
  286. package/lib/typescript/lib/commonjs/BetRouter/types/contests.d.ts +2 -0
  287. package/lib/typescript/lib/commonjs/BetRouter/types/contests.d.ts.map +1 -0
  288. package/lib/typescript/lib/commonjs/BetRouter/types/credentials.d.ts +56 -0
  289. package/lib/typescript/lib/commonjs/BetRouter/types/credentials.d.ts.map +1 -0
  290. package/lib/typescript/lib/commonjs/BetRouter/types/index.d.ts +2 -0
  291. package/lib/typescript/lib/commonjs/BetRouter/types/index.d.ts.map +1 -0
  292. package/lib/typescript/lib/commonjs/BetRouter/types/jobs.d.ts +2 -0
  293. package/lib/typescript/lib/commonjs/BetRouter/types/jobs.d.ts.map +1 -0
  294. package/lib/typescript/lib/commonjs/BetRouter/types/leagues.d.ts +2 -0
  295. package/lib/typescript/lib/commonjs/BetRouter/types/leagues.d.ts.map +1 -0
  296. package/lib/typescript/lib/commonjs/BetRouter/types/liquidity.d.ts +2 -0
  297. package/lib/typescript/lib/commonjs/BetRouter/types/liquidity.d.ts.map +1 -0
  298. package/lib/typescript/lib/commonjs/BetRouter/types/markets.d.ts +2 -0
  299. package/lib/typescript/lib/commonjs/BetRouter/types/markets.d.ts.map +1 -0
  300. package/lib/typescript/lib/commonjs/BetRouter/types/opportunities.d.ts +2 -0
  301. package/lib/typescript/lib/commonjs/BetRouter/types/opportunities.d.ts.map +1 -0
  302. package/lib/typescript/lib/commonjs/BetRouter/types/orders.d.ts +2 -0
  303. package/lib/typescript/lib/commonjs/BetRouter/types/orders.d.ts.map +1 -0
  304. package/lib/typescript/lib/commonjs/BetRouter/types/participants.d.ts +2 -0
  305. package/lib/typescript/lib/commonjs/BetRouter/types/participants.d.ts.map +1 -0
  306. package/lib/typescript/lib/commonjs/BetRouter/types/partners.d.ts +2 -0
  307. package/lib/typescript/lib/commonjs/BetRouter/types/partners.d.ts.map +1 -0
  308. package/lib/typescript/lib/commonjs/Charts/adapters/TradeChartAdapter.d.ts +87 -0
  309. package/lib/typescript/lib/commonjs/Charts/adapters/TradeChartAdapter.d.ts.map +1 -0
  310. package/lib/typescript/lib/commonjs/Charts/components/BaseLineChart.d.ts +31 -0
  311. package/lib/typescript/lib/commonjs/Charts/components/BaseLineChart.d.ts.map +1 -0
  312. package/lib/typescript/lib/commonjs/Charts/components/LivePriceChart.d.ts +45 -0
  313. package/lib/typescript/lib/commonjs/Charts/components/LivePriceChart.d.ts.map +1 -0
  314. package/lib/typescript/lib/commonjs/Charts/index.d.ts +95 -0
  315. package/lib/typescript/lib/commonjs/Charts/index.d.ts.map +1 -0
  316. package/lib/typescript/lib/commonjs/Charts/themes/chartTheme.d.ts +106 -0
  317. package/lib/typescript/lib/commonjs/Charts/themes/chartTheme.d.ts.map +1 -0
  318. package/lib/typescript/lib/commonjs/Charts/types.d.ts +2 -0
  319. package/lib/typescript/lib/commonjs/Charts/types.d.ts.map +1 -0
  320. package/lib/typescript/lib/commonjs/Charts/utils/formatters.d.ts +24 -0
  321. package/lib/typescript/lib/commonjs/Charts/utils/formatters.d.ts.map +1 -0
  322. package/lib/typescript/lib/commonjs/Components/Dropdown.d.ts.map +1 -1
  323. package/lib/typescript/lib/commonjs/Components/Icons.d.ts +5 -0
  324. package/lib/typescript/lib/commonjs/Components/Icons.d.ts.map +1 -1
  325. package/lib/typescript/lib/commonjs/LocationTracker/LocationStatus.d.ts +2 -1
  326. package/lib/typescript/lib/commonjs/LocationTracker/LocationStatus.d.ts.map +1 -1
  327. package/lib/typescript/lib/commonjs/LocationTracker/api/index.d.ts +1 -1
  328. package/lib/typescript/lib/commonjs/LocationTracker/api/index.d.ts.map +1 -1
  329. package/lib/typescript/lib/commonjs/index.d.ts +6 -1
  330. package/lib/typescript/lib/commonjs/index.d.ts.map +1 -1
  331. package/lib/typescript/lib/module/ApiOverrides/index.d.ts.map +1 -1
  332. package/lib/typescript/lib/module/BetRouter/api/index.d.ts +108 -0
  333. package/lib/typescript/lib/module/BetRouter/api/index.d.ts.map +1 -0
  334. package/lib/typescript/lib/module/BetRouter/api/types.d.ts +2 -0
  335. package/lib/typescript/lib/module/BetRouter/api/types.d.ts.map +1 -0
  336. package/lib/typescript/lib/module/BetRouter/components/AccountManager.d.ts +16 -0
  337. package/lib/typescript/lib/module/BetRouter/components/AccountManager.d.ts.map +1 -0
  338. package/lib/typescript/lib/module/BetRouter/components/AdminPortal.d.ts +9 -0
  339. package/lib/typescript/lib/module/BetRouter/components/AdminPortal.d.ts.map +1 -0
  340. package/lib/typescript/lib/module/BetRouter/components/BuyOpportunities.d.ts +16 -0
  341. package/lib/typescript/lib/module/BetRouter/components/BuyOpportunities.d.ts.map +1 -0
  342. package/lib/typescript/lib/module/BetRouter/components/BuyOpportunityCard.d.ts +14 -0
  343. package/lib/typescript/lib/module/BetRouter/components/BuyOpportunityCard.d.ts.map +1 -0
  344. package/lib/typescript/lib/module/BetRouter/components/ContestLiquidity.d.ts +11 -0
  345. package/lib/typescript/lib/module/BetRouter/components/ContestLiquidity.d.ts.map +1 -0
  346. package/lib/typescript/lib/module/BetRouter/components/ContestSelector.d.ts +11 -0
  347. package/lib/typescript/lib/module/BetRouter/components/ContestSelector.d.ts.map +1 -0
  348. package/lib/typescript/lib/module/BetRouter/components/MyOpportunities.d.ts +8 -0
  349. package/lib/typescript/lib/module/BetRouter/components/MyOpportunities.d.ts.map +1 -0
  350. package/lib/typescript/lib/module/BetRouter/components/OpportunityDetailModal.d.ts +15 -0
  351. package/lib/typescript/lib/module/BetRouter/components/OpportunityDetailModal.d.ts.map +1 -0
  352. package/lib/typescript/lib/module/BetRouter/components/OpportunityHistory.d.ts +9 -0
  353. package/lib/typescript/lib/module/BetRouter/components/OpportunityHistory.d.ts.map +1 -0
  354. package/lib/typescript/lib/module/BetRouter/components/PartnerCredentials.d.ts +11 -0
  355. package/lib/typescript/lib/module/BetRouter/components/PartnerCredentials.d.ts.map +1 -0
  356. package/lib/typescript/lib/module/BetRouter/components/PlacedOpportunityModal.d.ts +12 -0
  357. package/lib/typescript/lib/module/BetRouter/components/PlacedOpportunityModal.d.ts.map +1 -0
  358. package/lib/typescript/lib/module/BetRouter/components/admin/AutoFillView.d.ts +4 -0
  359. package/lib/typescript/lib/module/BetRouter/components/admin/AutoFillView.d.ts.map +1 -0
  360. package/lib/typescript/lib/module/BetRouter/components/admin/ConfigManager.d.ts +4 -0
  361. package/lib/typescript/lib/module/BetRouter/components/admin/ConfigManager.d.ts.map +1 -0
  362. package/lib/typescript/lib/module/BetRouter/components/admin/JobManager.d.ts +4 -0
  363. package/lib/typescript/lib/module/BetRouter/components/admin/JobManager.d.ts.map +1 -0
  364. package/lib/typescript/lib/module/BetRouter/components/admin/LeagueContests.d.ts +9 -0
  365. package/lib/typescript/lib/module/BetRouter/components/admin/LeagueContests.d.ts.map +1 -0
  366. package/lib/typescript/lib/module/BetRouter/components/admin/LeagueInfo.d.ts +6 -0
  367. package/lib/typescript/lib/module/BetRouter/components/admin/LeagueInfo.d.ts.map +1 -0
  368. package/lib/typescript/lib/module/BetRouter/components/admin/LeagueParticipants.d.ts +8 -0
  369. package/lib/typescript/lib/module/BetRouter/components/admin/LeagueParticipants.d.ts.map +1 -0
  370. package/lib/typescript/lib/module/BetRouter/index.d.ts +9 -0
  371. package/lib/typescript/lib/module/BetRouter/index.d.ts.map +1 -0
  372. package/lib/typescript/lib/module/BetRouter/layouts/DesktopAdminLayout.d.ts +9 -0
  373. package/lib/typescript/lib/module/BetRouter/layouts/DesktopAdminLayout.d.ts.map +1 -0
  374. package/lib/typescript/lib/module/BetRouter/layouts/DesktopLayout.d.ts +20 -0
  375. package/lib/typescript/lib/module/BetRouter/layouts/DesktopLayout.d.ts.map +1 -0
  376. package/lib/typescript/lib/module/BetRouter/layouts/MobileAdminLayout.d.ts +9 -0
  377. package/lib/typescript/lib/module/BetRouter/layouts/MobileAdminLayout.d.ts.map +1 -0
  378. package/lib/typescript/lib/module/BetRouter/layouts/MobileLayout.d.ts +20 -0
  379. package/lib/typescript/lib/module/BetRouter/layouts/MobileLayout.d.ts.map +1 -0
  380. package/lib/typescript/lib/module/BetRouter/types/accounts.d.ts +2 -0
  381. package/lib/typescript/lib/module/BetRouter/types/accounts.d.ts.map +1 -0
  382. package/lib/typescript/lib/module/BetRouter/types/api-contracts.d.ts +742 -0
  383. package/lib/typescript/lib/module/BetRouter/types/api-contracts.d.ts.map +1 -0
  384. package/lib/typescript/lib/module/BetRouter/types/config.d.ts +2 -0
  385. package/lib/typescript/lib/module/BetRouter/types/config.d.ts.map +1 -0
  386. package/lib/typescript/lib/module/BetRouter/types/contests.d.ts +2 -0
  387. package/lib/typescript/lib/module/BetRouter/types/contests.d.ts.map +1 -0
  388. package/lib/typescript/lib/module/BetRouter/types/credentials.d.ts +55 -0
  389. package/lib/typescript/lib/module/BetRouter/types/credentials.d.ts.map +1 -0
  390. package/lib/typescript/lib/module/BetRouter/types/index.d.ts +14 -0
  391. package/lib/typescript/lib/module/BetRouter/types/index.d.ts.map +1 -0
  392. package/lib/typescript/lib/module/BetRouter/types/jobs.d.ts +2 -0
  393. package/lib/typescript/lib/module/BetRouter/types/jobs.d.ts.map +1 -0
  394. package/lib/typescript/lib/module/BetRouter/types/leagues.d.ts +2 -0
  395. package/lib/typescript/lib/module/BetRouter/types/leagues.d.ts.map +1 -0
  396. package/lib/typescript/lib/module/BetRouter/types/liquidity.d.ts +2 -0
  397. package/lib/typescript/lib/module/BetRouter/types/liquidity.d.ts.map +1 -0
  398. package/lib/typescript/lib/module/BetRouter/types/markets.d.ts +2 -0
  399. package/lib/typescript/lib/module/BetRouter/types/markets.d.ts.map +1 -0
  400. package/lib/typescript/lib/module/BetRouter/types/opportunities.d.ts +2 -0
  401. package/lib/typescript/lib/module/BetRouter/types/opportunities.d.ts.map +1 -0
  402. package/lib/typescript/lib/module/BetRouter/types/orders.d.ts +2 -0
  403. package/lib/typescript/lib/module/BetRouter/types/orders.d.ts.map +1 -0
  404. package/lib/typescript/lib/module/BetRouter/types/participants.d.ts +2 -0
  405. package/lib/typescript/lib/module/BetRouter/types/participants.d.ts.map +1 -0
  406. package/lib/typescript/lib/module/BetRouter/types/partners.d.ts +2 -0
  407. package/lib/typescript/lib/module/BetRouter/types/partners.d.ts.map +1 -0
  408. package/lib/typescript/lib/module/Charts/adapters/TradeChartAdapter.d.ts +81 -0
  409. package/lib/typescript/lib/module/Charts/adapters/TradeChartAdapter.d.ts.map +1 -0
  410. package/lib/typescript/lib/module/Charts/components/BaseLineChart.d.ts +31 -0
  411. package/lib/typescript/lib/module/Charts/components/BaseLineChart.d.ts.map +1 -0
  412. package/lib/typescript/lib/module/Charts/components/LivePriceChart.d.ts +41 -0
  413. package/lib/typescript/lib/module/Charts/components/LivePriceChart.d.ts.map +1 -0
  414. package/lib/typescript/lib/module/Charts/index.d.ts +6 -0
  415. package/lib/typescript/lib/module/Charts/index.d.ts.map +1 -0
  416. package/lib/typescript/lib/module/Charts/themes/chartTheme.d.ts +102 -0
  417. package/lib/typescript/lib/module/Charts/themes/chartTheme.d.ts.map +1 -0
  418. package/lib/typescript/lib/module/Charts/types.d.ts +2 -0
  419. package/lib/typescript/lib/module/Charts/types.d.ts.map +1 -0
  420. package/lib/typescript/lib/module/Charts/utils/formatters.d.ts +14 -0
  421. package/lib/typescript/lib/module/Charts/utils/formatters.d.ts.map +1 -0
  422. package/lib/typescript/lib/module/Components/Dropdown.d.ts.map +1 -1
  423. package/lib/typescript/lib/module/Components/Icons.d.ts +5 -0
  424. package/lib/typescript/lib/module/Components/Icons.d.ts.map +1 -1
  425. package/lib/typescript/lib/module/Components/index.d.ts +1 -0
  426. package/lib/typescript/lib/module/Components/index.d.ts.map +1 -1
  427. package/lib/typescript/lib/module/LocationTracker/LocationStatus.d.ts +2 -1
  428. package/lib/typescript/lib/module/LocationTracker/LocationStatus.d.ts.map +1 -1
  429. package/lib/typescript/lib/module/LocationTracker/api/index.d.ts +1 -1
  430. package/lib/typescript/lib/module/index.d.ts +3 -1
  431. package/lib/typescript/lib/module/index.d.ts.map +1 -1
  432. package/lib/typescript/src/ApiOverrides/index.d.ts.map +1 -1
  433. package/lib/typescript/src/BetRouter/api/index.d.ts +115 -0
  434. package/lib/typescript/src/BetRouter/api/index.d.ts.map +1 -0
  435. package/lib/typescript/src/BetRouter/api/types.d.ts +2 -0
  436. package/lib/typescript/src/BetRouter/api/types.d.ts.map +1 -0
  437. package/lib/typescript/src/BetRouter/components/AccountManager.d.ts +18 -0
  438. package/lib/typescript/src/BetRouter/components/AccountManager.d.ts.map +1 -0
  439. package/lib/typescript/src/BetRouter/components/AdminPortal.d.ts +15 -0
  440. package/lib/typescript/src/BetRouter/components/AdminPortal.d.ts.map +1 -0
  441. package/lib/typescript/src/BetRouter/components/BuyOpportunities.d.ts +24 -0
  442. package/lib/typescript/src/BetRouter/components/BuyOpportunities.d.ts.map +1 -0
  443. package/lib/typescript/src/BetRouter/components/BuyOpportunityCard.d.ts +19 -0
  444. package/lib/typescript/src/BetRouter/components/BuyOpportunityCard.d.ts.map +1 -0
  445. package/lib/typescript/src/BetRouter/components/ContestLiquidity.d.ts +15 -0
  446. package/lib/typescript/src/BetRouter/components/ContestLiquidity.d.ts.map +1 -0
  447. package/lib/typescript/src/BetRouter/components/ContestSelector.d.ts +13 -0
  448. package/lib/typescript/src/BetRouter/components/ContestSelector.d.ts.map +1 -0
  449. package/lib/typescript/src/BetRouter/components/MyOpportunities.d.ts +16 -0
  450. package/lib/typescript/src/BetRouter/components/MyOpportunities.d.ts.map +1 -0
  451. package/lib/typescript/src/BetRouter/components/OpportunityDetailModal.d.ts +21 -0
  452. package/lib/typescript/src/BetRouter/components/OpportunityDetailModal.d.ts.map +1 -0
  453. package/lib/typescript/src/BetRouter/components/OpportunityHistory.d.ts +20 -0
  454. package/lib/typescript/src/BetRouter/components/OpportunityHistory.d.ts.map +1 -0
  455. package/lib/typescript/src/BetRouter/components/PartnerCredentials.d.ts +12 -0
  456. package/lib/typescript/src/BetRouter/components/PartnerCredentials.d.ts.map +1 -0
  457. package/lib/typescript/src/BetRouter/components/PlacedOpportunityModal.d.ts +18 -0
  458. package/lib/typescript/src/BetRouter/components/PlacedOpportunityModal.d.ts.map +1 -0
  459. package/lib/typescript/src/BetRouter/components/admin/AutoFillView.d.ts +4 -0
  460. package/lib/typescript/src/BetRouter/components/admin/AutoFillView.d.ts.map +1 -0
  461. package/lib/typescript/src/BetRouter/components/admin/ConfigManager.d.ts +4 -0
  462. package/lib/typescript/src/BetRouter/components/admin/ConfigManager.d.ts.map +1 -0
  463. package/lib/typescript/src/BetRouter/components/admin/JobManager.d.ts +4 -0
  464. package/lib/typescript/src/BetRouter/components/admin/JobManager.d.ts.map +1 -0
  465. package/lib/typescript/src/BetRouter/components/admin/LeagueContests.d.ts +9 -0
  466. package/lib/typescript/src/BetRouter/components/admin/LeagueContests.d.ts.map +1 -0
  467. package/lib/typescript/src/BetRouter/components/admin/LeagueInfo.d.ts +8 -0
  468. package/lib/typescript/src/BetRouter/components/admin/LeagueInfo.d.ts.map +1 -0
  469. package/lib/typescript/src/BetRouter/components/admin/LeagueParticipants.d.ts +8 -0
  470. package/lib/typescript/src/BetRouter/components/admin/LeagueParticipants.d.ts.map +1 -0
  471. package/lib/typescript/src/BetRouter/index.d.ts +16 -0
  472. package/lib/typescript/src/BetRouter/index.d.ts.map +1 -0
  473. package/lib/typescript/src/BetRouter/layouts/DesktopAdminLayout.d.ts +15 -0
  474. package/lib/typescript/src/BetRouter/layouts/DesktopAdminLayout.d.ts.map +1 -0
  475. package/lib/typescript/src/BetRouter/layouts/DesktopLayout.d.ts +44 -0
  476. package/lib/typescript/src/BetRouter/layouts/DesktopLayout.d.ts.map +1 -0
  477. package/lib/typescript/src/BetRouter/layouts/MobileAdminLayout.d.ts +15 -0
  478. package/lib/typescript/src/BetRouter/layouts/MobileAdminLayout.d.ts.map +1 -0
  479. package/lib/typescript/src/BetRouter/layouts/MobileLayout.d.ts +44 -0
  480. package/lib/typescript/src/BetRouter/layouts/MobileLayout.d.ts.map +1 -0
  481. package/lib/typescript/src/BetRouter/types/accounts.d.ts +19 -0
  482. package/lib/typescript/src/BetRouter/types/accounts.d.ts.map +1 -0
  483. package/lib/typescript/src/BetRouter/types/api-contracts.d.ts +1071 -0
  484. package/lib/typescript/src/BetRouter/types/api-contracts.d.ts.map +1 -0
  485. package/lib/typescript/src/BetRouter/types/config.d.ts +12 -0
  486. package/lib/typescript/src/BetRouter/types/config.d.ts.map +1 -0
  487. package/lib/typescript/src/BetRouter/types/contests.d.ts +34 -0
  488. package/lib/typescript/src/BetRouter/types/contests.d.ts.map +1 -0
  489. package/lib/typescript/src/BetRouter/types/credentials.d.ts +24 -0
  490. package/lib/typescript/src/BetRouter/types/credentials.d.ts.map +1 -0
  491. package/lib/typescript/src/BetRouter/types/index.d.ts +14 -0
  492. package/lib/typescript/src/BetRouter/types/index.d.ts.map +1 -0
  493. package/lib/typescript/src/BetRouter/types/jobs.d.ts +35 -0
  494. package/lib/typescript/src/BetRouter/types/jobs.d.ts.map +1 -0
  495. package/lib/typescript/src/BetRouter/types/leagues.d.ts +26 -0
  496. package/lib/typescript/src/BetRouter/types/leagues.d.ts.map +1 -0
  497. package/lib/typescript/src/BetRouter/types/liquidity.d.ts +14 -0
  498. package/lib/typescript/src/BetRouter/types/liquidity.d.ts.map +1 -0
  499. package/lib/typescript/src/BetRouter/types/markets.d.ts +87 -0
  500. package/lib/typescript/src/BetRouter/types/markets.d.ts.map +1 -0
  501. package/lib/typescript/src/BetRouter/types/opportunities.d.ts +88 -0
  502. package/lib/typescript/src/BetRouter/types/opportunities.d.ts.map +1 -0
  503. package/lib/typescript/src/BetRouter/types/orders.d.ts +34 -0
  504. package/lib/typescript/src/BetRouter/types/orders.d.ts.map +1 -0
  505. package/lib/typescript/src/BetRouter/types/participants.d.ts +33 -0
  506. package/lib/typescript/src/BetRouter/types/participants.d.ts.map +1 -0
  507. package/lib/typescript/src/BetRouter/types/partners.d.ts +11 -0
  508. package/lib/typescript/src/BetRouter/types/partners.d.ts.map +1 -0
  509. package/lib/typescript/src/Charts/adapters/TradeChartAdapter.d.ts +117 -0
  510. package/lib/typescript/src/Charts/adapters/TradeChartAdapter.d.ts.map +1 -0
  511. package/lib/typescript/src/Charts/components/BaseLineChart.d.ts +40 -0
  512. package/lib/typescript/src/Charts/components/BaseLineChart.d.ts.map +1 -0
  513. package/lib/typescript/src/Charts/components/LivePriceChart.d.ts +13 -0
  514. package/lib/typescript/src/Charts/components/LivePriceChart.d.ts.map +1 -0
  515. package/lib/typescript/src/Charts/index.d.ts +28 -0
  516. package/lib/typescript/src/Charts/index.d.ts.map +1 -0
  517. package/lib/typescript/src/Charts/themes/chartTheme.d.ts +78 -0
  518. package/lib/typescript/src/Charts/themes/chartTheme.d.ts.map +1 -0
  519. package/lib/typescript/src/Charts/types.d.ts +155 -0
  520. package/lib/typescript/src/Charts/types.d.ts.map +1 -0
  521. package/lib/typescript/src/Charts/utils/formatters.d.ts +66 -0
  522. package/lib/typescript/src/Charts/utils/formatters.d.ts.map +1 -0
  523. package/lib/typescript/src/Components/Dropdown.d.ts.map +1 -1
  524. package/lib/typescript/src/Components/Icons.d.ts +1 -0
  525. package/lib/typescript/src/Components/Icons.d.ts.map +1 -1
  526. package/lib/typescript/src/Components/index.d.ts +1 -0
  527. package/lib/typescript/src/Components/index.d.ts.map +1 -1
  528. package/lib/typescript/src/LocationTracker/LocationStatus.d.ts +2 -1
  529. package/lib/typescript/src/LocationTracker/LocationStatus.d.ts.map +1 -1
  530. package/lib/typescript/src/LocationTracker/api/index.d.ts +3 -1
  531. package/lib/typescript/src/LocationTracker/api/index.d.ts.map +1 -1
  532. package/lib/typescript/src/index.d.ts +4 -1
  533. package/lib/typescript/src/index.d.ts.map +1 -1
  534. package/package.json +4 -2
  535. package/src/ApiOverrides/index.ts +4 -0
  536. package/src/BetRouter/api/index.ts +854 -0
  537. package/src/BetRouter/api/types.ts +0 -0
  538. package/src/BetRouter/components/AccountManager.tsx +533 -0
  539. package/src/BetRouter/components/AdminPortal.tsx +44 -0
  540. package/src/BetRouter/components/BuyOpportunities.tsx +491 -0
  541. package/src/BetRouter/components/BuyOpportunityCard.tsx +331 -0
  542. package/src/BetRouter/components/ContestLiquidity.tsx +613 -0
  543. package/src/BetRouter/components/ContestSelector.tsx +179 -0
  544. package/src/BetRouter/components/MyOpportunities.tsx +279 -0
  545. package/src/BetRouter/components/MyOpportunities.tsx.bak +440 -0
  546. package/src/BetRouter/components/OpportunityDetailModal.tsx +360 -0
  547. package/src/BetRouter/components/OpportunityHistory.tsx +408 -0
  548. package/src/BetRouter/components/PartnerCredentials.tsx +212 -0
  549. package/src/BetRouter/components/PlacedOpportunityModal.tsx +192 -0
  550. package/src/BetRouter/components/admin/AutoFillView.tsx +275 -0
  551. package/src/BetRouter/components/admin/ConfigManager.tsx +596 -0
  552. package/src/BetRouter/components/admin/JobManager.tsx +758 -0
  553. package/src/BetRouter/components/admin/LeagueContests.tsx +2443 -0
  554. package/src/BetRouter/components/admin/LeagueInfo.tsx +253 -0
  555. package/src/BetRouter/components/admin/LeagueParticipants.tsx +662 -0
  556. package/src/BetRouter/index.tsx +453 -0
  557. package/src/BetRouter/layouts/DesktopAdminLayout.tsx +348 -0
  558. package/src/BetRouter/layouts/DesktopLayout.tsx +292 -0
  559. package/src/BetRouter/layouts/MobileAdminLayout.tsx +387 -0
  560. package/src/BetRouter/layouts/MobileLayout.tsx +325 -0
  561. package/src/BetRouter/types/ADMIN_PORTAL.md +863 -0
  562. package/src/BetRouter/types/ADMIN_PORTAL_SIMPLIFIED.md +1881 -0
  563. package/src/BetRouter/types/CREDENTIALS_EXAMPLE.md +350 -0
  564. package/src/BetRouter/types/LIQUIDITY_CLIENT_GUIDE.md +399 -0
  565. package/src/BetRouter/types/MARKET_LINKING_WORKFLOW.md +682 -0
  566. package/src/BetRouter/types/MARKET_LINKING_WORKFLOW_V2.md +627 -0
  567. package/src/BetRouter/types/README.md +249 -0
  568. package/src/BetRouter/types/accounts.ts +21 -0
  569. package/src/BetRouter/types/api-contracts.ts +1164 -0
  570. package/src/BetRouter/types/config.ts +12 -0
  571. package/src/BetRouter/types/contests.ts +37 -0
  572. package/src/BetRouter/types/credentials.ts +99 -0
  573. package/src/BetRouter/types/index.ts +16 -0
  574. package/src/BetRouter/types/jobs.ts +37 -0
  575. package/src/BetRouter/types/leagues.ts +29 -0
  576. package/src/BetRouter/types/liquidity.ts +15 -0
  577. package/src/BetRouter/types/markets.ts +94 -0
  578. package/src/BetRouter/types/opportunities.ts +107 -0
  579. package/src/BetRouter/types/orders.ts +51 -0
  580. package/src/BetRouter/types/participants.ts +34 -0
  581. package/src/BetRouter/types/partners.ts +10 -0
  582. package/src/Charts/README.md +310 -0
  583. package/src/Charts/adapters/TradeChartAdapter.ts +471 -0
  584. package/src/Charts/components/BaseLineChart.tsx +293 -0
  585. package/src/Charts/components/LivePriceChart.tsx +521 -0
  586. package/src/Charts/index.tsx +62 -0
  587. package/src/Charts/themes/chartTheme.ts +113 -0
  588. package/src/Charts/types.ts +160 -0
  589. package/src/Charts/utils/formatters.ts +182 -0
  590. package/src/Components/Dropdown.tsx +6 -3
  591. package/src/Components/Icons.tsx +12 -0
  592. package/src/Components/index.tsx +4 -0
  593. package/src/LocationTracker/LocationStatus.tsx +4 -3
  594. package/src/LocationTracker/api/index.tsx +2 -2
  595. package/src/index.tsx +6 -0
  596. package/src/types.d.ts +410 -2
@@ -0,0 +1,2443 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { View, Text, Button } from "../../../Components/Themed";
3
+ import { ActivityIndicator, TouchableOpacity, FlatList, TextInput, ScrollView } from 'react-native';
4
+ import { useColors } from '../../../constants/useColors';
5
+ import { BetRouterApi } from '../../api';
6
+ import { Icons, SearchBox } from '../../../Components';
7
+ import Pagination from '../../../Components/Pagination';
8
+ import Switch from '../../../Components/Switch';
9
+ import moment from 'moment-mini';
10
+ import type {
11
+ RouterLeagueProps,
12
+ RouterContestProps,
13
+ PartnerContestProps,
14
+ RawContestProps,
15
+ RouterPartnerProps,
16
+ RouterMarketProps,
17
+ MarketContestProps,
18
+ PartnerMarketProps,
19
+ RawMarketProps,
20
+ RouterMarketSideProps,
21
+ RouterMarketVariableProps,
22
+ RouterParticipantProps
23
+ } from '../../types';
24
+
25
+ type LeagueContestsProps = {
26
+ league: RouterLeagueProps;
27
+ initialContestId?: string; // Optional contest ID to auto-select
28
+ };
29
+
30
+ type LinkStatus = 'all' | 'complete' | 'partial' | 'none';
31
+
32
+ type ContestData = {
33
+ contests: RouterContestProps[];
34
+ partnerContests: PartnerContestProps[];
35
+ partners: RouterPartnerProps[];
36
+ participants: RouterParticipantProps[];
37
+ selectedContest: RouterContestProps | null;
38
+ loading: boolean;
39
+ loadingMarkets: boolean;
40
+ loadingModal: boolean;
41
+ searchValue: string;
42
+ currentTab: 'partners' | 'markets';
43
+ linkStatusFilter: LinkStatus;
44
+ dateFilter: 'all' | 'upcoming' | 'today' | 'past';
45
+ customDateFrom: string;
46
+ customDateTo: string;
47
+ // Link modal state
48
+ showLinkModal: boolean;
49
+ selectedPartner: RouterPartnerProps | null;
50
+ availableRawContests: RawContestProps[];
51
+ selectedRawIds: string[];
52
+ rawSearchValue: string;
53
+ rawPage: number;
54
+ // Auto-link modal state
55
+ showAutoLinkModal: boolean;
56
+ autoLinkResults: any;
57
+ showAutoLinkResults: boolean;
58
+ // Market auto-link modal state
59
+ showMarketAutoLinkModal: boolean;
60
+ allRouterMarkets: RouterMarketProps[];
61
+ selectedMarketIds: string[];
62
+ // Manage markets modal state
63
+ showManageMarketsModal: boolean;
64
+ marketContests: MarketContestProps[];
65
+ // Partner markets state
66
+ partnerMarkets: PartnerMarketProps[];
67
+ // Link markets modal state
68
+ showLinkMarketsModal: boolean;
69
+ selectedMarketContest: MarketContestProps | null;
70
+ availableRawMarkets: RawMarketProps[];
71
+ alreadyLinkedRawMarkets: RawMarketProps[];
72
+ // Add variable modal state
73
+ showAddVariableModal: boolean;
74
+ newVariableValue: string;
75
+ // Inspect partner markets modal state
76
+ showInspectModal: boolean;
77
+ inspectPartnerMarkets: PartnerMarketProps[];
78
+ // Lookup data for enriching displays
79
+ marketSides: RouterMarketSideProps[];
80
+ marketVariables: RouterMarketVariableProps[];
81
+ // Manual link modal state
82
+ showManualLinkModal: boolean;
83
+ selectedRawMarket: RawMarketProps | null;
84
+ linkingData: {
85
+ market_sides: RouterMarketSideProps[];
86
+ timeframes: any[];
87
+ participants: Array<{
88
+ partner_participant_id: string;
89
+ router_participant_id: string;
90
+ name: string;
91
+ participant_type: string;
92
+ external_id: string;
93
+ raw_name: string;
94
+ tags: string[];
95
+ }>;
96
+ } | null;
97
+ manualLinkForm: {
98
+ sideParticipants: Array<{
99
+ market_side_id: string;
100
+ partner_participant_id: string;
101
+ price_key: string;
102
+ }>;
103
+ timeframe_id: string;
104
+ variable: string;
105
+ variable_type: 'total' | 'spread';
106
+ };
107
+ participantSearchValue: string;
108
+ participantPage: number;
109
+ selectedSideIndex: number;
110
+ };
111
+
112
+ const RAW_CONTESTS_PER_PAGE = 10;
113
+ const PARTICIPANTS_PER_PAGE = 10;
114
+
115
+ const LeagueContests = ({ league, initialContestId }: LeagueContestsProps) => {
116
+ const Colors = useColors();
117
+
118
+ const [contestData, setContestData] = useState<ContestData>({
119
+ contests: [],
120
+ partnerContests: [],
121
+ partners: [],
122
+ participants: [],
123
+ selectedContest: null,
124
+ loading: true,
125
+ loadingMarkets: false,
126
+ loadingModal: false,
127
+ searchValue: '',
128
+ currentTab: 'partners',
129
+ linkStatusFilter: 'all',
130
+ dateFilter: 'all',
131
+ customDateFrom: '',
132
+ customDateTo: '',
133
+ showLinkModal: false,
134
+ selectedPartner: null,
135
+ availableRawContests: [],
136
+ selectedRawIds: [],
137
+ rawSearchValue: '',
138
+ rawPage: 0,
139
+ showAutoLinkModal: false,
140
+ autoLinkResults: null,
141
+ showAutoLinkResults: false,
142
+ showMarketAutoLinkModal: false,
143
+ allRouterMarkets: [],
144
+ selectedMarketIds: [],
145
+ showManageMarketsModal: false,
146
+ marketContests: [],
147
+ partnerMarkets: [],
148
+ showLinkMarketsModal: false,
149
+ selectedMarketContest: null,
150
+ availableRawMarkets: [],
151
+ alreadyLinkedRawMarkets: [],
152
+ showAddVariableModal: false,
153
+ newVariableValue: '',
154
+ showInspectModal: false,
155
+ inspectPartnerMarkets: [],
156
+ marketSides: [],
157
+ marketVariables: [],
158
+ showManualLinkModal: false,
159
+ selectedRawMarket: null,
160
+ linkingData: null,
161
+ manualLinkForm: {
162
+ sideParticipants: [],
163
+ timeframe_id: '',
164
+ variable: '',
165
+ variable_type: 'spread'
166
+ },
167
+ participantSearchValue: '',
168
+ participantPage: 0,
169
+ selectedSideIndex: 0
170
+ });
171
+
172
+ useEffect(() => {
173
+ loadContestData();
174
+ }, [league.router_league_id]);
175
+
176
+ // Auto-select contest when data loads
177
+ useEffect(() => {
178
+ if (initialContestId && contestData.contests.length > 0 && !contestData.selectedContest) {
179
+ const contest = contestData.contests.find(c => c.router_contest_id === initialContestId);
180
+ if (contest) {
181
+ console.log('Auto-selecting contest:', contest);
182
+ setContestData(prev => ({ ...prev, selectedContest: contest }));
183
+ }
184
+ }
185
+ }, [initialContestId, contestData.contests]);
186
+
187
+ const loadContestData = async () => {
188
+ setContestData(prev => ({ ...prev, loading: true }));
189
+ try {
190
+ const [contestsRes, partnerContestsRes, partnersRes, participantsRes, sidesRes, variablesRes] = await Promise.all([
191
+ BetRouterApi.BetRouter.ContestApi.getOpenContests(league.router_league_id, 'open'),
192
+ BetRouterApi.BetRouter.ContestApi.getPartnerContests(),
193
+ BetRouterApi.BetRouter.PartnerApi.getPartners(),
194
+ BetRouterApi.BetRouter.ParticipantApi.getRouterParticipants(league.router_league_id),
195
+ // Load market sides and variables once - they're small and global
196
+ BetRouterApi.BetRouter.MarketApi.getMarketSides(),
197
+ BetRouterApi.BetRouter.MarketApi.getMarketVariables()
198
+ ]);
199
+
200
+ setContestData(prev => ({
201
+ ...prev,
202
+ contests: contestsRes.router_contests || [],
203
+ partnerContests: Array.isArray(partnerContestsRes) ? partnerContestsRes : [],
204
+ partners: Array.isArray(partnersRes) ? partnersRes : [],
205
+ participants: Array.isArray(participantsRes) ? participantsRes : [],
206
+ marketSides: Array.isArray(sidesRes) ? sidesRes : [],
207
+ marketVariables: Array.isArray(variablesRes) ? variablesRes : [],
208
+ loading: false
209
+ }));
210
+ } catch (error) {
211
+ console.error('Failed to load contest data:', error);
212
+ setContestData(prev => ({ ...prev, loading: false }));
213
+ }
214
+ };
215
+
216
+ const loadRawContests = async (partner: RouterPartnerProps) => {
217
+ try {
218
+ setContestData(prev => ({ ...prev, loading: true }));
219
+ const result = await BetRouterApi.BetRouter.ContestApi.loadRawContests(
220
+ partner.partner_id,
221
+ league.router_league_id
222
+ );
223
+ alert(`Loaded ${result.count} raw contests from ${partner.name}`);
224
+ await loadContestData(); // Reload to get updated data
225
+ } catch (error) {
226
+ console.error('Error loading raw contests:', error);
227
+ alert('Error loading raw contests: ' + (error as any).message);
228
+ } finally {
229
+ setContestData(prev => ({ ...prev, loading: false }));
230
+ }
231
+ };
232
+
233
+ const openLinkModal = async (contest: RouterContestProps, partner: RouterPartnerProps) => {
234
+ try {
235
+ setContestData(prev => ({ ...prev, loading: true }));
236
+ const data = await BetRouterApi.BetRouter.ContestApi.getAvailableRawContests(
237
+ contest.router_contest_id,
238
+ partner.partner_id
239
+ );
240
+
241
+ setContestData(prev => ({
242
+ ...prev,
243
+ availableRawContests: data.raw_contests || [],
244
+ showLinkModal: true,
245
+ selectedPartner: partner,
246
+ selectedContest: contest,
247
+ selectedRawIds: [],
248
+ rawSearchValue: '',
249
+ rawPage: 0,
250
+ loading: false
251
+ }));
252
+ } catch (error) {
253
+ console.error('Error loading raw contests:', error);
254
+ setContestData(prev => ({ ...prev, loading: false }));
255
+ }
256
+ };
257
+
258
+ const linkSelectedContests = async () => {
259
+ if (!contestData.selectedContest || contestData.selectedRawIds.length === 0) return;
260
+
261
+ try {
262
+ setContestData(prev => ({ ...prev, loading: true }));
263
+ await BetRouterApi.BetRouter.ContestApi.linkContest(
264
+ contestData.selectedRawIds,
265
+ contestData.selectedContest.router_contest_id
266
+ );
267
+ alert(`Linked ${contestData.selectedRawIds.length} raw contests`);
268
+ setContestData(prev => ({ ...prev, showLinkModal: false }));
269
+ await loadContestData(); // Reload to get updated data
270
+ } catch (error) {
271
+ console.error('Error linking contests:', error);
272
+ alert('Error linking contests: ' + (error as any).message);
273
+ } finally {
274
+ setContestData(prev => ({ ...prev, loading: false }));
275
+ }
276
+ };
277
+
278
+ const toggleRawContestSelection = (rawContestId: string) => {
279
+ setContestData(prev => ({
280
+ ...prev,
281
+ selectedRawIds: prev.selectedRawIds.includes(rawContestId)
282
+ ? prev.selectedRawIds.filter(id => id !== rawContestId)
283
+ : [...prev.selectedRawIds, rawContestId]
284
+ }));
285
+ };
286
+
287
+ const getUniquePartnerCountForContest = (contestId: string) => {
288
+ const contestPartners = contestData.partnerContests.filter(pc => pc.router_contest_id === contestId);
289
+ const uniquePartnerIds = new Set(contestPartners.map(pc => pc.partner_id));
290
+ return uniquePartnerIds.size;
291
+ };
292
+
293
+ const isPartnerLinked = (contestId: string, partnerId: string) => {
294
+ return contestData.partnerContests.some(
295
+ pc => pc.router_contest_id === contestId && pc.partner_id === partnerId
296
+ );
297
+ };
298
+
299
+ // Calculate link status for a contest
300
+ const getContestLinkStatus = (contest: RouterContestProps): LinkStatus => {
301
+ const linkedPartnerCount = getUniquePartnerCountForContest(contest.router_contest_id);
302
+ const totalPartners = contestData.partners.length;
303
+
304
+ if (linkedPartnerCount === 0) return 'none';
305
+ if (linkedPartnerCount === totalPartners) return 'complete';
306
+ return 'partial';
307
+ };
308
+
309
+ // Get contests by link status
310
+ const getContestsByStatus = (status: LinkStatus) => {
311
+ if (status === 'all') return contestData.contests;
312
+ return contestData.contests.filter(contest => getContestLinkStatus(contest) === status);
313
+ };
314
+
315
+ const getLinkedExternalIds = (contestId: string, partnerId: string) => {
316
+ return contestData.partnerContests
317
+ .filter(pc => pc.router_contest_id === contestId && pc.partner_id === partnerId)
318
+ .map(pc => pc.external_id);
319
+ };
320
+
321
+ const openManageMarketsModal = async (contest: RouterContestProps) => {
322
+ try {
323
+ setContestData(prev => ({ ...prev, loadingModal: true }));
324
+ const data = await BetRouterApi.BetRouter.MarketApi.getAvailableToSupport(contest.router_contest_id);
325
+ setContestData(prev => ({
326
+ ...prev,
327
+ allRouterMarkets: data.all_router_markets || [],
328
+ marketContests: data.market_contests || [],
329
+ showManageMarketsModal: true,
330
+ loadingModal: false
331
+ }));
332
+ } catch (error) {
333
+ console.error('Error loading available markets:', error);
334
+ alert('Error loading markets: ' + (error as any).message);
335
+ setContestData(prev => ({ ...prev, loadingModal: false }));
336
+ }
337
+ };
338
+
339
+ const toggleMarketSupport = async (routerMarketId: string) => {
340
+ if (!contestData.selectedContest) return;
341
+
342
+ const isSupported = contestData.marketContests.some(mc => mc.router_market_id === routerMarketId);
343
+
344
+ try {
345
+ setContestData(prev => ({ ...prev, loadingModal: true }));
346
+
347
+ if (isSupported) {
348
+ // Remove it
349
+ const marketContest = contestData.marketContests.find(mc => mc.router_market_id === routerMarketId);
350
+ if (marketContest) {
351
+ await BetRouterApi.BetRouter.MarketApi.removeSupportedMarket(marketContest.market_contest_id);
352
+ }
353
+ } else {
354
+ // Add it
355
+ await BetRouterApi.BetRouter.MarketApi.addSupportedMarket(
356
+ contestData.selectedContest.router_contest_id,
357
+ routerMarketId
358
+ );
359
+ }
360
+
361
+ // Reload the data
362
+ const data = await BetRouterApi.BetRouter.MarketApi.getAvailableToSupport(contestData.selectedContest.router_contest_id);
363
+ setContestData(prev => ({
364
+ ...prev,
365
+ marketContests: data.market_contests || [],
366
+ loadingModal: false
367
+ }));
368
+ } catch (error) {
369
+ console.error('Error toggling market support:', error);
370
+ alert('Error updating market: ' + (error as any).message);
371
+ setContestData(prev => ({ ...prev, loadingModal: false }));
372
+ }
373
+ };
374
+
375
+ const loadSupportedMarkets = async (contest: RouterContestProps) => {
376
+ try {
377
+ setContestData(prev => ({ ...prev, loadingMarkets: true }));
378
+ const data = await BetRouterApi.BetRouter.MarketApi.getSupportedMarkets(contest.router_contest_id);
379
+
380
+ // Also load all router markets so we can display market info
381
+ const allMarketsData = await BetRouterApi.BetRouter.MarketApi.getAvailableToSupport(contest.router_contest_id);
382
+
383
+ setContestData(prev => ({
384
+ ...prev,
385
+ marketContests: data.market_contests || [],
386
+ allRouterMarkets: allMarketsData.all_router_markets || [],
387
+ loadingMarkets: false
388
+ }));
389
+ } catch (error) {
390
+ console.error('Error loading supported markets:', error);
391
+ setContestData(prev => ({ ...prev, loadingMarkets: false }));
392
+ }
393
+ };
394
+
395
+ const removeSupportedMarket = async (marketContestId: string, contest: RouterContestProps) => {
396
+ try {
397
+ setContestData(prev => ({ ...prev, loadingMarkets: true }));
398
+ await BetRouterApi.BetRouter.MarketApi.removeSupportedMarket(marketContestId);
399
+ await loadSupportedMarkets(contest);
400
+ } catch (error) {
401
+ console.error('Error removing supported market:', error);
402
+ alert('Error removing market: ' + (error as any).message);
403
+ setContestData(prev => ({ ...prev, loadingMarkets: false }));
404
+ }
405
+ };
406
+
407
+ const loadPartnerMarketsForContest = async (contest: RouterContestProps) => {
408
+ try {
409
+ // Use contest-scoped endpoint to get only data for this specific contest
410
+ const contestData = await BetRouterApi.BetRouter.ContestApi.getContest(contest.router_contest_id);
411
+
412
+ setContestData(prev => ({
413
+ ...prev,
414
+ partnerMarkets: contestData.partner_markets || [],
415
+ // marketSides and marketVariables are global, load them once
416
+ // We'll fetch these only when needed or load them globally once
417
+ }));
418
+ } catch (error) {
419
+ console.error('Error loading partner markets for contest:', error);
420
+ }
421
+ };
422
+
423
+ // Helper to get participant name from partner_participant_id
424
+ // This now uses linkingData which is loaded on-demand in the manual link modal
425
+ const getParticipantName = (partner_participant_id: string): string | null => {
426
+ if (!contestData.linkingData?.participants) return null;
427
+
428
+ const participant = contestData.linkingData.participants.find(
429
+ p => p.partner_participant_id === partner_participant_id
430
+ );
431
+ return participant?.name || null;
432
+ };
433
+
434
+ const openManualLinkModal = async (rawMarket: RawMarketProps) => {
435
+ if (!contestData.selectedContest || !contestData.selectedMarketContest || !contestData.selectedPartner) return;
436
+
437
+ try {
438
+ setContestData(prev => ({ ...prev, loadingModal: true }));
439
+
440
+ const data = await BetRouterApi.BetRouter.MarketApi.getMarketLinkingData(
441
+ contestData.selectedContest.router_contest_id,
442
+ contestData.selectedMarketContest.router_market_id,
443
+ contestData.selectedPartner.partner_id
444
+ );
445
+
446
+ const routerMarket = contestData.allRouterMarkets.find(
447
+ m => m.router_market_id === contestData.selectedMarketContest?.router_market_id
448
+ );
449
+
450
+ // Set default values
451
+ const defaultTimeframe = data.timeframes?.[0]?.timeframe_id || '';
452
+ const defaultVariableType = routerMarket?.default_variable_type || 'spread';
453
+
454
+ // Initialize sideParticipants with empty entries for each side
455
+ const sideParticipants = data.market_sides.map(side => ({
456
+ market_side_id: side.market_side_id,
457
+ partner_participant_id: '',
458
+ price_key: ''
459
+ }));
460
+
461
+ setContestData(prev => ({
462
+ ...prev,
463
+ showManualLinkModal: true,
464
+ selectedRawMarket: rawMarket,
465
+ linkingData: data,
466
+ manualLinkForm: {
467
+ sideParticipants: sideParticipants,
468
+ timeframe_id: defaultTimeframe,
469
+ variable: '',
470
+ variable_type: defaultVariableType
471
+ },
472
+ participantSearchValue: '',
473
+ participantPage: 0,
474
+ selectedSideIndex: 0,
475
+ loadingModal: false
476
+ }));
477
+ } catch (error) {
478
+ console.error('Error loading linking data:', error);
479
+ alert('Error loading linking data: ' + (error as any).message);
480
+ setContestData(prev => ({ ...prev, loadingModal: false }));
481
+ }
482
+ };
483
+
484
+ const submitManualLink = async () => {
485
+ if (!contestData.selectedRawMarket || !contestData.selectedMarketContest) return;
486
+
487
+ const routerMarket = contestData.allRouterMarkets.find(
488
+ m => m.router_market_id === contestData.selectedMarketContest?.router_market_id
489
+ );
490
+
491
+ // Validate required fields - at least one side must have a participant
492
+ const sidesWithParticipants = contestData.manualLinkForm.sideParticipants.filter(sp => sp.partner_participant_id);
493
+ if (sidesWithParticipants.length === 0) {
494
+ alert('Please select at least one participant');
495
+ return;
496
+ }
497
+
498
+ if (routerMarket?.variable_required && !contestData.manualLinkForm.variable) {
499
+ alert('Please enter a variable value');
500
+ return;
501
+ }
502
+
503
+ try {
504
+ setContestData(prev => ({ ...prev, loadingModal: true }));
505
+
506
+ const baseVariable = contestData.manualLinkForm.variable ? parseFloat(contestData.manualLinkForm.variable) : 0;
507
+ const isSpread = contestData.manualLinkForm.variable_type === 'spread';
508
+
509
+ // Create a link for each side that has a participant selected
510
+ const linkPromises = sidesWithParticipants.map(sideParticipant => {
511
+ // Find the side info to determine if we need to flip the variable
512
+ const side = contestData.linkingData!.market_sides.find(s => s.market_side_id === sideParticipant.market_side_id);
513
+
514
+ // For spreads, flip the sign for away side (home keeps the value as entered)
515
+ let variableValue = baseVariable;
516
+ if (isSpread && side?.side_key.toLowerCase() === 'away') {
517
+ variableValue = baseVariable * -1;
518
+ }
519
+
520
+ return BetRouterApi.BetRouter.MarketApi.linkMarket(
521
+ contestData.selectedRawMarket!.raw_market_id,
522
+ contestData.selectedMarketContest!.router_market_id,
523
+ sideParticipant.market_side_id,
524
+ sideParticipant.partner_participant_id,
525
+ contestData.manualLinkForm.timeframe_id,
526
+ variableValue,
527
+ contestData.manualLinkForm.variable_type,
528
+ sideParticipant.price_key || undefined
529
+ );
530
+ });
531
+
532
+ await Promise.all(linkPromises);
533
+
534
+ // Reload data
535
+ if (contestData.selectedContest) {
536
+ await Promise.all([
537
+ loadPartnerMarketsForContest(contestData.selectedContest),
538
+ openLinkMarketsModal(contestData.selectedMarketContest, contestData.selectedPartner!)
539
+ ]);
540
+ }
541
+
542
+ setContestData(prev => ({
543
+ ...prev,
544
+ showManualLinkModal: false,
545
+ selectedRawMarket: null,
546
+ linkingData: null,
547
+ loadingModal: false
548
+ }));
549
+
550
+ alert(`Successfully linked ${sidesWithParticipants.length} market side${sidesWithParticipants.length !== 1 ? 's' : ''}!`);
551
+ } catch (error) {
552
+ console.error('Error linking market:', error);
553
+ alert('Error linking market: ' + (error as any).message);
554
+ setContestData(prev => ({ ...prev, loadingModal: false }));
555
+ }
556
+ };
557
+
558
+ const openLinkMarketsModal = async (marketContest: MarketContestProps, partner: RouterPartnerProps) => {
559
+ if (!contestData.selectedContest) return;
560
+
561
+ try {
562
+ setContestData(prev => ({ ...prev, loadingModal: true }));
563
+ const data = await BetRouterApi.BetRouter.MarketApi.getAvailableRawMarkets(
564
+ contestData.selectedContest.router_contest_id,
565
+ marketContest.router_market_id,
566
+ partner.partner_id
567
+ );
568
+
569
+ setContestData(prev => ({
570
+ ...prev,
571
+ availableRawMarkets: data.raw_markets || [],
572
+ alreadyLinkedRawMarkets: data.already_linked || [],
573
+ showLinkMarketsModal: true,
574
+ selectedMarketContest: marketContest,
575
+ selectedPartner: partner,
576
+ loadingModal: false
577
+ }));
578
+ } catch (error) {
579
+ console.error('Error loading raw markets:', error);
580
+ alert('Error loading markets: ' + (error as any).message);
581
+ setContestData(prev => ({ ...prev, loadingModal: false }));
582
+ }
583
+ };
584
+
585
+ const openAddVariableModal = (marketContest: MarketContestProps, partner: RouterPartnerProps) => {
586
+ setContestData(prev => ({
587
+ ...prev,
588
+ showAddVariableModal: true,
589
+ selectedMarketContest: marketContest,
590
+ selectedPartner: partner,
591
+ newVariableValue: ''
592
+ }));
593
+ };
594
+
595
+ const addVariable = async () => {
596
+ if (!contestData.selectedContest || !contestData.selectedMarketContest || !contestData.selectedPartner) return;
597
+
598
+ const variableValue = parseFloat(contestData.newVariableValue);
599
+ if (isNaN(variableValue)) {
600
+ alert('Please enter a valid number');
601
+ return;
602
+ }
603
+
604
+ try {
605
+ setContestData(prev => ({ ...prev, loadingModal: true }));
606
+ const result = await BetRouterApi.BetRouter.MarketApi.addVariable(
607
+ contestData.selectedContest.router_contest_id,
608
+ contestData.selectedMarketContest.router_market_id,
609
+ contestData.selectedPartner.partner_id,
610
+ variableValue
611
+ );
612
+
613
+ // Reload partner markets to show the new links
614
+ if (contestData.selectedContest) {
615
+ await loadPartnerMarketsForContest(contestData.selectedContest);
616
+ }
617
+
618
+ setContestData(prev => ({
619
+ ...prev,
620
+ showAddVariableModal: false,
621
+ newVariableValue: '',
622
+ loadingModal: false
623
+ }));
624
+
625
+ alert(`Successfully added variable ${variableValue}. Created ${result.count} partner market${result.count !== 1 ? 's' : ''}.`);
626
+ } catch (error) {
627
+ console.error('Error adding variable:', error);
628
+ alert('Error adding variable: ' + (error as any).message);
629
+ setContestData(prev => ({ ...prev, loadingModal: false }));
630
+ }
631
+ };
632
+
633
+ const inspectPartnerMarkets = (marketContest: MarketContestProps, partner: RouterPartnerProps) => {
634
+ if (!contestData.selectedContest) return;
635
+
636
+ //const routerMarket = contestData.allRouterMarkets.find(m => m.router_market_id === marketContest.router_market_id);
637
+
638
+ // Filter partner markets for this specific market and partner
639
+ // No need to filter by router_contest_id - data is already scoped to this contest
640
+ const relevantPartnerMarkets = contestData.partnerMarkets.filter(
641
+ pm => pm.router_market_id === marketContest.router_market_id &&
642
+ pm.partner_id === partner.partner_id
643
+ );
644
+
645
+ setContestData(prev => ({
646
+ ...prev,
647
+ showInspectModal: true,
648
+ inspectPartnerMarkets: relevantPartnerMarkets,
649
+ selectedMarketContest: marketContest,
650
+ selectedPartner: partner
651
+ }));
652
+ };
653
+
654
+ // Apply search, link status, and date filters, then sort by scheduled_datetime
655
+ const filteredContests = contestData.contests
656
+ .filter(c => {
657
+ // Search filter
658
+ const matchesSearch = c.contest_label.toLowerCase().includes(contestData.searchValue.toLowerCase());
659
+ // Link status filter
660
+ const matchesStatus = contestData.linkStatusFilter === 'all' || getContestLinkStatus(c) === contestData.linkStatusFilter;
661
+
662
+ // Date filter
663
+ let matchesDate = true;
664
+ if (contestData.dateFilter !== 'all') {
665
+ const contestDate = moment(c.scheduled_datetime);
666
+ const now = moment();
667
+ const todayStart = moment().startOf('day');
668
+ const todayEnd = moment().endOf('day');
669
+
670
+ if (contestData.dateFilter === 'upcoming') {
671
+ matchesDate = contestDate.isAfter(now);
672
+ } else if (contestData.dateFilter === 'today') {
673
+ matchesDate = contestDate.isBetween(todayStart, todayEnd, undefined, '[]');
674
+ } else if (contestData.dateFilter === 'past') {
675
+ matchesDate = contestDate.isBefore(now);
676
+ }
677
+ }
678
+
679
+ return matchesSearch && matchesStatus && matchesDate;
680
+ })
681
+ .sort((a, b) => {
682
+ // Sort by scheduled_datetime ascending (earliest first)
683
+ return moment(a.scheduled_datetime).valueOf() - moment(b.scheduled_datetime).valueOf();
684
+ });
685
+
686
+ const filteredRawContests = contestData.availableRawContests.filter(c =>
687
+ c.pretty_title.toLowerCase().includes(contestData.rawSearchValue.toLowerCase())
688
+ );
689
+
690
+ const totalRawPages = Math.ceil(filteredRawContests.length / RAW_CONTESTS_PER_PAGE);
691
+ const paginatedRawContests = filteredRawContests.slice(
692
+ contestData.rawPage * RAW_CONTESTS_PER_PAGE,
693
+ (contestData.rawPage + 1) * RAW_CONTESTS_PER_PAGE
694
+ );
695
+
696
+ if (contestData.loading) {
697
+ return (
698
+ <View transparent style={{ padding: 40, alignItems: 'center' }}>
699
+ <ActivityIndicator size="large" color={Colors.text.h1} />
700
+ </View>
701
+ );
702
+ }
703
+
704
+ return (
705
+ <>
706
+ <View transparent style={{ flex: 1 }}>
707
+ {/* Header */}
708
+ <View transparent style={{ marginBottom: 24 }}>
709
+ <Text theme='h1' size={24}>Contests</Text>
710
+ <Text theme='description' size={14} style={{ marginTop: 8 }}>
711
+ {league.name} - Manage contests and partner mappings
712
+ </Text>
713
+ </View>
714
+
715
+ {/* Load Raw Contests Section */}
716
+ <View type='body' style={{ padding: 16, marginBottom: 16, borderRadius: 8, borderWidth: 1, borderColor: Colors.borders.light }}>
717
+ <View type='header' style={{ padding: 16, marginBottom: 12 }}>
718
+ <Text theme='h2' size={16}>Load Raw Contests from Partners</Text>
719
+ <Text theme='description' size={12} style={{ marginTop: 4 }}>
720
+ Fetch contests from each partner's API
721
+ </Text>
722
+ </View>
723
+
724
+ <View transparent style={{ paddingHorizontal: 16, paddingBottom: 16 }}>
725
+ {contestData.partners.map(partner => (
726
+ <View
727
+ key={partner.partner_id}
728
+ transparent
729
+ style={{
730
+ flexDirection: 'row',
731
+ alignItems: 'center',
732
+ marginBottom: 8,
733
+ padding: 12,
734
+ backgroundColor: Colors.views.header,
735
+ borderRadius: 6
736
+ }}
737
+ >
738
+ <Text theme='h2' size={13} style={{ flex: 1 }}>{partner.name}</Text>
739
+ <Button
740
+ type='action'
741
+ title="Load Contests"
742
+ onPress={() => loadRawContests(partner)}
743
+ style={{ paddingHorizontal: 15, paddingVertical: 8 }}
744
+ />
745
+ </View>
746
+ ))}
747
+ </View>
748
+ </View>
749
+
750
+ {/* Link Status Stats */}
751
+ <View transparent style={{ flexDirection: 'row', gap: 12, marginBottom: 16 }}>
752
+ {(() => {
753
+ const allCount = contestData.contests.length;
754
+ const completeCount = getContestsByStatus('complete').length;
755
+ const partialCount = getContestsByStatus('partial').length;
756
+ const noneCount = getContestsByStatus('none').length;
757
+
758
+ const stats = [
759
+ { status: 'all' as LinkStatus, label: 'All Contests', count: allCount, color: Colors.text.h1 },
760
+ { status: 'complete' as LinkStatus, label: 'Fully Linked', count: completeCount, color: Colors.text.success },
761
+ { status: 'partial' as LinkStatus, label: 'Partially Linked', count: partialCount, color: Colors.text.warning },
762
+ { status: 'none' as LinkStatus, label: 'Not Linked', count: noneCount, color: Colors.text.error },
763
+ ];
764
+
765
+ return stats.map(stat => (
766
+ <TouchableOpacity
767
+ key={stat.status}
768
+ onPress={() => setContestData(prev => ({ ...prev, linkStatusFilter: stat.status }))}
769
+ style={{
770
+ flex: 1,
771
+ padding: 16,
772
+ backgroundColor: Colors.views.header,
773
+ borderRadius: 8,
774
+ borderWidth: 2,
775
+ borderColor: contestData.linkStatusFilter === stat.status ? stat.color : Colors.borders.light,
776
+ }}
777
+ >
778
+ <Text theme='description' size={11} style={{ marginBottom: 4 }}>
779
+ {stat.label.toUpperCase()}
780
+ </Text>
781
+ <Text size={28} style={{ color: stat.color, fontWeight: '600' }}>
782
+ {stat.count}
783
+ </Text>
784
+ </TouchableOpacity>
785
+ ));
786
+ })()}
787
+ </View>
788
+
789
+ {/* Contests List */}
790
+ <View type='body' style={{ flex: 1, borderRadius: 8, borderWidth: 1, borderColor: Colors.borders.light, overflow: 'hidden' }}>
791
+ <View type='header' style={{ padding: 16 }}>
792
+ <View transparent style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
793
+ <View transparent>
794
+ <Text theme='h2' size={16}>Router Contests</Text>
795
+ <Text theme='description' size={12} style={{ marginTop: 4 }}>
796
+ {filteredContests.length} contest{filteredContests.length !== 1 ? 's' : ''}
797
+ {contestData.linkStatusFilter !== 'all' && ` (${contestData.linkStatusFilter})`}
798
+ </Text>
799
+ </View>
800
+ <View transparent style={{ flexDirection: 'row', gap: 8 }}>
801
+ <Button
802
+ type='action'
803
+ title="🔗 Auto-Link Contests"
804
+ onPress={() => setContestData(prev => ({ ...prev, showAutoLinkModal: true }))}
805
+ style={{ paddingHorizontal: 15, paddingVertical: 8 }}
806
+ />
807
+ <Button
808
+ type='action'
809
+ title="🔗 Auto-Link Markets"
810
+ onPress={async () => {
811
+ try {
812
+ setContestData(prev => ({ ...prev, loading: true }));
813
+ const markets = await BetRouterApi.BetRouter.MarketApi.getRouterMarkets();
814
+ setContestData(prev => ({
815
+ ...prev,
816
+ allRouterMarkets: Array.isArray(markets) ? markets : [],
817
+ showMarketAutoLinkModal: true,
818
+ loading: false
819
+ }));
820
+ } catch (error) {
821
+ console.error('Error loading router markets:', error);
822
+ alert('Error loading markets: ' + (error as any).message);
823
+ setContestData(prev => ({ ...prev, loading: false }));
824
+ }
825
+ }}
826
+ style={{ paddingHorizontal: 15, paddingVertical: 8 }}
827
+ />
828
+ </View>
829
+ </View>
830
+
831
+ <View transparent style={{ marginTop: 12 }}>
832
+ <SearchBox
833
+ placeholder="Search contests..."
834
+ onChange={(text) => setContestData(prev => ({ ...prev, searchValue: text }))}
835
+ hide_search_button={true}
836
+ />
837
+ </View>
838
+
839
+ {/* Date Filter */}
840
+ <View transparent style={{ marginTop: 12 }}>
841
+ <Text theme='description' size={11} style={{ marginBottom: 6, textTransform: 'uppercase' }}>
842
+ Filter by Date
843
+ </Text>
844
+ <View transparent style={{ flexDirection: 'row', gap: 8, flexWrap: 'wrap' }}>
845
+ {[
846
+ { value: 'all', label: 'All' },
847
+ { value: 'today', label: 'Today' },
848
+ { value: 'upcoming', label: 'Upcoming' },
849
+ { value: 'past', label: 'Past' }
850
+ ].map(filter => (
851
+ <TouchableOpacity
852
+ key={filter.value}
853
+ onPress={() => setContestData(prev => ({ ...prev, dateFilter: filter.value as any }))}
854
+ style={{
855
+ paddingHorizontal: 14,
856
+ paddingVertical: 7,
857
+ borderRadius: 6,
858
+ borderWidth: 1,
859
+ borderColor: contestData.dateFilter === filter.value ? Colors.text.success : Colors.borders.light,
860
+ backgroundColor: contestData.dateFilter === filter.value ? Colors.views.body : 'transparent'
861
+ }}
862
+ >
863
+ <Text
864
+ theme={contestData.dateFilter === filter.value ? 'h2' : 'description'}
865
+ size={12}
866
+ >
867
+ {filter.label}
868
+ </Text>
869
+ </TouchableOpacity>
870
+ ))}
871
+ </View>
872
+ </View>
873
+ </View>
874
+
875
+ <FlatList
876
+ data={filteredContests}
877
+ keyExtractor={(item) => item.router_contest_id}
878
+ renderItem={({ item: contest }) => {
879
+ const partnerCount = getUniquePartnerCountForContest(contest.router_contest_id);
880
+ const isExpanded = contestData.selectedContest?.router_contest_id === contest.router_contest_id;
881
+
882
+ return (
883
+ <View transparent style={{ borderBottomWidth: 1, borderBottomColor: Colors.borders.light }}>
884
+ {/* Contest Header */}
885
+ <TouchableOpacity
886
+ onPress={() => {
887
+ if (isExpanded) {
888
+ setContestData(prev => ({ ...prev, selectedContest: null }));
889
+ } else {
890
+ setContestData(prev => ({ ...prev, selectedContest: contest }));
891
+ // Load supported markets and partner markets when expanding
892
+ loadSupportedMarkets(contest);
893
+ loadPartnerMarketsForContest(contest);
894
+ }
895
+ }}
896
+ style={{
897
+ padding: 16,
898
+ backgroundColor: isExpanded ? Colors.views.header : 'transparent',
899
+ flexDirection: 'row',
900
+ alignItems: 'center'
901
+ }}
902
+ >
903
+ <Icons.ChevronIcon
904
+ direction={isExpanded ? 'down' : 'right'}
905
+ size={8}
906
+ color={Colors.text.h1}
907
+ />
908
+ <View transparent style={{ flex: 1, marginLeft: 12 }}>
909
+ <Text theme='h2' size={14}>{contest.contest_label}</Text>
910
+ <Text theme='description' size={11} style={{ marginTop: 2 }}>
911
+ {moment(contest.scheduled_datetime).format('ddd, MMM D, YYYY [at] h:mm A')} • {partnerCount} partner{partnerCount !== 1 ? 's' : ''}
912
+ </Text>
913
+ </View>
914
+ <View transparent style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
915
+ <Text theme='description' size={12}>Auto-fill:</Text>
916
+ <Switch
917
+ value={contest.auto_fill ?? false}
918
+ switch_type='on_off'
919
+ size={14}
920
+ onChange={async (value) => {
921
+ try {
922
+ await BetRouterApi.BetRouter.ContestApi.updateRouterContest(
923
+ contest.router_contest_id,
924
+ { auto_fill: value }
925
+ );
926
+ setContestData(prev => ({
927
+ ...prev,
928
+ contests: prev.contests.map(c =>
929
+ c.router_contest_id === contest.router_contest_id
930
+ ? { ...c, auto_fill: value }
931
+ : c
932
+ )
933
+ }));
934
+ } catch (error) {
935
+ console.error('Failed to update auto_fill:', error);
936
+ alert('Failed to update auto-fill setting');
937
+ }
938
+ }}
939
+ />
940
+ </View>
941
+ </TouchableOpacity>
942
+
943
+ {/* Expanded Contest Details with Tabs */}
944
+ {isExpanded && (
945
+ <View transparent style={{ paddingTop: 0 }}>
946
+ {/* Tabs */}
947
+ <View transparent style={{ flexDirection: 'row', borderBottomWidth: 1, borderBottomColor: Colors.borders.light, paddingHorizontal: 16 }}>
948
+ <TouchableOpacity
949
+ onPress={() => setContestData(prev => ({ ...prev, currentTab: 'partners' }))}
950
+ style={{
951
+ paddingVertical: 12,
952
+ paddingHorizontal: 16,
953
+ borderBottomWidth: contestData.currentTab === 'partners' ? 2 : 0,
954
+ borderBottomColor: Colors.text.action
955
+ }}
956
+ >
957
+ <Text
958
+ theme={contestData.currentTab === 'partners' ? 'h2' : 'description'}
959
+ size={13}
960
+ style={{ color: contestData.currentTab === 'partners' ? Colors.text.action : Colors.text.description }}
961
+ >
962
+ Partner Links
963
+ </Text>
964
+ </TouchableOpacity>
965
+ <TouchableOpacity
966
+ onPress={() => {
967
+ setContestData(prev => ({ ...prev, currentTab: 'markets' }));
968
+ loadSupportedMarkets(contest);
969
+ loadPartnerMarketsForContest(contest);
970
+ }}
971
+ style={{
972
+ paddingVertical: 12,
973
+ paddingHorizontal: 16,
974
+ borderBottomWidth: contestData.currentTab === 'markets' ? 2 : 0,
975
+ borderBottomColor: Colors.text.action
976
+ }}
977
+ >
978
+ <Text
979
+ theme={contestData.currentTab === 'markets' ? 'h2' : 'description'}
980
+ size={13}
981
+ style={{ color: contestData.currentTab === 'markets' ? Colors.text.action : Colors.text.description }}
982
+ >
983
+ Markets
984
+ </Text>
985
+ </TouchableOpacity>
986
+ </View>
987
+
988
+ {/* Tab Content */}
989
+ <View transparent style={{ padding: 16 }}>
990
+ {contestData.currentTab === 'partners' ? (
991
+ // Partners tab
992
+ <>
993
+ {contestData.partners.map(partner => {
994
+ const linked = isPartnerLinked(contest.router_contest_id, partner.partner_id);
995
+ const externalIds = getLinkedExternalIds(contest.router_contest_id, partner.partner_id);
996
+
997
+ return (
998
+ <View
999
+ key={partner.partner_id}
1000
+ transparent
1001
+ style={{
1002
+ padding: 12,
1003
+ marginBottom: 8,
1004
+ backgroundColor: Colors.views.header,
1005
+ borderRadius: 6,
1006
+ flexDirection: 'row',
1007
+ alignItems: 'center'
1008
+ }}
1009
+ >
1010
+ <View transparent style={{ flex: 1 }}>
1011
+ <View transparent style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
1012
+ <Text theme='h2' size={13}>{partner.name}</Text>
1013
+ {linked ? (
1014
+ <Icons.CheckCirlceIcon color={Colors.text.success} size={14} />
1015
+ ) : (
1016
+ <Text theme='description' size={11}>Not Linked</Text>
1017
+ )}
1018
+ </View>
1019
+ {linked && externalIds.length > 0 && (
1020
+ <Text theme='description' size={11} style={{ marginTop: 4 }}>
1021
+ External IDs: {externalIds.join(', ')}
1022
+ </Text>
1023
+ )}
1024
+ </View>
1025
+ <Button
1026
+ type='action'
1027
+ title={linked ? 'Manage Links' : 'Link'}
1028
+ onPress={() => openLinkModal(contest, partner)}
1029
+ style={{ paddingHorizontal: 12, paddingVertical: 6 }}
1030
+ />
1031
+ </View>
1032
+ );
1033
+ })}
1034
+ </>
1035
+ ) : (
1036
+ // Markets tab
1037
+ <>
1038
+ <Button
1039
+ type='action'
1040
+ title='Manage Markets'
1041
+ onPress={() => openManageMarketsModal(contest)}
1042
+ style={{ marginBottom: 16 }}
1043
+ />
1044
+
1045
+ {/* Loading indicator for markets */}
1046
+ {contestData.loadingMarkets ? (
1047
+ <View transparent style={{ padding: 40, alignItems: 'center' }}>
1048
+ <ActivityIndicator size="small" color={Colors.text.h1} />
1049
+ <Text theme='description' size={12} style={{ marginTop: 8 }}>Loading markets...</Text>
1050
+ </View>
1051
+ ) : contestData.marketContests.length === 0 ? (
1052
+ <Text theme='description' size={12} style={{ textAlign: 'center', padding: 20, opacity: 0.6 }}>
1053
+ No supported markets yet. Add a market above to get started.
1054
+ </Text>
1055
+ ) : (
1056
+ contestData.marketContests.map(marketContest => {
1057
+ const routerMarket = contestData.allRouterMarkets.find(rm => rm.router_market_id === marketContest.router_market_id);
1058
+ if (!routerMarket) return null;
1059
+
1060
+ return (
1061
+ <View
1062
+ key={marketContest.market_contest_id}
1063
+ transparent
1064
+ style={{
1065
+ marginBottom: 16,
1066
+ padding: 15,
1067
+ backgroundColor: Colors.views.header,
1068
+ borderRadius: 8,
1069
+ borderWidth: 1,
1070
+ borderColor: Colors.borders.light
1071
+ }}
1072
+ >
1073
+ <View transparent style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 10 }}>
1074
+ <Text theme='h2' size={14} style={{ flex: 1 }}>{routerMarket.market_label}</Text>
1075
+ <View transparent style={{ flexDirection: 'row', alignItems: 'center', gap: 12, marginRight: 12 }}>
1076
+ <Text theme='description' size={11}>Auto-fill:</Text>
1077
+ <Switch
1078
+ value={marketContest.auto_fill ?? false}
1079
+ switch_type='on_off'
1080
+ size={12}
1081
+ onChange={async (value) => {
1082
+ try {
1083
+ await BetRouterApi.BetRouter.MarketApi.updateMarketContest(
1084
+ marketContest.market_contest_id,
1085
+ { auto_fill: value }
1086
+ );
1087
+ setContestData(prev => ({
1088
+ ...prev,
1089
+ marketContests: prev.marketContests.map(mc =>
1090
+ mc.market_contest_id === marketContest.market_contest_id
1091
+ ? { ...mc, auto_fill: value }
1092
+ : mc
1093
+ )
1094
+ }));
1095
+ } catch (error) {
1096
+ console.error('Failed to update market auto_fill:', error);
1097
+ alert('Failed to update auto-fill setting');
1098
+ }
1099
+ }}
1100
+ />
1101
+ </View>
1102
+ <TouchableOpacity onPress={() => removeSupportedMarket(marketContest.market_contest_id, contest)}>
1103
+ <Text theme='description' size={12} style={{ color: Colors.text.warning }}>Remove</Text>
1104
+ </TouchableOpacity>
1105
+ </View>
1106
+
1107
+ <Text theme='description' size={11} style={{ marginBottom: 12 }}>
1108
+ {routerMarket.market_description}
1109
+ </Text>
1110
+
1111
+ {/* Partner Market Links */}
1112
+ <View transparent style={{ paddingTop: 8, borderTopWidth: 1, borderTopColor: Colors.borders.light }}>
1113
+ {contestData.partners.map(partner => {
1114
+ // No need to filter by router_contest_id - data is already scoped to this contest
1115
+ const partnerMarketsForThis = contestData.partnerMarkets.filter(
1116
+ pm => pm.router_market_id === routerMarket.router_market_id &&
1117
+ pm.partner_id === partner.partner_id
1118
+ );
1119
+ const isLinked = partnerMarketsForThis.length > 0;
1120
+
1121
+ return (
1122
+ <View
1123
+ key={partner.partner_id}
1124
+ transparent
1125
+ style={{
1126
+ flexDirection: 'row',
1127
+ alignItems: 'center',
1128
+ padding: 10,
1129
+ marginTop: 8
1130
+ }}
1131
+ >
1132
+ <View transparent style={{ flex: 1, flexDirection: 'row', alignItems: 'center', gap: 10 }}>
1133
+ <Text theme='description' size={12}>{partner.name}:</Text>
1134
+ {isLinked ? (
1135
+ <>
1136
+ <Icons.CheckCirlceIcon color={Colors.text.success} size={14} />
1137
+ <Text theme='description' size={11}>
1138
+ ({partnerMarketsForThis.length} linked)
1139
+ </Text>
1140
+ </>
1141
+ ) : (
1142
+ <Text theme='description' size={11}>❌ Not Linked</Text>
1143
+ )}
1144
+ </View>
1145
+ <View transparent style={{ flexDirection: 'row', gap: 8 }}>
1146
+ {isLinked && (
1147
+ <Button
1148
+ type='close'
1149
+ title='Inspect'
1150
+ onPress={() => inspectPartnerMarkets(marketContest, partner)}
1151
+ style={{ paddingHorizontal: 12, paddingVertical: 6 }}
1152
+ />
1153
+ )}
1154
+ <Button
1155
+ type='action'
1156
+ title={!isLinked ? 'Link Markets' : routerMarket.variable_required ? '+ Add Variable' : '+ Add More'}
1157
+ onPress={() => {
1158
+ if (!isLinked || !routerMarket.variable_required) {
1159
+ openLinkMarketsModal(marketContest, partner);
1160
+ } else {
1161
+ openAddVariableModal(marketContest, partner);
1162
+ }
1163
+ }}
1164
+ style={{ paddingHorizontal: 12, paddingVertical: 6 }}
1165
+ />
1166
+ </View>
1167
+ </View>
1168
+ );
1169
+ })}
1170
+ </View>
1171
+ </View>
1172
+ );
1173
+ })
1174
+ )}
1175
+ </>
1176
+ )}
1177
+ </View>
1178
+ </View>
1179
+ )}
1180
+ </View>
1181
+ );
1182
+ }}
1183
+ />
1184
+ </View>
1185
+
1186
+ {/* Link Modal */}
1187
+ {contestData.showLinkModal && (
1188
+ <View
1189
+ style={{
1190
+ position: 'absolute',
1191
+ top: 0,
1192
+ left: 0,
1193
+ right: 0,
1194
+ bottom: 0,
1195
+ backgroundColor: 'rgba(0,0,0,0.5)',
1196
+ justifyContent: 'center',
1197
+ alignItems: 'center',
1198
+ padding: 20
1199
+ }}
1200
+ >
1201
+ <View float style={{ width: '90%', maxWidth: 600, maxHeight: '80%', borderRadius: 8, overflow: 'hidden', flexDirection: 'column' }}>
1202
+ <View type='header' style={{ padding: 16, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
1203
+ <View transparent>
1204
+ <Text theme='h1' size={18}>Link Raw Contests</Text>
1205
+ <Text theme='description' size={12} style={{ marginTop: 4 }}>
1206
+ {contestData.selectedPartner?.name} → {contestData.selectedContest?.contest_label}
1207
+ </Text>
1208
+ </View>
1209
+ <TouchableOpacity onPress={() => setContestData(prev => ({ ...prev, showLinkModal: false }))}>
1210
+ <Icons.CloseIcon size={24} color={Colors.text.h1} />
1211
+ </TouchableOpacity>
1212
+ </View>
1213
+
1214
+ {/* Search in modal */}
1215
+ <View transparent style={{ padding: 16, paddingTop: 0 }}>
1216
+ <SearchBox
1217
+ placeholder="Search raw contests..."
1218
+ onChange={(text) => setContestData(prev => ({ ...prev, rawSearchValue: text, rawPage: 0 }))}
1219
+ hide_search_button={true}
1220
+ />
1221
+ </View>
1222
+
1223
+ {/* Results count */}
1224
+ <View transparent style={{ paddingHorizontal: 16, paddingBottom: 8 }}>
1225
+ <Text theme='description' size={12}>
1226
+ Showing {paginatedRawContests.length} of {filteredRawContests.length} contest{filteredRawContests.length !== 1 ? 's' : ''}
1227
+ </Text>
1228
+ </View>
1229
+
1230
+ <FlatList
1231
+ data={paginatedRawContests}
1232
+ keyExtractor={(item) => item.raw_contest_id}
1233
+ renderItem={({ item: rawContest }) => {
1234
+ const isSelected = contestData.selectedRawIds.includes(rawContest.raw_contest_id);
1235
+ return (
1236
+ <TouchableOpacity
1237
+ onPress={() => toggleRawContestSelection(rawContest.raw_contest_id)}
1238
+ style={{
1239
+ padding: 12,
1240
+ backgroundColor: isSelected ? Colors.views.header : Colors.views.body,
1241
+ borderBottomWidth: 1,
1242
+ borderBottomColor: Colors.borders.light,
1243
+ flexDirection: 'row',
1244
+ alignItems: 'center'
1245
+ }}
1246
+ >
1247
+ <View transparent style={{ width: 24, height: 24, marginRight: 12 }}>
1248
+ {isSelected && <Icons.CheckIcon color={Colors.text.success} size={20} />}
1249
+ </View>
1250
+ <View transparent style={{ flex: 1 }}>
1251
+ <Text theme='h2' size={13}>{rawContest.pretty_title}</Text>
1252
+ <Text theme='description' size={11} style={{ marginTop: 2 }}>
1253
+ {new Date(rawContest.scheduled_datetime).toLocaleString()} • {rawContest.external_id}
1254
+ </Text>
1255
+ </View>
1256
+ </TouchableOpacity>
1257
+ );
1258
+ }}
1259
+ />
1260
+
1261
+ {/* Pagination */}
1262
+ {totalRawPages > 1 && (
1263
+ <View transparent style={{ padding: 16, paddingTop: 8 }}>
1264
+ <Pagination
1265
+ offset={contestData.rawPage}
1266
+ pages={totalRawPages}
1267
+ onNext={() => setContestData(prev => ({ ...prev, rawPage: prev.rawPage + 1 }))}
1268
+ onPrevious={() => setContestData(prev => ({ ...prev, rawPage: prev.rawPage - 1 }))}
1269
+ />
1270
+ </View>
1271
+ )}
1272
+
1273
+ <View type='footer' style={{ padding: 16, flexDirection: 'row', justifyContent: 'flex-end', gap: 10 }}>
1274
+ <Button
1275
+ type='close'
1276
+ title="Cancel"
1277
+ onPress={() => setContestData(prev => ({ ...prev, showLinkModal: false }))}
1278
+ />
1279
+ <Button
1280
+ type='action'
1281
+ title={`Link ${contestData.selectedRawIds.length} Contest${contestData.selectedRawIds.length !== 1 ? 's' : ''}`}
1282
+ onPress={linkSelectedContests}
1283
+ disabled={contestData.selectedRawIds.length === 0}
1284
+ />
1285
+ </View>
1286
+ </View>
1287
+ </View>
1288
+ )}
1289
+ </View>
1290
+
1291
+ {/* Auto-Link Modal */}
1292
+ {contestData.showAutoLinkModal && (
1293
+ <View
1294
+ style={{
1295
+ position: 'fixed' as any,
1296
+ top: 0,
1297
+ left: 0,
1298
+ right: 0,
1299
+ bottom: 0,
1300
+ backgroundColor: Colors.views.blur,
1301
+ justifyContent: 'center',
1302
+ alignItems: 'center',
1303
+ padding: 20,
1304
+ zIndex: 1000
1305
+ }}
1306
+ >
1307
+ <View float style={{ maxWidth: 500, width: '100%', borderRadius: 8, overflow: 'hidden' }}>
1308
+ <View type='header' style={{ padding: 20 }}>
1309
+ <Text theme='h1' size={18}>Auto-Link Contests</Text>
1310
+ <Text theme='description' size={14} style={{ marginTop: 5 }}>
1311
+ Select partner to automatically match and link contests
1312
+ </Text>
1313
+ </View>
1314
+
1315
+ <View type='body' style={{ padding: 20 }}>
1316
+ <Text theme='description' size={12} style={{ marginBottom: 15 }}>
1317
+ This will attempt to automatically match contests based on scheduled time and participants.
1318
+ </Text>
1319
+
1320
+ {contestData.partners.map(partner => {
1321
+ const linkedCount = contestData.partnerContests.filter(pc => pc.partner_id === partner.partner_id).length;
1322
+ const totalCount = contestData.contests.length;
1323
+
1324
+ return (
1325
+ <View
1326
+ key={partner.partner_id}
1327
+ transparent
1328
+ style={{
1329
+ flexDirection: 'row',
1330
+ alignItems: 'center',
1331
+ padding: 15,
1332
+ marginBottom: 10,
1333
+ backgroundColor: Colors.views.header,
1334
+ borderRadius: 8
1335
+ }}
1336
+ >
1337
+ <View transparent style={{ flex: 1 }}>
1338
+ <Text theme='h2' size={14}>{partner.name}</Text>
1339
+ <Text theme='description' size={11} style={{ marginTop: 3 }}>
1340
+ {linkedCount}/{totalCount} contests linked
1341
+ </Text>
1342
+ </View>
1343
+ <Button
1344
+ type='action'
1345
+ title='Auto-Link'
1346
+ onPress={async () => {
1347
+ try {
1348
+ setContestData(prev => ({ ...prev, loading: true }));
1349
+ const result = await BetRouterApi.BetRouter.AutoLinkingApi.autoLinkContests(
1350
+ league.router_league_id,
1351
+ partner.partner_id
1352
+ );
1353
+ setContestData(prev => ({
1354
+ ...prev,
1355
+ autoLinkResults: result,
1356
+ showAutoLinkModal: false,
1357
+ showAutoLinkResults: true
1358
+ }));
1359
+
1360
+ // Reload partner contests
1361
+ const allPartnerContests = await BetRouterApi.BetRouter.ContestApi.getPartnerContests();
1362
+ setContestData(prev => ({
1363
+ ...prev,
1364
+ partnerContests: Array.isArray(allPartnerContests) ? allPartnerContests : [],
1365
+ loading: false
1366
+ }));
1367
+ } catch (error) {
1368
+ console.error('Error auto-linking contests:', error);
1369
+ alert('Error auto-linking contests: ' + (error as any).message);
1370
+ setContestData(prev => ({ ...prev, loading: false }));
1371
+ }
1372
+ }}
1373
+ style={{ paddingHorizontal: 15, paddingVertical: 8 }}
1374
+ />
1375
+ </View>
1376
+ );
1377
+ })}
1378
+ </View>
1379
+
1380
+ <View type='footer' style={{ padding: 15 }}>
1381
+ <Button
1382
+ type='close'
1383
+ title='Cancel'
1384
+ onPress={() => setContestData(prev => ({ ...prev, showAutoLinkModal: false }))}
1385
+ />
1386
+ </View>
1387
+ </View>
1388
+ </View>
1389
+ )}
1390
+
1391
+ {/* Auto-Link Results Modal */}
1392
+ {contestData.showAutoLinkResults && contestData.autoLinkResults && (
1393
+ <View
1394
+ style={{
1395
+ position: 'fixed' as any,
1396
+ top: 0,
1397
+ left: 0,
1398
+ right: 0,
1399
+ bottom: 0,
1400
+ backgroundColor: Colors.views.blur,
1401
+ justifyContent: 'center',
1402
+ alignItems: 'center',
1403
+ padding: 20,
1404
+ zIndex: 1000
1405
+ }}
1406
+ >
1407
+ <View float style={{ maxWidth: 600, width: '100%', maxHeight: '90%', borderRadius: 8, overflow: 'hidden' }}>
1408
+ <View type='header' style={{ padding: 20 }}>
1409
+ <Text theme='h1' size={18}>Auto-Link Results</Text>
1410
+ <Text theme='description' size={14} style={{ marginTop: 5 }}>
1411
+ {contestData.autoLinkResults.partner_name} • {league.name}
1412
+ </Text>
1413
+ </View>
1414
+
1415
+ <ScrollView style={{ flex: 1 }}>
1416
+ <View transparent style={{ padding: 20 }}>
1417
+ {/* Summary */}
1418
+ <View type='body' style={{ padding: 16, borderRadius: 8, marginBottom: 16 }}>
1419
+ <Text theme='h2' size={16} style={{ marginBottom: 12 }}>Summary</Text>
1420
+ <Text theme='description' size={13} style={{ marginBottom: 6 }}>
1421
+ Successfully linked: {contestData.autoLinkResults.matched_count}/{contestData.autoLinkResults.total_router_entities} contests
1422
+ </Text>
1423
+ {contestData.autoLinkResults.failed_count > 0 && (
1424
+ <Text theme='description' size={13} style={{ color: Colors.text.warning }}>
1425
+ Failed: {contestData.autoLinkResults.failed_count} contests
1426
+ </Text>
1427
+ )}
1428
+ </View>
1429
+
1430
+ {/* Failed Results */}
1431
+ {contestData.autoLinkResults.results.filter((r: any) => !r.success).length > 0 && (
1432
+ <View type='body' style={{ padding: 16, borderRadius: 8 }}>
1433
+ <Text theme='h2' size={16} style={{ marginBottom: 12 }}>Failed Matches</Text>
1434
+ {contestData.autoLinkResults.results.filter((r: any) => !r.success).map((result: any, index: number) => (
1435
+ <View
1436
+ key={index}
1437
+ transparent
1438
+ style={{
1439
+ padding: 12,
1440
+ marginBottom: 8,
1441
+ backgroundColor: Colors.views.header,
1442
+ borderRadius: 6
1443
+ }}
1444
+ >
1445
+ <Text theme='h2' size={13}>{result.router_entity_label}</Text>
1446
+ <Text theme='description' size={11} style={{ marginTop: 4, color: Colors.text.warning }}>
1447
+ {result.error || 'No matches found'}
1448
+ </Text>
1449
+ </View>
1450
+ ))}
1451
+ </View>
1452
+ )}
1453
+ </View>
1454
+ </ScrollView>
1455
+
1456
+ <View type='footer' style={{ padding: 15 }}>
1457
+ <Button
1458
+ type='action'
1459
+ title='Done'
1460
+ onPress={() => setContestData(prev => ({
1461
+ ...prev,
1462
+ showAutoLinkResults: false,
1463
+ autoLinkResults: null
1464
+ }))}
1465
+ />
1466
+ </View>
1467
+ </View>
1468
+ </View>
1469
+ )}
1470
+
1471
+ {/* Market Auto-Link Modal */}
1472
+ {contestData.showMarketAutoLinkModal && (
1473
+ <View
1474
+ style={{
1475
+ position: 'fixed' as any,
1476
+ top: 0,
1477
+ left: 0,
1478
+ right: 0,
1479
+ bottom: 0,
1480
+ backgroundColor: Colors.views.blur,
1481
+ justifyContent: 'center',
1482
+ alignItems: 'center',
1483
+ padding: 20,
1484
+ zIndex: 1000
1485
+ }}
1486
+ >
1487
+ <View float style={{ maxWidth: 700, width: '100%', maxHeight: '90%', borderRadius: 8, overflow: 'hidden' }}>
1488
+ <View type='header' style={{ padding: 20 }}>
1489
+ <Text theme='h1' size={18}>Auto-Link Markets</Text>
1490
+ <Text theme='description' size={14} style={{ marginTop: 5 }}>
1491
+ Select markets and partner to auto-link
1492
+ </Text>
1493
+ </View>
1494
+
1495
+ <ScrollView style={{ flex: 1 }}>
1496
+ <View transparent style={{ padding: 20 }}>
1497
+ {/* Market Selection */}
1498
+ <Text theme='h2' size={14} style={{ marginBottom: 10 }}>
1499
+ Select Markets:
1500
+ </Text>
1501
+ <Text theme='description' size={12} style={{ marginBottom: 15 }}>
1502
+ Choose which markets to auto-link for the selected partner
1503
+ </Text>
1504
+
1505
+ {contestData.allRouterMarkets.filter(m => m.status === 'active').map(market => {
1506
+ const isSelected = contestData.selectedMarketIds.includes(market.router_market_id);
1507
+ return (
1508
+ <TouchableOpacity
1509
+ key={market.router_market_id}
1510
+ style={{
1511
+ padding: 12,
1512
+ marginBottom: 8,
1513
+ backgroundColor: isSelected ? Colors.text.action : Colors.views.header,
1514
+ borderRadius: 6,
1515
+ borderWidth: isSelected ? 2 : 1,
1516
+ borderColor: isSelected ? Colors.text.action : Colors.borders.light
1517
+ }}
1518
+ onPress={() => {
1519
+ setContestData(prev => ({
1520
+ ...prev,
1521
+ selectedMarketIds: isSelected
1522
+ ? prev.selectedMarketIds.filter(id => id !== market.router_market_id)
1523
+ : [...prev.selectedMarketIds, market.router_market_id]
1524
+ }));
1525
+ }}
1526
+ >
1527
+ <View transparent style={{ flexDirection: 'row', alignItems: 'center', gap: 10 }}>
1528
+ <View
1529
+ style={{
1530
+ width: 20,
1531
+ height: 20,
1532
+ borderRadius: 4,
1533
+ borderWidth: 2,
1534
+ borderColor: isSelected ? Colors.text.success : Colors.borders.light,
1535
+ backgroundColor: isSelected ? Colors.text.success : 'transparent',
1536
+ justifyContent: 'center',
1537
+ alignItems: 'center'
1538
+ }}
1539
+ >
1540
+ {isSelected && <Icons.CheckIcon color={Colors.text.white} size={12} />}
1541
+ </View>
1542
+ <View transparent style={{ flex: 1 }}>
1543
+ <Text theme='h2' size={13}>{market.market_label}</Text>
1544
+ <Text theme='description' size={11} style={{ marginTop: 2 }}>
1545
+ {market.market_description}
1546
+ </Text>
1547
+ </View>
1548
+ </View>
1549
+ </TouchableOpacity>
1550
+ );
1551
+ })}
1552
+
1553
+ {/* Partner Selection */}
1554
+ <Text theme='h2' size={14} style={{ marginTop: 20, marginBottom: 10 }}>
1555
+ Select Partner:
1556
+ </Text>
1557
+ {contestData.partners.map(partner => (
1558
+ <View
1559
+ key={partner.partner_id}
1560
+ transparent
1561
+ style={{
1562
+ marginBottom: 10,
1563
+ padding: 15,
1564
+ backgroundColor: Colors.views.header,
1565
+ borderRadius: 8,
1566
+ flexDirection: 'row',
1567
+ alignItems: 'center',
1568
+ justifyContent: 'space-between'
1569
+ }}
1570
+ >
1571
+ <Text theme='h2' size={14}>{partner.name}</Text>
1572
+ <Button
1573
+ type='action'
1574
+ title='Auto-Link'
1575
+ onPress={async () => {
1576
+ if (contestData.selectedMarketIds.length === 0) {
1577
+ alert('Please select at least one market');
1578
+ return;
1579
+ }
1580
+
1581
+ try {
1582
+ setContestData(prev => ({ ...prev, loading: true }));
1583
+ const results = [];
1584
+
1585
+ // Call auto-link for each selected market
1586
+ for (const marketId of contestData.selectedMarketIds) {
1587
+ const result = await BetRouterApi.BetRouter.AutoLinkingApi.autoLinkMarkets(
1588
+ league.router_league_id,
1589
+ marketId,
1590
+ partner.partner_id
1591
+ );
1592
+ results.push(result);
1593
+ }
1594
+
1595
+ // Combine results
1596
+ const combinedResults = {
1597
+ entity_type: 'market',
1598
+ partner_name: partner.name,
1599
+ total_router_entities: results.reduce((sum, r) => sum + r.total_router_entities, 0),
1600
+ matched_count: results.reduce((sum, r) => sum + r.matched_count, 0),
1601
+ created_count: results.reduce((sum, r) => sum + (r.created_count || 0), 0),
1602
+ updated_count: results.reduce((sum, r) => sum + (r.updated_count || 0), 0),
1603
+ failed_count: results.reduce((sum, r) => sum + r.failed_count, 0),
1604
+ results: results.flatMap(r => r.results)
1605
+ };
1606
+
1607
+ setContestData(prev => ({
1608
+ ...prev,
1609
+ autoLinkResults: combinedResults,
1610
+ showMarketAutoLinkModal: false,
1611
+ showAutoLinkResults: true,
1612
+ selectedMarketIds: [],
1613
+ loading: false
1614
+ }));
1615
+ } catch (error) {
1616
+ console.error('Error auto-linking markets:', error);
1617
+ alert('Error auto-linking markets: ' + (error as any).message);
1618
+ setContestData(prev => ({ ...prev, loading: false }));
1619
+ }
1620
+ }}
1621
+ style={{ paddingHorizontal: 15, paddingVertical: 8 }}
1622
+ />
1623
+ </View>
1624
+ ))}
1625
+ </View>
1626
+ </ScrollView>
1627
+
1628
+ <View type='footer' style={{ padding: 15 }}>
1629
+ <Button
1630
+ type='close'
1631
+ title='Cancel'
1632
+ onPress={() => setContestData(prev => ({
1633
+ ...prev,
1634
+ showMarketAutoLinkModal: false,
1635
+ selectedMarketIds: []
1636
+ }))}
1637
+ />
1638
+ </View>
1639
+ </View>
1640
+ </View>
1641
+ )}
1642
+
1643
+ {/* Manage Markets Modal */}
1644
+ {contestData.showManageMarketsModal && contestData.selectedContest && (
1645
+ <View
1646
+ style={{
1647
+ position: 'fixed' as any,
1648
+ top: 0,
1649
+ left: 0,
1650
+ right: 0,
1651
+ bottom: 0,
1652
+ backgroundColor: Colors.views.blur,
1653
+ justifyContent: 'center',
1654
+ alignItems: 'center',
1655
+ padding: 20,
1656
+ zIndex: 1000
1657
+ }}
1658
+ >
1659
+ <View float style={{ maxWidth: 600, width: '100%', maxHeight: '80%', borderRadius: 8, overflow: 'hidden' }}>
1660
+ <View type='header' style={{ padding: 20 }}>
1661
+ <Text theme='h1' size={18}>Manage Markets</Text>
1662
+ <Text theme='description' size={14} style={{ marginTop: 5 }}>
1663
+ Select which markets are supported for "{contestData.selectedContest.contest_label}"
1664
+ </Text>
1665
+ </View>
1666
+
1667
+ <ScrollView style={{ flex: 1 }}>
1668
+ <View transparent style={{ padding: 20 }}>
1669
+ {contestData.allRouterMarkets.length === 0 ? (
1670
+ <Text theme='description' size={13} style={{ textAlign: 'center', padding: 20 }}>
1671
+ No markets available
1672
+ </Text>
1673
+ ) : (
1674
+ contestData.allRouterMarkets.map(market => {
1675
+ const isSupported = contestData.marketContests.some(mc => mc.router_market_id === market.router_market_id);
1676
+ return (
1677
+ <TouchableOpacity
1678
+ key={market.router_market_id}
1679
+ style={{
1680
+ padding: 15,
1681
+ marginBottom: 10,
1682
+ backgroundColor: isSupported ? Colors.text.action : Colors.views.header,
1683
+ borderRadius: 8,
1684
+ borderWidth: isSupported ? 2 : 1,
1685
+ borderColor: isSupported ? Colors.text.success : Colors.borders.light
1686
+ }}
1687
+ onPress={() => toggleMarketSupport(market.router_market_id)}
1688
+ >
1689
+ <View transparent style={{ flexDirection: 'row', alignItems: 'center' }}>
1690
+ <View transparent style={{ marginRight: 10 }}>
1691
+ {isSupported ? (
1692
+ <Icons.CheckCirlceIcon color={Colors.text.success} size={20} />
1693
+ ) : (
1694
+ <View
1695
+ style={{
1696
+ width: 20,
1697
+ height: 20,
1698
+ borderWidth: 2,
1699
+ borderColor: Colors.borders.light,
1700
+ borderRadius: 4
1701
+ }}
1702
+ />
1703
+ )}
1704
+ </View>
1705
+ <View transparent style={{ flex: 1 }}>
1706
+ <Text theme='h2' size={14}>{market.market_label}</Text>
1707
+ <Text theme='description' size={12} style={{ marginTop: 3 }}>
1708
+ {market.market_description}
1709
+ </Text>
1710
+ {isSupported && (
1711
+ <Text theme='description' size={12} style={{ marginTop: 3, color: Colors.text.success }}>
1712
+ ✓ Currently Active
1713
+ </Text>
1714
+ )}
1715
+ </View>
1716
+ </View>
1717
+ </TouchableOpacity>
1718
+ );
1719
+ })
1720
+ )}
1721
+ </View>
1722
+ </ScrollView>
1723
+
1724
+ <View type='footer' style={{ padding: 15 }}>
1725
+ <Button
1726
+ type='action'
1727
+ title='Done'
1728
+ onPress={() => setContestData(prev => ({ ...prev, showManageMarketsModal: false }))}
1729
+ />
1730
+ </View>
1731
+ </View>
1732
+ </View>
1733
+ )}
1734
+
1735
+ {/* Link Markets Modal */}
1736
+ {contestData.showLinkMarketsModal && contestData.selectedMarketContest && contestData.selectedPartner && (
1737
+ <View
1738
+ style={{
1739
+ position: 'fixed' as any,
1740
+ top: 0,
1741
+ left: 0,
1742
+ right: 0,
1743
+ bottom: 0,
1744
+ backgroundColor: Colors.views.blur,
1745
+ justifyContent: 'center',
1746
+ alignItems: 'center',
1747
+ padding: 20,
1748
+ zIndex: 1000
1749
+ }}
1750
+ >
1751
+ <View float style={{ width: '90%', maxWidth: 600, maxHeight: '80%', borderRadius: 8, overflow: 'hidden', flexDirection: 'column' }}>
1752
+ <View type='header' style={{ padding: 16, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
1753
+ <View transparent>
1754
+ <Text theme='h1' size={18}>Link Raw Markets</Text>
1755
+ <Text theme='description' size={12} style={{ marginTop: 4 }}>
1756
+ {contestData.selectedPartner.name} → {contestData.allRouterMarkets.find(m => m.router_market_id === contestData.selectedMarketContest?.router_market_id)?.market_label}
1757
+ </Text>
1758
+ </View>
1759
+ <TouchableOpacity onPress={() => setContestData(prev => ({ ...prev, showLinkMarketsModal: false }))}>
1760
+ <Icons.CloseIcon size={24} color={Colors.text.h1} />
1761
+ </TouchableOpacity>
1762
+ </View>
1763
+
1764
+ {/* Already Linked Section */}
1765
+ {contestData.alreadyLinkedRawMarkets.length > 0 && (
1766
+ <View transparent style={{ padding: 16, paddingTop: 0 }}>
1767
+ <Text theme='h2' size={13} style={{ marginBottom: 8 }}>Already Linked:</Text>
1768
+ {contestData.alreadyLinkedRawMarkets.map(raw => (
1769
+ <View
1770
+ key={raw.raw_market_id}
1771
+ transparent
1772
+ style={{
1773
+ padding: 8,
1774
+ marginBottom: 4,
1775
+ backgroundColor: Colors.views.header,
1776
+ borderRadius: 4
1777
+ }}
1778
+ >
1779
+ <Text theme='description' size={12}>{raw.pretty_title} ({raw.external_id})</Text>
1780
+ </View>
1781
+ ))}
1782
+ </View>
1783
+ )}
1784
+
1785
+ <ScrollView style={{ flex: 1 }}>
1786
+ <View transparent style={{ padding: 16 }}>
1787
+ <Text theme='h2' size={13} style={{ marginBottom: 8 }}>Available Raw Markets:</Text>
1788
+ {contestData.availableRawMarkets.length === 0 ? (
1789
+ <Text theme='description' size={12} style={{ textAlign: 'center', padding: 20, opacity: 0.6 }}>
1790
+ No available raw markets to link
1791
+ </Text>
1792
+ ) : (
1793
+ contestData.availableRawMarkets.map(rawMarket => (
1794
+ <View
1795
+ key={rawMarket.raw_market_id}
1796
+ transparent
1797
+ style={{
1798
+ padding: 12,
1799
+ marginBottom: 8,
1800
+ backgroundColor: Colors.views.header,
1801
+ borderRadius: 6,
1802
+ borderWidth: 1,
1803
+ borderColor: Colors.borders.light
1804
+ }}
1805
+ >
1806
+ <View transparent style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
1807
+ <View transparent style={{ flex: 1 }}>
1808
+ <Text theme='h2' size={13}>{rawMarket.pretty_title}</Text>
1809
+ <Text theme='description' size={11} style={{ marginTop: 2 }}>
1810
+ External ID: {rawMarket.external_id}
1811
+ </Text>
1812
+ </View>
1813
+ <Button
1814
+ type='action'
1815
+ title='Link'
1816
+ onPress={() => openManualLinkModal(rawMarket)}
1817
+ style={{ paddingHorizontal: 12, paddingVertical: 6 }}
1818
+ />
1819
+ </View>
1820
+ </View>
1821
+ ))
1822
+ )}
1823
+ </View>
1824
+ </ScrollView>
1825
+
1826
+ <View type='footer' style={{ padding: 16 }}>
1827
+ <Button
1828
+ type='close'
1829
+ title="Close"
1830
+ onPress={() => setContestData(prev => ({ ...prev, showLinkMarketsModal: false }))}
1831
+ />
1832
+ </View>
1833
+ </View>
1834
+ </View>
1835
+ )}
1836
+
1837
+ {/* Add Variable Modal */}
1838
+ {contestData.showAddVariableModal && contestData.selectedMarketContest && contestData.selectedPartner && (
1839
+ <View
1840
+ style={{
1841
+ position: 'fixed' as any,
1842
+ top: 0,
1843
+ left: 0,
1844
+ right: 0,
1845
+ bottom: 0,
1846
+ backgroundColor: Colors.views.blur,
1847
+ justifyContent: 'center',
1848
+ alignItems: 'center',
1849
+ padding: 20,
1850
+ zIndex: 1000
1851
+ }}
1852
+ >
1853
+ <View float style={{ maxWidth: 500, width: '100%', borderRadius: 8, overflow: 'hidden' }}>
1854
+ <View type='header' style={{ padding: 20 }}>
1855
+ <Text theme='h1' size={18}>Add Variable</Text>
1856
+ <Text theme='description' size={14} style={{ marginTop: 5 }}>
1857
+ {contestData.selectedPartner.name} • {contestData.allRouterMarkets.find(m => m.router_market_id === contestData.selectedMarketContest?.router_market_id)?.market_label}
1858
+ </Text>
1859
+ </View>
1860
+
1861
+ <View type='body' style={{ padding: 20 }}>
1862
+ {(() => {
1863
+ const routerMarket = contestData.allRouterMarkets.find(
1864
+ m => m.router_market_id === contestData.selectedMarketContest?.router_market_id
1865
+ );
1866
+ const variableType = routerMarket?.default_variable_type || 'spread';
1867
+
1868
+ // Try to find home participant from existing partner markets
1869
+ const homeSide = contestData.marketSides.find(s => s.router_market_id === routerMarket?.router_market_id && s.side_key === 'home');
1870
+ const existingHomeMarket = contestData.inspectPartnerMarkets.length > 0
1871
+ ? contestData.inspectPartnerMarkets.find(pm => pm.market_side_id === homeSide?.market_side_id)
1872
+ : contestData.partnerMarkets.find(pm =>
1873
+ pm.router_market_id === routerMarket?.router_market_id &&
1874
+ pm.market_side_id === homeSide?.market_side_id &&
1875
+ pm.router_contest_id === contestData.selectedContest?.router_contest_id
1876
+ );
1877
+ const homeParticipantId = existingHomeMarket?.partner_participant_id;
1878
+
1879
+ return (
1880
+ <>
1881
+ <Text theme='description' size={13} style={{ marginBottom: 15 }}>
1882
+ {variableType === 'spread'
1883
+ ? 'Enter the spread value from the HOME team\'s perspective. For example, if the home team is favored by 7 points, enter -7. This creates home -7 and away +7.'
1884
+ : 'Enter the total value (e.g., 220.5 for over/under 220.5). This will automatically create both over and under sides.'}
1885
+ </Text>
1886
+
1887
+ {homeParticipantId && (() => {
1888
+ const participantName = getParticipantName(homeParticipantId);
1889
+ return (
1890
+ <View transparent style={{ padding: 10, backgroundColor: Colors.views.header, borderRadius: 6, marginBottom: 12 }}>
1891
+ <Text theme='description' size={11} style={{ marginBottom: 4 }}>Home Team:</Text>
1892
+ <Text theme='h2' size={12}>
1893
+ {participantName || homeParticipantId}
1894
+ </Text>
1895
+ {participantName && (
1896
+ <Text theme='description' size={10} style={{ marginTop: 2 }}>
1897
+ ID: {homeParticipantId}
1898
+ </Text>
1899
+ )}
1900
+ </View>
1901
+ );
1902
+ })()}
1903
+
1904
+ <Text theme='h2' size={13} style={{ marginBottom: 8 }}>
1905
+ {variableType === 'spread' ? 'Home Team Spread:' : 'Total Value:'}
1906
+ </Text>
1907
+
1908
+ <TextInput
1909
+ style={{
1910
+ padding: 12,
1911
+ borderWidth: 1,
1912
+ borderColor: Colors.borders.light,
1913
+ borderRadius: 6,
1914
+ backgroundColor: Colors.views.header,
1915
+ color: Colors.text.h1,
1916
+ fontSize: 14
1917
+ }}
1918
+ value={contestData.newVariableValue}
1919
+ onChangeText={(text) => setContestData(prev => ({ ...prev, newVariableValue: text }))}
1920
+ placeholder={variableType === 'spread' ? 'e.g., -7 or +3.5' : 'e.g., 220.5'}
1921
+ placeholderTextColor={Colors.text.description}
1922
+ keyboardType="numeric"
1923
+ />
1924
+
1925
+ {variableType === 'spread' && contestData.newVariableValue && !isNaN(parseFloat(contestData.newVariableValue)) && (
1926
+ <Text theme='description' size={11} style={{ marginTop: 8, fontStyle: 'italic' }}>
1927
+ Will create: Home {contestData.newVariableValue} / Away {parseFloat(contestData.newVariableValue) * -1}
1928
+ </Text>
1929
+ )}
1930
+
1931
+ <Text theme='description' size={11} style={{ marginTop: 10, fontStyle: 'italic' }}>
1932
+ This will create partner markets for all raw markets from {contestData.selectedPartner.name} that match this contest.
1933
+ </Text>
1934
+ </>
1935
+ );
1936
+ })()}
1937
+ </View>
1938
+
1939
+ <View type='footer' style={{ padding: 15, flexDirection: 'row', gap: 10, justifyContent: 'flex-end' }}>
1940
+ <Button
1941
+ type='close'
1942
+ title='Cancel'
1943
+ onPress={() => setContestData(prev => ({
1944
+ ...prev,
1945
+ showAddVariableModal: false,
1946
+ newVariableValue: ''
1947
+ }))}
1948
+ />
1949
+ <Button
1950
+ type='action'
1951
+ title='Add Variable'
1952
+ onPress={addVariable}
1953
+ disabled={!contestData.newVariableValue || isNaN(parseFloat(contestData.newVariableValue))}
1954
+ />
1955
+ </View>
1956
+ </View>
1957
+ </View>
1958
+ )}
1959
+
1960
+ {/* Inspect Partner Markets Modal */}
1961
+ {contestData.showInspectModal && contestData.selectedMarketContest && contestData.selectedPartner && (
1962
+ <View
1963
+ style={{
1964
+ position: 'fixed' as any,
1965
+ top: 0,
1966
+ left: 0,
1967
+ right: 0,
1968
+ bottom: 0,
1969
+ backgroundColor: Colors.views.blur,
1970
+ justifyContent: 'center',
1971
+ alignItems: 'center',
1972
+ padding: 20,
1973
+ zIndex: 1000
1974
+ }}
1975
+ >
1976
+ <View float style={{ width: '90%', maxWidth: 800, maxHeight: '85%', borderRadius: 8, overflow: 'hidden', flexDirection: 'column' }}>
1977
+ <View type='header' style={{ padding: 16, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
1978
+ <View transparent>
1979
+ <Text theme='h1' size={18}>Partner Markets</Text>
1980
+ <Text theme='description' size={12} style={{ marginTop: 4 }}>
1981
+ {contestData.selectedPartner.name} • {contestData.allRouterMarkets.find(m => m.router_market_id === contestData.selectedMarketContest?.router_market_id)?.market_label}
1982
+ </Text>
1983
+ </View>
1984
+ <TouchableOpacity onPress={() => setContestData(prev => ({ ...prev, showInspectModal: false }))}>
1985
+ <Icons.CloseIcon size={24} color={Colors.text.h1} />
1986
+ </TouchableOpacity>
1987
+ </View>
1988
+
1989
+ <ScrollView style={{ flex: 1 }}>
1990
+ <View transparent style={{ padding: 16 }}>
1991
+ {contestData.inspectPartnerMarkets.length === 0 ? (
1992
+ <Text theme='description' size={13} style={{ textAlign: 'center', padding: 20 }}>
1993
+ No partner markets found
1994
+ </Text>
1995
+ ) : (
1996
+ <>
1997
+ <Text theme='h2' size={14} style={{ marginBottom: 12 }}>
1998
+ {contestData.inspectPartnerMarkets.length} Partner Market{contestData.inspectPartnerMarkets.length !== 1 ? 's' : ''}
1999
+ </Text>
2000
+ {contestData.inspectPartnerMarkets.map((pm, index) => {
2001
+ // Find enriched data
2002
+ const side = contestData.marketSides.find(s => s.market_side_id === pm.market_side_id);
2003
+ const variable = contestData.marketVariables.find(v => v.router_market_variable_id === pm.router_market_variable_id);
2004
+
2005
+ return (
2006
+ <View
2007
+ key={pm.partner_market_id}
2008
+ transparent
2009
+ style={{
2010
+ padding: 14,
2011
+ marginBottom: 10,
2012
+ backgroundColor: Colors.views.header,
2013
+ borderRadius: 8,
2014
+ borderWidth: 1,
2015
+ borderColor: Colors.borders.light
2016
+ }}
2017
+ >
2018
+ <View transparent style={{ flexDirection: 'row', justifyContent: 'space-between', marginBottom: 8 }}>
2019
+ <Text theme='h2' size={13}>
2020
+ {side ? `${side.side_key}` : `Partner Market #${index + 1}`}
2021
+ {variable ? ` (${variable.variable > 0 ? '+' : ''}${variable.variable})` : ''}
2022
+ </Text>
2023
+ <Text theme='description' size={11}>
2024
+ ID: {pm.partner_market_id.slice(0, 8)}...
2025
+ </Text>
2026
+ </View>
2027
+
2028
+ <View transparent style={{ gap: 6 }}>
2029
+ <View transparent style={{ flexDirection: 'row' }}>
2030
+ <Text theme='description' size={12} style={{ width: 160 }}>External ID:</Text>
2031
+ <Text theme='h2' size={12} style={{ flex: 1 }}>{pm.external_id}</Text>
2032
+ </View>
2033
+
2034
+ {side && (
2035
+ <View transparent style={{ flexDirection: 'row' }}>
2036
+ <Text theme='description' size={12} style={{ width: 160 }}>Side:</Text>
2037
+ <Text theme='h2' size={12} style={{ flex: 1 }}>
2038
+ {side.side_key} ({side.side_type})
2039
+ </Text>
2040
+ </View>
2041
+ )}
2042
+
2043
+ {variable && (
2044
+ <View transparent style={{ flexDirection: 'row' }}>
2045
+ <Text theme='description' size={12} style={{ width: 160 }}>Variable:</Text>
2046
+ <Text theme='h2' size={12} style={{ flex: 1 }}>
2047
+ {variable.variable} ({variable.variable_type})
2048
+ </Text>
2049
+ </View>
2050
+ )}
2051
+
2052
+ <View transparent style={{ flexDirection: 'row' }}>
2053
+ <Text theme='description' size={12} style={{ width: 160 }}>Raw Market ID:</Text>
2054
+ <Text theme='h2' size={12} style={{ flex: 1 }}>{pm.raw_market_id}</Text>
2055
+ </View>
2056
+
2057
+ {pm.partner_participant_id && (() => {
2058
+ const participantName = getParticipantName(pm.partner_participant_id);
2059
+ return (
2060
+ <View transparent style={{ flexDirection: 'row' }}>
2061
+ <Text theme='description' size={12} style={{ width: 160 }}>Participant:</Text>
2062
+ <View transparent style={{ flex: 1 }}>
2063
+ <Text theme='h2' size={12}>
2064
+ {participantName || pm.partner_participant_id}
2065
+ </Text>
2066
+ {participantName && (
2067
+ <Text theme='description' size={10} style={{ marginTop: 2 }}>
2068
+ ID: {pm.partner_participant_id}
2069
+ </Text>
2070
+ )}
2071
+ </View>
2072
+ </View>
2073
+ );
2074
+ })()}
2075
+
2076
+ {pm.timeframe_id && (
2077
+ <View transparent style={{ flexDirection: 'row' }}>
2078
+ <Text theme='description' size={12} style={{ width: 160 }}>Timeframe ID:</Text>
2079
+ <Text theme='h2' size={12} style={{ flex: 1 }}>{pm.timeframe_id}</Text>
2080
+ </View>
2081
+ )}
2082
+
2083
+ {pm.price_key && (
2084
+ <View transparent style={{ flexDirection: 'row' }}>
2085
+ <Text theme='description' size={12} style={{ width: 160 }}>Price Key:</Text>
2086
+ <Text theme='h2' size={12} style={{ flex: 1 }}>{pm.price_key}</Text>
2087
+ </View>
2088
+ )}
2089
+ </View>
2090
+ </View>
2091
+ );
2092
+ })}
2093
+ </>
2094
+ )}
2095
+ </View>
2096
+ </ScrollView>
2097
+
2098
+ <View type='footer' style={{ padding: 16 }}>
2099
+ <Button
2100
+ type='close'
2101
+ title="Close"
2102
+ onPress={() => setContestData(prev => ({ ...prev, showInspectModal: false }))}
2103
+ />
2104
+ </View>
2105
+ </View>
2106
+ </View>
2107
+ )}
2108
+
2109
+ {/* Manual Link Modal */}
2110
+ {contestData.showManualLinkModal && contestData.selectedRawMarket && contestData.linkingData && (
2111
+ <View
2112
+ style={{
2113
+ position: 'fixed' as any,
2114
+ top: 0,
2115
+ left: 0,
2116
+ right: 0,
2117
+ bottom: 0,
2118
+ backgroundColor: Colors.views.blur,
2119
+ justifyContent: 'center',
2120
+ alignItems: 'center',
2121
+ padding: 20,
2122
+ zIndex: 1000
2123
+ }}
2124
+ >
2125
+ <View float style={{ width: '90%', maxWidth: 600, maxHeight: '85%', borderRadius: 8, overflow: 'hidden', flexDirection: 'column' }}>
2126
+ {/* Header */}
2127
+ <View type='header' style={{ padding: 16, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
2128
+ <View transparent>
2129
+ <Text theme='h1' size={18}>Link Market</Text>
2130
+ <Text theme='description' size={12} style={{ marginTop: 4 }}>
2131
+ {contestData.selectedRawMarket.pretty_title}
2132
+ </Text>
2133
+ </View>
2134
+ <TouchableOpacity onPress={() => setContestData(prev => ({ ...prev, showManualLinkModal: false }))}>
2135
+ <Icons.CloseIcon size={24} color={Colors.text.h1} />
2136
+ </TouchableOpacity>
2137
+ </View>
2138
+
2139
+ {contestData.loadingModal ? (
2140
+ <View transparent style={{ padding: 40, alignItems: 'center' }}>
2141
+ <ActivityIndicator size="large" color={Colors.text.h1} />
2142
+ </View>
2143
+ ) : (
2144
+ <>
2145
+ <ScrollView style={{ flex: 1 }}>
2146
+ <View transparent style={{ padding: 16 }}>
2147
+ {(() => {
2148
+ const routerMarket = contestData.allRouterMarkets.find(
2149
+ m => m.router_market_id === contestData.selectedMarketContest?.router_market_id
2150
+ );
2151
+
2152
+ return (
2153
+ <>
2154
+ {/* Variable Input (if required) - at the top */}
2155
+ {routerMarket?.variable_required && (
2156
+ <View transparent style={{ marginBottom: 20 }}>
2157
+ <Text theme='h2' size={13} style={{ marginBottom: 8 }}>
2158
+ {routerMarket.default_variable_type === 'spread' ? 'Spread' : 'Total'} Value: <Text theme='error' size={13}>*</Text>
2159
+ </Text>
2160
+ <TextInput
2161
+ value={contestData.manualLinkForm.variable}
2162
+ onChangeText={(text) => setContestData(prev => ({
2163
+ ...prev,
2164
+ manualLinkForm: { ...prev.manualLinkForm, variable: text }
2165
+ }))}
2166
+ placeholder={routerMarket.default_variable_type === 'spread' ? 'e.g., -7 or +3.5' : 'e.g., 220.5'}
2167
+ keyboardType="numeric"
2168
+ style={{
2169
+ padding: 12,
2170
+ borderWidth: 1,
2171
+ borderColor: Colors.borders.light,
2172
+ borderRadius: 6,
2173
+ backgroundColor: Colors.views.header,
2174
+ color: Colors.text.h1,
2175
+ fontSize: 14
2176
+ }}
2177
+ />
2178
+ </View>
2179
+ )}
2180
+
2181
+ {/* Side Toggle */}
2182
+ <View transparent style={{ marginBottom: 20 }}>
2183
+ <Text theme='h2' size={13} style={{ marginBottom: 8 }}>
2184
+ Select Side: <Text theme='error' size={13}>*</Text>
2185
+ </Text>
2186
+ <View transparent style={{ flexDirection: 'row', gap: 8 }}>
2187
+ {contestData.linkingData.market_sides.map((side, index) => {
2188
+ const sideParticipant = contestData.manualLinkForm.sideParticipants[index];
2189
+ const hasParticipant = !!sideParticipant?.partner_participant_id;
2190
+ const isSelected = contestData.selectedSideIndex === index;
2191
+
2192
+ return (
2193
+ <TouchableOpacity
2194
+ key={side.market_side_id}
2195
+ onPress={() => setContestData(prev => ({
2196
+ ...prev,
2197
+ selectedSideIndex: index,
2198
+ participantSearchValue: '',
2199
+ participantPage: 0
2200
+ }))}
2201
+ style={{
2202
+ flex: 1,
2203
+ padding: 12,
2204
+ backgroundColor: Colors.views.header,
2205
+ borderRadius: 6,
2206
+ borderWidth: 2,
2207
+ borderColor: isSelected ? Colors.text.success : Colors.borders.light,
2208
+ flexDirection: 'row',
2209
+ alignItems: 'center',
2210
+ justifyContent: 'center',
2211
+ gap: 6
2212
+ }}
2213
+ >
2214
+ <Text size={14} style={{
2215
+ color: isSelected ? Colors.text.success : Colors.text.h1,
2216
+ fontWeight: isSelected ? '600' : '400'
2217
+ }}>
2218
+ {side.side_key}
2219
+ </Text>
2220
+ {hasParticipant && (
2221
+ <Text size={14} style={{ color: Colors.text.success }}>✓</Text>
2222
+ )}
2223
+ </TouchableOpacity>
2224
+ );
2225
+ })}
2226
+ </View>
2227
+ </View>
2228
+
2229
+ {/* Participant Selection for Selected Side */}
2230
+ {(() => {
2231
+ const selectedSide = contestData.linkingData.market_sides[contestData.selectedSideIndex];
2232
+ const sideParticipant = contestData.manualLinkForm.sideParticipants[contestData.selectedSideIndex];
2233
+ const contestLeagueId = contestData.selectedContest?.router_league_id;
2234
+
2235
+ // Filter and paginate participants
2236
+ const searchFiltered = contestData.linkingData.participants.filter(p => {
2237
+ const searchLower = contestData.participantSearchValue.toLowerCase();
2238
+ return p.name.toLowerCase().includes(searchLower) ||
2239
+ p.raw_name.toLowerCase().includes(searchLower) ||
2240
+ p.external_id.toLowerCase().includes(searchLower);
2241
+ });
2242
+
2243
+ const leagueFiltered = searchFiltered.filter(p => {
2244
+ const routerParticipant = contestData.participants.find(
2245
+ rp => rp.participant_id === p.router_participant_id
2246
+ );
2247
+ return routerParticipant?.router_league_id === contestLeagueId;
2248
+ });
2249
+
2250
+ const totalPages = Math.ceil(leagueFiltered.length / PARTICIPANTS_PER_PAGE);
2251
+ const startIdx = contestData.participantPage * PARTICIPANTS_PER_PAGE;
2252
+ const endIdx = startIdx + PARTICIPANTS_PER_PAGE;
2253
+ const paginatedParticipants = leagueFiltered.slice(startIdx, endIdx);
2254
+
2255
+ return (
2256
+ <View transparent style={{ marginBottom: 20 }}>
2257
+ <Text theme='h2' size={13} style={{ marginBottom: 8 }}>
2258
+ Participant for {selectedSide?.side_key}: <Text theme='error' size={13}>*</Text>
2259
+ </Text>
2260
+ <Text theme='description' size={11} style={{ marginBottom: 12 }}>
2261
+ {leagueFiltered.length} participants available
2262
+ </Text>
2263
+
2264
+ {/* Search Box */}
2265
+ <View transparent style={{ marginBottom: 12 }}>
2266
+ <SearchBox
2267
+ placeholder="Search participants..."
2268
+ onChange={(text) => setContestData(prev => ({
2269
+ ...prev,
2270
+ participantSearchValue: text,
2271
+ participantPage: 0
2272
+ }))}
2273
+ hide_search_button={true}
2274
+ />
2275
+ </View>
2276
+
2277
+ {/* Participants List */}
2278
+ {paginatedParticipants.length === 0 ? (
2279
+ <Text theme='description' size={12} style={{ textAlign: 'center', padding: 20, opacity: 0.6 }}>
2280
+ {contestData.participantSearchValue
2281
+ ? 'No participants match your search'
2282
+ : 'No participants available for this league'}
2283
+ </Text>
2284
+ ) : (
2285
+ paginatedParticipants.map(participant => {
2286
+ const isSelected = sideParticipant?.partner_participant_id === participant.partner_participant_id;
2287
+ return (
2288
+ <TouchableOpacity
2289
+ key={participant.partner_participant_id}
2290
+ onPress={() => {
2291
+ setContestData(prev => ({
2292
+ ...prev,
2293
+ manualLinkForm: {
2294
+ ...prev.manualLinkForm,
2295
+ sideParticipants: prev.manualLinkForm.sideParticipants.map((sp, idx) =>
2296
+ idx === prev.selectedSideIndex
2297
+ ? { ...sp, partner_participant_id: participant.partner_participant_id }
2298
+ : sp
2299
+ )
2300
+ }
2301
+ }));
2302
+ }}
2303
+ style={{
2304
+ padding: 12,
2305
+ marginBottom: 6,
2306
+ backgroundColor: Colors.views.header,
2307
+ borderRadius: 6,
2308
+ borderWidth: 1,
2309
+ borderColor: isSelected ? Colors.text.success : Colors.borders.light
2310
+ }}
2311
+ >
2312
+ <Text size={13} style={{ color: isSelected ? Colors.text.success : Colors.text.h1, fontWeight: isSelected ? '600' : '400' }}>
2313
+ {participant.name}
2314
+ </Text>
2315
+ <Text theme='description' size={11} style={{ marginTop: 2 }}>
2316
+ {participant.raw_name} • External ID: {participant.external_id}
2317
+ </Text>
2318
+ </TouchableOpacity>
2319
+ );
2320
+ })
2321
+ )}
2322
+
2323
+ {/* Pagination */}
2324
+ {totalPages > 1 && (
2325
+ <View transparent style={{ marginTop: 12 }}>
2326
+ <Pagination
2327
+ offset={contestData.participantPage}
2328
+ pages={totalPages}
2329
+ onSelectPage={(page) => setContestData(prev => ({
2330
+ ...prev,
2331
+ participantPage: page
2332
+ }))}
2333
+ />
2334
+ </View>
2335
+ )}
2336
+ </View>
2337
+ );
2338
+ })()}
2339
+
2340
+ {/* Timeframe Selection (if available) */}
2341
+ {contestData.linkingData.timeframes.length > 0 && (
2342
+ <View transparent style={{ marginBottom: 20 }}>
2343
+ <Text theme='h2' size={13} style={{ marginBottom: 8 }}>
2344
+ Timeframe:
2345
+ </Text>
2346
+ {contestData.linkingData.timeframes.map(timeframe => {
2347
+ const isSelected = contestData.manualLinkForm.timeframe_id === timeframe.timeframe_id;
2348
+ return (
2349
+ <TouchableOpacity
2350
+ key={timeframe.timeframe_id}
2351
+ onPress={() => setContestData(prev => ({
2352
+ ...prev,
2353
+ manualLinkForm: { ...prev.manualLinkForm, timeframe_id: timeframe.timeframe_id }
2354
+ }))}
2355
+ style={{
2356
+ padding: 12,
2357
+ marginBottom: 6,
2358
+ backgroundColor: Colors.views.header,
2359
+ borderRadius: 6,
2360
+ borderWidth: 1,
2361
+ borderColor: isSelected ? Colors.text.success : Colors.borders.light
2362
+ }}
2363
+ >
2364
+ <Text size={13} style={{ color: isSelected ? Colors.text.success : Colors.text.h1, fontWeight: isSelected ? '600' : '400' }}>
2365
+ {timeframe.label}
2366
+ </Text>
2367
+ </TouchableOpacity>
2368
+ );
2369
+ })}
2370
+ </View>
2371
+ )}
2372
+
2373
+ {/* Price Key (optional, for specific partners like Kalshi) - Per Side */}
2374
+ {(() => {
2375
+ const selectedSide = contestData.linkingData.market_sides[contestData.selectedSideIndex];
2376
+ const sideParticipant = contestData.manualLinkForm.sideParticipants[contestData.selectedSideIndex];
2377
+
2378
+ return (
2379
+ <View transparent style={{ marginBottom: 20 }}>
2380
+ <Text theme='h2' size={13} style={{ marginBottom: 8 }}>
2381
+ Price Key for {selectedSide?.side_key} (optional):
2382
+ </Text>
2383
+ <TextInput
2384
+ value={sideParticipant?.price_key || ''}
2385
+ onChangeText={(text) => setContestData(prev => ({
2386
+ ...prev,
2387
+ manualLinkForm: {
2388
+ ...prev.manualLinkForm,
2389
+ sideParticipants: prev.manualLinkForm.sideParticipants.map((sp, idx) =>
2390
+ idx === prev.selectedSideIndex
2391
+ ? { ...sp, price_key: text }
2392
+ : sp
2393
+ )
2394
+ }
2395
+ }))}
2396
+ placeholder="e.g., yes or no (for Kalshi)"
2397
+ style={{
2398
+ padding: 12,
2399
+ borderWidth: 1,
2400
+ borderColor: Colors.borders.light,
2401
+ borderRadius: 6,
2402
+ backgroundColor: Colors.views.header,
2403
+ color: Colors.text.h1,
2404
+ fontSize: 14
2405
+ }}
2406
+ />
2407
+ <Text theme='description' size={11} style={{ marginTop: 4 }}>
2408
+ Used by some partners to indicate which price to use for this side
2409
+ </Text>
2410
+ </View>
2411
+ );
2412
+ })()}
2413
+ </>
2414
+ );
2415
+ })()}
2416
+ </View>
2417
+ </ScrollView>
2418
+
2419
+ {/* Footer */}
2420
+ <View type='footer' style={{ padding: 16, flexDirection: 'row', gap: 12 }}>
2421
+ <Button
2422
+ type='close'
2423
+ title="Cancel"
2424
+ onPress={() => setContestData(prev => ({ ...prev, showManualLinkModal: false }))}
2425
+ style={{ flex: 1 }}
2426
+ />
2427
+ <Button
2428
+ type='action'
2429
+ title="Link Market"
2430
+ onPress={submitManualLink}
2431
+ style={{ flex: 1 }}
2432
+ />
2433
+ </View>
2434
+ </>
2435
+ )}
2436
+ </View>
2437
+ </View>
2438
+ )}
2439
+ </>
2440
+ );
2441
+ };
2442
+
2443
+ export default LeagueContests;