be-components 7.0.6 → 7.0.8

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