be-components 7.0.6 → 7.0.9

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 (180) hide show
  1. package/lib/commonjs/Components/BETimePicker.js +110 -0
  2. package/lib/commonjs/Components/BETimePicker.js.map +1 -0
  3. package/lib/commonjs/Components/Icons.js +37 -0
  4. package/lib/commonjs/Components/Icons.js.map +1 -1
  5. package/lib/commonjs/Components/ImageUploader.js +4 -0
  6. package/lib/commonjs/Components/ImageUploader.js.map +1 -1
  7. package/lib/commonjs/Components/Slider.js +2 -0
  8. package/lib/commonjs/Components/Slider.js.map +1 -1
  9. package/lib/commonjs/Components/Themed.js +4 -2
  10. package/lib/commonjs/Components/Themed.js.map +1 -1
  11. package/lib/commonjs/CreateEngagement/api/index.js +89 -1
  12. package/lib/commonjs/CreateEngagement/api/index.js.map +1 -1
  13. package/lib/commonjs/CreateEngagement/index.js +306 -5
  14. package/lib/commonjs/CreateEngagement/index.js.map +1 -1
  15. package/lib/commonjs/FlashMarket/FlashHolder.js +14 -1
  16. package/lib/commonjs/FlashMarket/FlashHolder.js.map +1 -1
  17. package/lib/commonjs/FlashMarket/api/index.js +42 -0
  18. package/lib/commonjs/FlashMarket/api/index.js.map +1 -1
  19. package/lib/commonjs/FlashMarket/components/FlashOptionCard.js +265 -0
  20. package/lib/commonjs/FlashMarket/components/FlashOptionCard.js.map +1 -0
  21. package/lib/commonjs/FlashMarket/components/ManageFlashMarket.js +1244 -0
  22. package/lib/commonjs/FlashMarket/components/ManageFlashMarket.js.map +1 -0
  23. package/lib/commonjs/FlashMarket/index.js +18 -6
  24. package/lib/commonjs/FlashMarket/index.js.map +1 -1
  25. package/lib/commonjs/Group/api/index.js +6 -3
  26. package/lib/commonjs/Group/api/index.js.map +1 -1
  27. package/lib/commonjs/Group/index.js +135 -20
  28. package/lib/commonjs/Group/index.js.map +1 -1
  29. package/lib/commonjs/Poll/api/index.js +0 -1
  30. package/lib/commonjs/Poll/api/index.js.map +1 -1
  31. package/lib/commonjs/constants/useColors.js +2 -0
  32. package/lib/commonjs/constants/useColors.js.map +1 -1
  33. package/lib/commonjs/index.js +7 -0
  34. package/lib/commonjs/index.js.map +1 -1
  35. package/lib/commonjs/types.d.js.map +1 -1
  36. package/lib/module/Components/BETimePicker.js +102 -0
  37. package/lib/module/Components/BETimePicker.js.map +1 -0
  38. package/lib/module/Components/Icons.js +37 -0
  39. package/lib/module/Components/Icons.js.map +1 -1
  40. package/lib/module/Components/ImageUploader.js +4 -0
  41. package/lib/module/Components/ImageUploader.js.map +1 -1
  42. package/lib/module/Components/Slider.js +2 -0
  43. package/lib/module/Components/Slider.js.map +1 -1
  44. package/lib/module/Components/Themed.js +4 -2
  45. package/lib/module/Components/Themed.js.map +1 -1
  46. package/lib/module/CreateEngagement/api/index.js +89 -1
  47. package/lib/module/CreateEngagement/api/index.js.map +1 -1
  48. package/lib/module/CreateEngagement/index.js +306 -5
  49. package/lib/module/CreateEngagement/index.js.map +1 -1
  50. package/lib/module/FlashMarket/FlashHolder.js +14 -1
  51. package/lib/module/FlashMarket/FlashHolder.js.map +1 -1
  52. package/lib/module/FlashMarket/api/index.js +42 -0
  53. package/lib/module/FlashMarket/api/index.js.map +1 -1
  54. package/lib/module/FlashMarket/components/FlashOptionCard.js +258 -0
  55. package/lib/module/FlashMarket/components/FlashOptionCard.js.map +1 -0
  56. package/lib/module/FlashMarket/components/ManageFlashMarket.js +1236 -0
  57. package/lib/module/FlashMarket/components/ManageFlashMarket.js.map +1 -0
  58. package/lib/module/FlashMarket/index.js +18 -6
  59. package/lib/module/FlashMarket/index.js.map +1 -1
  60. package/lib/module/Group/api/index.js +6 -3
  61. package/lib/module/Group/api/index.js.map +1 -1
  62. package/lib/module/Group/index.js +135 -20
  63. package/lib/module/Group/index.js.map +1 -1
  64. package/lib/module/Poll/api/index.js +0 -1
  65. package/lib/module/Poll/api/index.js.map +1 -1
  66. package/lib/module/constants/useColors.js +2 -0
  67. package/lib/module/constants/useColors.js.map +1 -1
  68. package/lib/module/index.js +2 -1
  69. package/lib/module/index.js.map +1 -1
  70. package/lib/module/types.d.js.map +1 -1
  71. package/lib/typescript/lib/commonjs/Components/BETimePicker.d.ts +8 -0
  72. package/lib/typescript/lib/commonjs/Components/BETimePicker.d.ts.map +1 -0
  73. package/lib/typescript/lib/commonjs/Components/Icons.d.ts +5 -0
  74. package/lib/typescript/lib/commonjs/Components/Icons.d.ts.map +1 -1
  75. package/lib/typescript/lib/commonjs/Components/ImageUploader.d.ts +2 -1
  76. package/lib/typescript/lib/commonjs/Components/ImageUploader.d.ts.map +1 -1
  77. package/lib/typescript/lib/commonjs/Components/Slider.d.ts +2 -1
  78. package/lib/typescript/lib/commonjs/Components/Slider.d.ts.map +1 -1
  79. package/lib/typescript/lib/commonjs/Components/Themed.d.ts.map +1 -1
  80. package/lib/typescript/lib/commonjs/CreateEngagement/api/index.d.ts +40 -1
  81. package/lib/typescript/lib/commonjs/CreateEngagement/api/index.d.ts.map +1 -1
  82. package/lib/typescript/lib/commonjs/CreateEngagement/index.d.ts.map +1 -1
  83. package/lib/typescript/lib/commonjs/FlashMarket/FlashHolder.d.ts +3 -1
  84. package/lib/typescript/lib/commonjs/FlashMarket/FlashHolder.d.ts.map +1 -1
  85. package/lib/typescript/lib/commonjs/FlashMarket/api/index.d.ts +2 -0
  86. package/lib/typescript/lib/commonjs/FlashMarket/api/index.d.ts.map +1 -1
  87. package/lib/typescript/lib/commonjs/FlashMarket/components/FlashOptionCard.d.ts +13 -0
  88. package/lib/typescript/lib/commonjs/FlashMarket/components/FlashOptionCard.d.ts.map +1 -0
  89. package/lib/typescript/lib/commonjs/FlashMarket/components/ManageFlashMarket.d.ts +11 -0
  90. package/lib/typescript/lib/commonjs/FlashMarket/components/ManageFlashMarket.d.ts.map +1 -0
  91. package/lib/typescript/lib/commonjs/FlashMarket/index.d.ts +2 -1
  92. package/lib/typescript/lib/commonjs/FlashMarket/index.d.ts.map +1 -1
  93. package/lib/typescript/lib/commonjs/Group/api/index.d.ts.map +1 -1
  94. package/lib/typescript/lib/commonjs/Group/index.d.ts +2 -1
  95. package/lib/typescript/lib/commonjs/Group/index.d.ts.map +1 -1
  96. package/lib/typescript/lib/commonjs/Poll/api/index.d.ts.map +1 -1
  97. package/lib/typescript/lib/commonjs/constants/useColors.d.ts +1 -0
  98. package/lib/typescript/lib/commonjs/constants/useColors.d.ts.map +1 -1
  99. package/lib/typescript/lib/commonjs/index.d.ts +1 -0
  100. package/lib/typescript/lib/commonjs/index.d.ts.map +1 -1
  101. package/lib/typescript/lib/module/Components/BETimePicker.d.ts +8 -0
  102. package/lib/typescript/lib/module/Components/BETimePicker.d.ts.map +1 -0
  103. package/lib/typescript/lib/module/Components/Icons.d.ts +5 -0
  104. package/lib/typescript/lib/module/Components/Icons.d.ts.map +1 -1
  105. package/lib/typescript/lib/module/Components/ImageUploader.d.ts +2 -1
  106. package/lib/typescript/lib/module/Components/ImageUploader.d.ts.map +1 -1
  107. package/lib/typescript/lib/module/Components/Slider.d.ts +2 -1
  108. package/lib/typescript/lib/module/Components/Slider.d.ts.map +1 -1
  109. package/lib/typescript/lib/module/Components/Themed.d.ts.map +1 -1
  110. package/lib/typescript/lib/module/CreateEngagement/api/index.d.ts +41 -1
  111. package/lib/typescript/lib/module/CreateEngagement/api/index.d.ts.map +1 -1
  112. package/lib/typescript/lib/module/CreateEngagement/index.d.ts.map +1 -1
  113. package/lib/typescript/lib/module/FlashMarket/FlashHolder.d.ts +3 -1
  114. package/lib/typescript/lib/module/FlashMarket/FlashHolder.d.ts.map +1 -1
  115. package/lib/typescript/lib/module/FlashMarket/api/index.d.ts +2 -0
  116. package/lib/typescript/lib/module/FlashMarket/api/index.d.ts.map +1 -1
  117. package/lib/typescript/lib/module/FlashMarket/components/FlashOptionCard.d.ts +13 -0
  118. package/lib/typescript/lib/module/FlashMarket/components/FlashOptionCard.d.ts.map +1 -0
  119. package/lib/typescript/lib/module/FlashMarket/components/ManageFlashMarket.d.ts +11 -0
  120. package/lib/typescript/lib/module/FlashMarket/components/ManageFlashMarket.d.ts.map +1 -0
  121. package/lib/typescript/lib/module/FlashMarket/index.d.ts +2 -1
  122. package/lib/typescript/lib/module/FlashMarket/index.d.ts.map +1 -1
  123. package/lib/typescript/lib/module/Group/api/index.d.ts.map +1 -1
  124. package/lib/typescript/lib/module/Group/index.d.ts +2 -1
  125. package/lib/typescript/lib/module/Group/index.d.ts.map +1 -1
  126. package/lib/typescript/lib/module/Poll/api/index.d.ts.map +1 -1
  127. package/lib/typescript/lib/module/constants/useColors.d.ts +1 -0
  128. package/lib/typescript/lib/module/constants/useColors.d.ts.map +1 -1
  129. package/lib/typescript/lib/module/index.d.ts +2 -1
  130. package/lib/typescript/lib/module/index.d.ts.map +1 -1
  131. package/lib/typescript/src/Components/BETimePicker.d.ts +11 -0
  132. package/lib/typescript/src/Components/BETimePicker.d.ts.map +1 -0
  133. package/lib/typescript/src/Components/Icons.d.ts +1 -0
  134. package/lib/typescript/src/Components/Icons.d.ts.map +1 -1
  135. package/lib/typescript/src/Components/ImageUploader.d.ts +2 -1
  136. package/lib/typescript/src/Components/ImageUploader.d.ts.map +1 -1
  137. package/lib/typescript/src/Components/Slider.d.ts +2 -1
  138. package/lib/typescript/src/Components/Slider.d.ts.map +1 -1
  139. package/lib/typescript/src/Components/Themed.d.ts.map +1 -1
  140. package/lib/typescript/src/CreateEngagement/api/index.d.ts +8 -2
  141. package/lib/typescript/src/CreateEngagement/api/index.d.ts.map +1 -1
  142. package/lib/typescript/src/CreateEngagement/index.d.ts.map +1 -1
  143. package/lib/typescript/src/FlashMarket/FlashHolder.d.ts +4 -2
  144. package/lib/typescript/src/FlashMarket/FlashHolder.d.ts.map +1 -1
  145. package/lib/typescript/src/FlashMarket/api/index.d.ts +2 -0
  146. package/lib/typescript/src/FlashMarket/api/index.d.ts.map +1 -1
  147. package/lib/typescript/src/FlashMarket/components/FlashOptionCard.d.ts +15 -0
  148. package/lib/typescript/src/FlashMarket/components/FlashOptionCard.d.ts.map +1 -0
  149. package/lib/typescript/src/FlashMarket/components/ManageFlashMarket.d.ts +15 -0
  150. package/lib/typescript/src/FlashMarket/components/ManageFlashMarket.d.ts.map +1 -0
  151. package/lib/typescript/src/FlashMarket/index.d.ts +2 -1
  152. package/lib/typescript/src/FlashMarket/index.d.ts.map +1 -1
  153. package/lib/typescript/src/Group/api/index.d.ts +5 -2
  154. package/lib/typescript/src/Group/api/index.d.ts.map +1 -1
  155. package/lib/typescript/src/Group/index.d.ts +3 -2
  156. package/lib/typescript/src/Group/index.d.ts.map +1 -1
  157. package/lib/typescript/src/Poll/api/index.d.ts.map +1 -1
  158. package/lib/typescript/src/constants/useColors.d.ts +1 -0
  159. package/lib/typescript/src/constants/useColors.d.ts.map +1 -1
  160. package/lib/typescript/src/index.d.ts +2 -1
  161. package/lib/typescript/src/index.d.ts.map +1 -1
  162. package/package.json +4 -2
  163. package/src/Components/BETimePicker.tsx +77 -0
  164. package/src/Components/Icons.tsx +17 -0
  165. package/src/Components/ImageUploader.tsx +3 -1
  166. package/src/Components/Slider.tsx +3 -1
  167. package/src/Components/Themed.tsx +6 -4
  168. package/src/CreateEngagement/api/index.ts +78 -2
  169. package/src/CreateEngagement/index.tsx +181 -7
  170. package/src/FlashMarket/FlashHolder.tsx +11 -2
  171. package/src/FlashMarket/api/index.ts +24 -1
  172. package/src/FlashMarket/components/FlashOptionCard.tsx +174 -0
  173. package/src/FlashMarket/components/ManageFlashMarket.tsx +769 -0
  174. package/src/FlashMarket/index.tsx +14 -8
  175. package/src/Group/api/index.ts +5 -5
  176. package/src/Group/index.tsx +84 -9
  177. package/src/Poll/api/index.ts +0 -2
  178. package/src/constants/useColors.tsx +2 -0
  179. package/src/index.tsx +2 -0
  180. package/src/types.d.ts +8 -1
@@ -0,0 +1,769 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Button, Text, TextInput, View } from "../../Components/Themed"
3
+ import { FlatList, Image, type ViewStyle } from 'react-native';
4
+ import type { FocusPositionProps, MyPlayerProps, PollCampaignProps, PollOptionProps, PollProps, PollSummaryProps, PublicPlayerProps } from '../../types';
5
+ import { Icons, Switch, Toggle } from '../../Components';
6
+ import { PollApi, PollCampaignApi, PollOptionApi } from '../../Poll/api';
7
+ import ImageUploader from '../../Components/ImageUploader';
8
+ import { useColors } from '../../constants/useColors';
9
+ import FlashOptionCard from './FlashOptionCard';
10
+ import moment from 'moment-mini';
11
+ import BETimePicker from '../../Components/BETimePicker';
12
+ import { FlashMarketHelpers } from '../api';
13
+ import { showConfirmAlert } from '../../Components/ConfirmAlert';
14
+
15
+ type ManageFlashMarketProps = {
16
+ poll_id:string,
17
+ player?:MyPlayerProps,
18
+ float?:boolean,
19
+ header_style?:ViewStyle,
20
+ footer_style?:ViewStyle,
21
+ onClose:() => void,
22
+ onFocusPosition?:(pos:FocusPositionProps) => void
23
+ }
24
+
25
+ const sections = ['header','activate','pause_resume','closed','resolve','toggle','image','question','options','settings','results']
26
+ const ManageFlashMarket = ({ float, header_style, player, onClose, poll_id, onFocusPosition }:ManageFlashMarketProps) => {
27
+ const Colors = useColors();
28
+ const [ labels, setLabels ] = useState({
29
+ base_stake: '0',
30
+ min_stake: '0',
31
+ max_stake: '0'
32
+ });
33
+ const { min_stake, max_stake, base_stake } = labels;
34
+ const [ expand_participants, setExpandParticipants ] = useState(false);
35
+ const [ flash_state, setFlashState ] = useState<{
36
+ loading:boolean,
37
+ action_loading:boolean,
38
+ probability_changed:boolean,
39
+ active_step:string,
40
+ poll_campaign?:PollCampaignProps,
41
+ players:PublicPlayerProps[],
42
+ poll?:PollProps,
43
+ draft_poll?:PollProps,
44
+ poll_summaries:PollSummaryProps[],
45
+ poll_options:PollOptionProps[]
46
+ }>({
47
+ loading:false,
48
+ action_loading:false,
49
+ probability_changed: false,
50
+ active_step: 'settings',
51
+ players: [],
52
+ poll_summaries:[],
53
+ poll_options: []
54
+ });
55
+ const { loading, action_loading, poll_options, players, active_step, poll, draft_poll, poll_summaries, probability_changed } = flash_state;
56
+ const real_options = poll_options.filter(o => o.status != 'inactive');
57
+ const total_responses = poll_summaries.reduce((a,b) => a + b.count, 0);
58
+ const unlocked_options = real_options.filter(o => !o.probability_locked);
59
+ const prob_locked = unlocked_options.length <= 1 ? true : false
60
+ const errors = FlashMarketHelpers.isNewValid(real_options, poll_summaries, poll);
61
+ const winning_option = real_options.find(o => o.poll_option_id == poll?.winning_option_id);
62
+ useEffect(() => {
63
+ PollCampaignApi.setEnvironment();
64
+ if(!poll_id){ return }
65
+ getData(poll_id);
66
+ },[poll_id]);
67
+
68
+ const getData = async(id:string) => {
69
+ setFlashState({ ...flash_state, loading:true });
70
+ const server_response = await PollApi.getPollById(id);
71
+ const server_campaign = await PollCampaignApi.getPollCampaignById(server_response.poll.poll_campaign_id);
72
+ let player_ids:string[] = []
73
+ server_response.poll_summaries.map(s => {
74
+ s.player_ids.map(id => id != '4985' ? player_ids.push(id) : console.log(''))
75
+ })
76
+ const server_players = await PollCampaignApi.getPlayersByPlayerIds([ ...new Set(player_ids.map(id => id))]);
77
+ setFlashState({
78
+ ...flash_state,
79
+ poll: server_response.poll,
80
+ poll_options: server_response.poll_options,
81
+ draft_poll: server_response.poll,
82
+ poll_summaries: server_response.poll_summaries,
83
+ poll_campaign: server_campaign,
84
+ players: server_players,
85
+ loading: false
86
+ });
87
+ setLabels({
88
+ min_stake: server_response.poll.minimum_stake.toString(),
89
+ max_stake: server_response.poll.max_stake.toString(),
90
+ base_stake: server_response.poll.base_stake?.toString() ?? '0'
91
+ })
92
+ }
93
+
94
+ const updatePoll = async(dp:PollProps) => {
95
+ if(action_loading){ return }
96
+ setFlashState({ ...flash_state, action_loading: true });
97
+ const new_resp = await PollApi.updatePoll(dp);
98
+ if(!new_resp){ return alert('Unable to update') }
99
+ setFlashState({
100
+ ...flash_state,
101
+ action_loading: false,
102
+ poll: new_resp.poll,
103
+ draft_poll: new_resp.poll,
104
+ poll_options: new_resp.poll_options
105
+ });
106
+ }
107
+
108
+ const handleSelectWinningOption = (checked:boolean, option:PollOptionProps) => {
109
+ if(!poll){ return alert('Unable to process') }
110
+ if(checked){
111
+ showConfirmAlert('Are you sure', `Confirm ${option.option_name} is the correct answer`,
112
+ () => updatePoll({ ...poll, winning_option_id: option.poll_option_id, status: 'paused' }),
113
+ () => console.log('')
114
+ )
115
+ } else {
116
+ if(!poll.winning_option_id){ return }
117
+ showConfirmAlert('Are you sure', `Remove ${option.option_name} as the correct answer`,
118
+ () => updatePoll({ ...poll, winning_option_id:undefined }),
119
+ () => console.log('')
120
+ )
121
+ }
122
+ }
123
+
124
+ const handleChangeProbability = (option:PollOptionProps, probability:number) => {
125
+ if(option.probability_locked){ return }
126
+ if(probability < 0){ return }
127
+ if(probability > 1){ return }
128
+ let other_options = [ ...real_options.filter(o => o.poll_option_id != option.poll_option_id) ]
129
+ //Find the min probability
130
+
131
+ //Other option probabilities
132
+ let other_option_probabilities = other_options.reduce((a,b) => a + (b.initial_odds ?? 0), 0);
133
+ //With new probabilities
134
+ let all_probs = other_option_probabilities + probability
135
+ let difference = 1 - all_probs
136
+
137
+ let unlocked_options = other_options.filter(po => !po.probability_locked);
138
+ if(unlocked_options.length == 0){ return } //There are no options!
139
+
140
+ let new_option:PollOptionProps = { ...option, initial_odds: probability }
141
+ //what is the current total probability
142
+ let delta = difference / unlocked_options.length
143
+ //Map through the others and update those
144
+
145
+ let min_option = unlocked_options.reduce((min, item) => {
146
+ let item_init = item.initial_odds ?? 0
147
+ let min_init = min.initial_odds ?? 0
148
+ if(item_init < min_init){ return item } else { return min }
149
+ });
150
+
151
+ let max_option = unlocked_options.reduce((min, item) => {
152
+ let item_init = item.initial_odds ?? 0
153
+ let min_init = min.initial_odds ?? 0
154
+ if(item_init > min_init){ return item } else { return min }
155
+ });
156
+ let new_delta = delta
157
+
158
+
159
+ if(delta < 0){
160
+ //Make sure our min has enough room
161
+ let min_diff = (min_option.initial_odds ?? 0) + delta
162
+ if(min_diff < 0) { new_delta = min_option.initial_odds ?? 0 }
163
+ } else {
164
+ let max_diff = (max_option.initial_odds ?? 0) + delta
165
+ if(max_diff > 1){ new_delta = 1 - (max_option.initial_odds ?? 0) }
166
+ }
167
+
168
+ let delta_difference = new_delta - delta
169
+ if(delta_difference != 0){
170
+ return
171
+ }
172
+ let failed = false
173
+ other_options = other_options.map(o => {
174
+ if(o.probability_locked){ return o }
175
+ let starting_odds = o.initial_odds ?? 0
176
+ let new_odds = starting_odds + delta
177
+ if(new_odds < 0){ failed = true }
178
+ if(new_odds > 1){ failed = true }
179
+ o.initial_odds = new_odds
180
+ return o
181
+ });
182
+ if(failed){ return }
183
+ let final_options = other_options.concat(new_option);
184
+ //let check it
185
+ let total_prob = final_options.reduce((a,b) => a + (b.initial_odds ?? 0), 0);
186
+ if(total_prob.toFixed(2) != '1.00'){ return }
187
+
188
+ setFlashState({
189
+ ...flash_state,
190
+ probability_changed: true,
191
+ poll_options: poll_options.filter(po => !final_options.find(fo => fo.poll_option_id == po.poll_option_id)).concat(final_options)
192
+ });
193
+ }
194
+
195
+ const renderOptions = (data:{ item:PollOptionProps, index:number }) => {
196
+ if(!poll){ return <></> }
197
+ const summary = poll_summaries.find(ps => ps.poll_option_id == data.item.poll_option_id);
198
+ if(!summary){ return <></> }
199
+ return (
200
+ <View style={{ padding:5 }}>
201
+ <FlashOptionCard
202
+ poll_option={data.item}
203
+ summary={summary}
204
+ poll={poll}
205
+ onSelectWinningOption={handleSelectWinningOption}
206
+ probability_locked={prob_locked}
207
+ onChangeProbability={(probability) => handleChangeProbability(data.item, probability)}
208
+ onLockProbability={(locked) => {
209
+ setFlashState({
210
+ ...flash_state,
211
+ poll_options: poll_options.filter(po => po.poll_option_id != data.item.poll_option_id).concat({ ...data.item, probability_locked: locked })
212
+ })
213
+ }}
214
+ onUpdateOption={(option) => {
215
+ setFlashState({
216
+ ...flash_state,
217
+ poll_options: poll_options.filter(po => po.poll_option_id != option.poll_option_id).concat(option)
218
+ })
219
+ }}
220
+ />
221
+ </View>
222
+ )
223
+ }
224
+
225
+ const handleSaveProbabilities = async() => {
226
+ if(!probability_changed){ return }
227
+ if(poll?.status != 'pending'){ return }
228
+ let total_prob = real_options.reduce((a,b) => a + (b.initial_odds ?? 0), 0);
229
+ if(total_prob.toFixed(2) != '1.00'){ return }
230
+
231
+ setFlashState({ ...flash_state, action_loading: true });
232
+ let new_options:PollOptionProps[] = []
233
+
234
+ const saveOptions = real_options.map(async o => {
235
+ new_options.push(await PollOptionApi.updatePollOption(o))
236
+ });
237
+ await Promise.all(saveOptions);
238
+ setFlashState({
239
+ ...flash_state,
240
+ poll_options: new_options,
241
+ probability_changed: false
242
+ })
243
+ }
244
+
245
+ const handleResolve = () => {
246
+ if(!poll){ return }
247
+ if(!winning_option){ return }
248
+ showConfirmAlert('Are you sure', `Confirm ${winning_option.option_name} is the correct answer and payout participants`,
249
+ () => resolveFlashMarket(),
250
+ () => console.log('')
251
+ )
252
+ }
253
+
254
+ const resolveFlashMarket = async() => {
255
+ if(!poll){ return }
256
+ if(!poll.winning_option_id){ return }
257
+ setFlashState({ ...flash_state, action_loading: true });
258
+ const resolved_poll = await PollApi.closePoll(poll.poll_id);
259
+ if(!resolved_poll){ return alert('Unable to activate market at this time') }
260
+ setFlashState({
261
+ ...flash_state,
262
+ action_loading: false,
263
+ poll: resolved_poll
264
+ })
265
+ }
266
+
267
+ const handleAddOption = async() => {
268
+ if(poll?.status != 'pending'){ return }
269
+ if(action_loading){ return }
270
+ setFlashState({ ...flash_state, action_loading:true });
271
+ let length = real_options.length
272
+ const new_option = await PollOptionApi.createPollOption({
273
+ poll_id: poll.poll_id,
274
+ poll_option_id: '',
275
+ option_name: '',
276
+ initial_odds: length == 0 ? 1 : 0,
277
+ option_value: 'optional',
278
+ response_message:'',
279
+ priority: length + 1,
280
+ create_datetime: '', last_update_datetime: '',
281
+ option_type:'select',
282
+ status: 'pending',
283
+ });
284
+ if(!new_option){
285
+ setFlashState({
286
+ ...flash_state,
287
+ action_loading: false
288
+ });
289
+ return alert('Unable to process')
290
+ }
291
+ let new_summary:PollSummaryProps = {
292
+ poll_id:poll_id,
293
+ poll_option_id: new_option.poll_option_id,
294
+ count: 0,
295
+ stake: 0,
296
+ winnings: 0,
297
+ player_ids: [],
298
+ pct: 0
299
+ }
300
+ //We have a new option! Now we will need to update the probabilities
301
+ setFlashState({
302
+ ...flash_state,
303
+ action_loading: false,
304
+ poll_options: poll_options.filter(po => po.poll_option_id != new_option.poll_option_id).concat(new_option),
305
+ poll_summaries: poll_summaries.filter(ps => ps.poll_option_id != new_summary.poll_option_id).concat(new_summary)
306
+ });
307
+ }
308
+
309
+
310
+ const renderPlayers = (data:{ item:PublicPlayerProps, index:number }) => {
311
+ return (
312
+ <View type='row' style={{ borderBottomWidth:1, borderColor:Colors.borders.light, padding:10 }}>
313
+ <Image
314
+ source={{ uri: data.item.profile_pic }}
315
+ style={{ height:30, width:30, borderRadius:100 }}
316
+ />
317
+ <View transparent style={{ flex:1, marginLeft:10 }}>
318
+ <Text theme='h1'>@{data.item.username}</Text>
319
+ <Text theme='description' style={{ marginTop:3 }}>Joined {moment(data.item.create_datetime).fromNow()}</Text>
320
+ </View>
321
+ </View>
322
+ )
323
+ }
324
+
325
+ const renderSections = (data:{ item:string, index:number }) => {
326
+ switch(data.item){
327
+ case 'header':
328
+ return (
329
+ <View type='header' style={{ flexDirection:'row', alignItems:'center', padding:10, ...header_style }}>
330
+ <View transparent style={{ flex:1 }}>
331
+ <Text theme='h1'>Flash Market</Text>
332
+ <Text theme='description' style={{ marginTop:3 }}>Use the form below to manage your custom flash market!</Text>
333
+ </View>
334
+ <Button
335
+ float
336
+ title='X'
337
+ title_color={Colors.text.error}
338
+ onPress={() => onClose()}
339
+ />
340
+ </View>
341
+ )
342
+ case 'activate':
343
+ if(poll?.status != 'pending'){ return <></> }
344
+ const ready = errors.length == 0 ? true : false
345
+ return (
346
+ <View transparent style={{ flexDirection:'row', alignItems:'center', padding:10 }}>
347
+ <View transparent style={{ flex:1 }}>
348
+ <Text theme='h1'>Flash Market is Pending</Text>
349
+ <Text theme='description'>Complete set up and select activate when you are ready</Text>
350
+ </View>
351
+ <Button
352
+ type='success'
353
+ title='Activate'
354
+ loading={action_loading}
355
+ disabled={errors.length > 0 ? true : probability_changed ? true : false}
356
+ style={{ opacity: ready && !action_loading && !probability_changed ? 1: 0.5 }}
357
+ onPress={async() => {
358
+ if(errors.length > 0){ return alert(errors.map(e => e)) }
359
+ if(probability_changed){ return }
360
+ setFlashState({ ...flash_state, action_loading: true });
361
+ const resp = await PollApi.activatePoll(poll.poll_id);
362
+ if(!resp){ return alert('Unable to activate market at this time') }
363
+ setFlashState({
364
+ ...flash_state,
365
+ action_loading: false,
366
+ poll: resp.poll,
367
+ poll_options: resp.poll_options
368
+ })
369
+ }}
370
+ />
371
+ </View>
372
+ )
373
+ case 'closed':
374
+ if(!poll){ return <></> }
375
+ if(poll.status != 'closed'){return <></>}
376
+ return (
377
+ <View transparent style={{ flexDirection:'row', alignItems:'center', padding:10, backgroundColor:Colors.views.liquidMarket }}>
378
+ <View transparent style={{ flex:1 }}>
379
+ <Text theme='h1'>Flash Market is Closed</Text>
380
+ <Text theme='description'>This flash market has been completed and all participants have been paid out</Text>
381
+ </View>
382
+ </View>
383
+ )
384
+ case 'pause_resume':
385
+ if(!poll){ return <></> }
386
+ if(!['active','paused',''].includes(poll.status)){ return <></> }
387
+ if(poll.winning_option_id){ return <></> }
388
+ return (
389
+ <View transparent style={{ flexDirection:'row', alignItems:'center', padding:10 }}>
390
+ <View transparent style={{ flex:1 }}>
391
+ <Text theme='h1'>Flash Market is {poll.status}</Text>
392
+ <Text theme='description'>Complete set up and select activate when you are ready</Text>
393
+ </View>
394
+ {poll.status == 'paused' ?
395
+ <Button
396
+ type='success'
397
+ title='Resume'
398
+ loading={action_loading}
399
+ disabled={action_loading ? true : false}
400
+ style={{ opacity: action_loading? 0.5:1}}
401
+ onPress={async() => {
402
+ updatePoll({ ...poll, status: 'active' });
403
+ }}
404
+ />
405
+ :
406
+ <Button
407
+ type='warning'
408
+ title='Pause'
409
+ loading={action_loading}
410
+ disabled={action_loading ? true : false}
411
+ style={{ opacity: action_loading? 0.5:1}}
412
+ onPress={async() => {
413
+ updatePoll({ ...poll, status: 'paused' });
414
+ }}
415
+ />
416
+ }
417
+ </View>
418
+ )
419
+ case 'resolve':
420
+ if(!poll){ return <></> }
421
+ if(!poll.winning_option_id){ return <></> }
422
+ if(!winning_option){ return <></> }
423
+ if(poll.status == 'closed'){ return <></> }
424
+ return (
425
+ <View transparent style={{ flexDirection:'row', alignItems:'center', padding:10 }}>
426
+ <View transparent style={{ flex:1 }}>
427
+ <Text theme='h1'>Resolve Flash Market</Text>
428
+ <Text theme='description'>Resolve with option: {winning_option.option_name} as the winner</Text>
429
+ </View>
430
+ <Button
431
+ type='success'
432
+ title='Resolve'
433
+ loading={action_loading}
434
+ disabled={action_loading}
435
+ style={{ opacity: action_loading ? 0.5:1 }}
436
+ onPress={async() => handleResolve()}
437
+ />
438
+ </View>
439
+ )
440
+ case 'toggle':
441
+ return (
442
+ <View style={{ padding:10 }}>
443
+ <Toggle
444
+ options={[
445
+ { key: 'question', label: 'Question' },
446
+ { key: 'options', label: 'Options' },
447
+ { key: 'settings', label: 'Settings' },
448
+ { key: 'results', label: 'Results' }
449
+ ]}
450
+ selected_option={active_step}
451
+ onSelectOption={(key) => setFlashState({ ...flash_state, active_step: key })}
452
+ />
453
+ </View>
454
+ )
455
+ case 'image':
456
+ if(active_step != 'question'){ return <></> }
457
+ if(!draft_poll || !poll){ return <></> }
458
+ return (
459
+ <View style={{ flexDirection:'row', alignItems:'center', padding:10, borderBottomWidth:1, borderColor:Colors.borders.light }}>
460
+ <View transparent style={{ flex:1, marginRight:10 }}>
461
+ <Text theme='h1'>Flash Market Image</Text>
462
+ <Text theme='description' style={{ marginTop:3 }}>Give the question an image that aligns with the question</Text>
463
+ </View>
464
+ <ImageUploader disabled={poll.status == 'closed' ? true : false} public_id={`poll_${poll_id}_${Math.random().toFixed(9)}`} onFinishUpload={(obj) => {
465
+ updatePoll({ ...draft_poll, poll_image: { ...obj, url: obj.secure_url } })
466
+ }}>
467
+ {poll.poll_image ?
468
+ <Image
469
+ source={{ uri: poll.poll_image.url }}
470
+ style={{ height:45, width:45 }}
471
+ resizeMode='contain'
472
+ />
473
+ :
474
+ <Icons.ImageIcon size={45} color={Colors.text.h1} />
475
+ }
476
+ <Text style={{ marginTop:5 }} textAlign='center' theme='action'>{draft_poll.poll_image ? 'CHANGE' : 'UPLOAD'}</Text>
477
+ </ImageUploader>
478
+ </View>
479
+
480
+ )
481
+ case 'question':
482
+ if(active_step != 'question'){ return <></> }
483
+ if(!draft_poll || !poll){ return <></> }
484
+ const is_q_changed = JSON.stringify(poll.poll_question) != JSON.stringify(draft_poll.poll_question) ? true : false
485
+ const edit_allowed = poll_summaries.length == 0 && ['pending','paused'].includes(poll.status) ? true : false
486
+ return (
487
+ <View transparent>
488
+ <View style={{ flexDirection:'row', alignItems:'center', padding:10 }}>
489
+ <View transparent style={{ flex:1 }}>
490
+ <Text theme='h1'>Flash Market Question</Text>
491
+ <Text theme='description' style={{ marginTop:3 }}>Edit your question below. Questions can be edited until a response is recorded.</Text>
492
+ </View>
493
+ </View>
494
+ <View transparent style={{ padding:20 }}>
495
+ <TextInput
496
+ style={{ height: 150, textAlign:'center' }}
497
+ multiline={true}
498
+ editable={edit_allowed}
499
+ placeholder='Enter Question Here'
500
+ value={draft_poll.poll_question}
501
+ onChangeText={(text) => setFlashState({ ...flash_state, draft_poll: { ...draft_poll, poll_question: text } })}
502
+ />
503
+ </View>
504
+ <Button
505
+ title='SAVE QUESTION'
506
+ type='success'
507
+ disabled={!edit_allowed || !is_q_changed ? true : false}
508
+ style={{ margin:10, opacity: !edit_allowed || !is_q_changed ? 0.5: 1 }}
509
+ loading={action_loading}
510
+ onPress={() => updatePoll(draft_poll)}
511
+ />
512
+ </View>
513
+ )
514
+ case 'results':
515
+ if(!poll){ return <></> }
516
+ if(active_step != 'results'){ return <></> }
517
+ let staked = poll_summaries.reduce((a,b) => a + b.stake, 0) - (poll.base_stake ?? 0)
518
+ let responses = poll_summaries.reduce((a,b) => a + b.count, 0) - poll_summaries.length;
519
+ if(responses < 0){ responses = 0 }
520
+ let participants = players.length
521
+ let total_stake = poll_summaries.reduce((a,b) => a + b.stake, 0);
522
+ let winnings = poll_summaries.reduce((a,b) => a + b.winnings, 0);
523
+ let revenue = total_stake - winnings
524
+ return (
525
+ <View transparent>
526
+ <View transparent type='row' style={{ padding:20, borderBottomWidth:1, borderColor:Colors.borders.light }}>
527
+ <View transparent style={{ flex:1, marginRight:10 }}>
528
+ <Text theme='h1'>Total Revenue</Text>
529
+ <Text theme='description' style={{ marginTop:3 }}>Total amount of revenue earned on this flash market</Text>
530
+ </View>
531
+ <Text theme='h1'>${revenue.toFixed(2)}</Text>
532
+ </View>
533
+ <View transparent type='row' style={{ padding:20, borderBottomWidth:1, borderColor:Colors.borders.light }}>
534
+ <View transparent style={{ flex:1, marginRight:10 }}>
535
+ <Text theme='h1'>Total Volume</Text>
536
+ <Text theme='description' style={{ marginTop:3 }}>Total amount bet on this market</Text>
537
+ </View>
538
+ <Text theme='h1'>${staked.toFixed(2)}</Text>
539
+ </View>
540
+ <View transparent type='row' style={{ padding:20, borderBottomWidth:1, borderColor:Colors.borders.light }}>
541
+ <View transparent style={{ flex:1, marginRight:10 }}>
542
+ <Text theme='h1'>Total Responses</Text>
543
+ <Text theme='description' style={{ marginTop:3 }}>Total number of bets on this market</Text>
544
+ </View>
545
+ <Text theme='h1'>{responses.toFixed()}</Text>
546
+ </View>
547
+ <View transparent type='row' style={{ padding:20, borderBottomWidth:1, borderColor:Colors.borders.light }}>
548
+ <View transparent style={{ flex:1, marginRight:10 }}>
549
+ <Text theme='h1'>Participants</Text>
550
+ <Text theme='description' style={{ marginTop:3 }}>Players that participated in this flash market</Text>
551
+ </View>
552
+ <Text theme='h1'>{participants.toFixed()}</Text>
553
+ <Button
554
+ onPress={() => setExpandParticipants(!expand_participants)}
555
+ float
556
+ style={{ marginLeft:10, height:30, width:30, borderRadius:100, padding:10, justifyContent:'center', alignItems:'center' }}>
557
+ <Icons.ChevronIcon direction={expand_participants ? 'up' : 'down'} size={8} color={Colors.text.action} />
558
+ </Button>
559
+ </View>
560
+ {expand_participants ?
561
+ <View transparent style={{ margin:10 }}>
562
+ <FlatList
563
+ data={players}
564
+ renderItem={renderPlayers}
565
+ key={'participant_list_poll'}
566
+ keyExtractor={item => item.player_id.toString()}
567
+ />
568
+ </View>
569
+ :<></>}
570
+ </View>
571
+ )
572
+ case 'options':
573
+ if(!poll){ return <></> }
574
+ if(active_step != 'options'){ return <></> }
575
+ const add_allowed = ['pending','paused'].includes(poll.status) && total_responses == 0 ? true : false
576
+ return (
577
+ <View transparent>
578
+ <View style={{ flexDirection:'row', alignItems:'center', padding:10 }}>
579
+ <View transparent style={{ flex:1 }}>
580
+ <Text theme='h1'>Flash Market Options</Text>
581
+ {poll.status == 'pending' ?
582
+ <Text theme='description' style={{ marginTop:3 }}>Enter the options below!</Text>
583
+ :
584
+ <Text theme='description' style={{ marginTop:3 }}>Select the winning option below</Text>
585
+ }
586
+ </View>
587
+ {probability_changed ?
588
+ <Button
589
+ title='SAVE PROBABILITIES'
590
+ onPress={() => handleSaveProbabilities()}
591
+ type='success'
592
+ disabled={action_loading}
593
+ loading={action_loading}
594
+ style={{ margin:5, padding:10, opacity:loading?0.5:1 }}
595
+ />
596
+ :<></>}
597
+ </View>
598
+ <View transparent style={{ padding:10 }}>
599
+ <FlatList
600
+ data={real_options.sort((a,b) => a.priority - b.priority || moment(a.create_datetime).unix() - moment(b.create_datetime).unix())}
601
+ key='option_list'
602
+ keyboardShouldPersistTaps
603
+ keyExtractor={item => item.poll_option_id.toString()}
604
+ renderItem={renderOptions}
605
+ />
606
+ {add_allowed ?
607
+ <Button
608
+ transparent
609
+ title_color={Colors.text.action}
610
+ title={real_options.length > 0 ? 'Add another option' : 'Add an option'}
611
+ style={{ alignItems:'flex-start', padding:10 }}
612
+ onPress={async() => handleAddOption()}
613
+ />
614
+ :<></>}
615
+ </View>
616
+
617
+ </View>
618
+ )
619
+ case 'settings':
620
+ if(active_step != 'settings'){ return <></> }
621
+ if(!draft_poll){ return <></> }
622
+ let settings_edit_allowed = ['paused','pending'].includes(draft_poll.status) && total_responses == 0 ? true : false
623
+ const min_stake_changed = settings_edit_allowed && poll?.minimum_stake != parseFloat(min_stake) ? true : false
624
+ const max_stake_changed = settings_edit_allowed && poll?.max_stake != parseFloat(max_stake) ? true : false
625
+ const base_stake_changed = settings_edit_allowed && poll?.base_stake != parseFloat(base_stake) ? true : false
626
+ return (
627
+ <View transparent>
628
+ {player?.role == 'admin' ?
629
+ <View type='row' style={{ padding:20, borderBottomWidth:1, borderColor:Colors.borders.light }}>
630
+ <View transparent style={{ flex:1, marginRight:10 }}>
631
+ <Text theme='h1'>Base Stake</Text>
632
+ <Text theme='description' style={{ marginTop:3 }}>Fill responses with a base stake based on their probabilities.</Text>
633
+ </View>
634
+ <TextInput
635
+ value={base_stake}
636
+ editable={settings_edit_allowed}
637
+ style={{ width:75, textAlign:'center' }}
638
+ onFocusPosition={onFocusPosition}
639
+ onChangeText={(text) => setLabels({ ...labels, base_stake: text })}
640
+ />
641
+ {base_stake_changed && poll?.status == 'pending' ?
642
+ <Button
643
+ title='SAVE'
644
+ type='success'
645
+ onPress={() => {
646
+ let num = parseFloat(base_stake);
647
+ if(isNaN(num)){ return alert('Invalid value') }
648
+ if(num < 0){ return alert('Invalid amount') }
649
+ updatePoll({ ...draft_poll, base_stake: parseFloat(base_stake) })
650
+ }}
651
+ />
652
+ :<></>}
653
+ </View>
654
+ :<></>}
655
+ <View transparent type='row' style={{ padding:20, borderBottomWidth:1, borderColor:Colors.borders.light }}>
656
+ <View transparent style={{ flex:1, marginRight:10 }}>
657
+ <Text theme='h1'>Minimum Stake Allowed</Text>
658
+ <Text theme='description' style={{ marginTop:3 }}>The smallest bet allowed to be placed on this market.</Text>
659
+ </View>
660
+ <TextInput
661
+ value={min_stake}
662
+ editable={settings_edit_allowed}
663
+ onFocus={() => min_stake == '0' ? setLabels({ ...labels, min_stake: '' }): console.log('')}
664
+ style={{ width:75, textAlign:'center' }}
665
+ onFocusPosition={onFocusPosition}
666
+ onChangeText={(text) => setLabels({ ...labels, min_stake: text })}
667
+ />
668
+ {min_stake_changed ?
669
+ <Button
670
+ title='SAVE'
671
+ type='success'
672
+ onPress={() => {
673
+ let num = parseFloat(min_stake);
674
+ if(isNaN(num)){ return alert('Invalid value') }
675
+ if(num < 0){ return alert('Invalid amount') }
676
+ updatePoll({ ...draft_poll, minimum_stake: parseFloat(min_stake) })
677
+ }}
678
+ />
679
+ :<></>}
680
+ </View>
681
+ <View transparent type='row' style={{ padding:20, borderBottomWidth:1, borderColor:Colors.borders.light }}>
682
+ <View transparent style={{ flex:1, marginRight:10 }}>
683
+ <Text theme='h1'>Max Stake Allowed</Text>
684
+ <Text theme='description' style={{ marginTop:3 }}>The largest bet allowed to be placed on this market.</Text>
685
+ </View>
686
+ <TextInput
687
+ value={max_stake}
688
+ editable={settings_edit_allowed}
689
+ onFocus={() => max_stake == '0' ? setLabels({ ...labels, max_stake: '' }): console.log('')}
690
+ style={{ width:75, textAlign:'center' }}
691
+ onFocusPosition={onFocusPosition}
692
+ onChangeText={(text) => setLabels({ ...labels, max_stake: text })}
693
+ />
694
+ {max_stake_changed ?
695
+ <Button
696
+ title='SAVE'
697
+ type='success'
698
+ onPress={() => {
699
+ let num = parseFloat(max_stake);
700
+ if(isNaN(num)){ return alert('Invalid value') }
701
+ if(num < 0){ return alert('Invalid amount') }
702
+ updatePoll({ ...draft_poll, max_stake: parseFloat(max_stake) })
703
+ }}
704
+ />
705
+ :<></>}
706
+ </View>
707
+ <View transparent type='row' style={{ padding:20, borderBottomWidth:1, borderColor:Colors.borders.light }}>
708
+ <View transparent style={{ flex:1, marginRight:10 }}>
709
+ <Text theme='h1'>Allow Multiple Responses</Text>
710
+ <Text theme='description' style={{ marginTop:3 }}>If on, players can select multiple options.</Text>
711
+ </View>
712
+ <Switch
713
+ switch_type='on_off'
714
+ disabled={settings_edit_allowed ? false: true}
715
+ value={draft_poll.multi_responses_allowed ?? false}
716
+ onChange={async(val) => {
717
+ updatePoll({ ...draft_poll, multi_responses_allowed: val })
718
+ }}
719
+ />
720
+ </View>
721
+ <View transparent type='row' style={{ padding:20, borderBottomWidth:1, borderColor:Colors.borders.light }}>
722
+ <View transparent style={{ flex:1, marginRight:10 }}>
723
+ <Text theme='h1'>Allow Increase Stake</Text>
724
+ <Text theme='description' style={{ marginTop:3 }}>If on, players can continue to add more funds to a selected option.</Text>
725
+ </View>
726
+ <Switch
727
+ switch_type='on_off'
728
+ disabled={settings_edit_allowed ? false : true}
729
+ value={draft_poll.stake_increase_allowed ?? false}
730
+ onChange={async(val) => {
731
+ updatePoll({ ...draft_poll, stake_increase_allowed: val })
732
+ }}
733
+ />
734
+ </View>
735
+ <View transparent type='row' style={{ padding:20, borderBottomWidth:1, borderColor:Colors.borders.light }}>
736
+ <View transparent style={{ flex:1, marginRight:10 }}>
737
+ <Text theme='h1'>Flash Close Time</Text>
738
+ <Text theme='description' style={{ marginTop:3 }}>When should this market close?</Text>
739
+ </View>
740
+ <BETimePicker
741
+ selected_time={moment(poll?.end_datetime)}
742
+ disabled={settings_edit_allowed ? false : true}
743
+ onSelectTime={(val) => {
744
+ updatePoll({ ...draft_poll, end_datetime: val })
745
+ }}
746
+ />
747
+ </View>
748
+ </View>
749
+ )
750
+ default: return <></>
751
+ }
752
+ }
753
+
754
+ return (
755
+ <View float={float} style={{ flex:1 }}>
756
+ <View transparent style={{flex:1}}>
757
+ <FlatList
758
+ data={sections}
759
+ //keyboardShouldPersistTaps
760
+ key='flash_market_sections'
761
+ keyExtractor={item => item}
762
+ renderItem={renderSections}
763
+ />
764
+ </View>
765
+ </View>
766
+ )
767
+ }
768
+
769
+ export default ManageFlashMarket