be-components 7.2.2 → 7.2.3

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 (59) hide show
  1. package/lib/commonjs/PartnerPortal/api/index.js +134 -1
  2. package/lib/commonjs/PartnerPortal/api/index.js.map +1 -1
  3. package/lib/commonjs/PartnerPortal/components/PromoSelector.js +100 -0
  4. package/lib/commonjs/PartnerPortal/components/PromoSelector.js.map +1 -0
  5. package/lib/commonjs/PartnerPortal/components/ReferralCodeManager.js +498 -0
  6. package/lib/commonjs/PartnerPortal/components/ReferralCodeManager.js.map +1 -0
  7. package/lib/commonjs/PartnerPortal/index.js +332 -1
  8. package/lib/commonjs/PartnerPortal/index.js.map +1 -1
  9. package/lib/commonjs/index.js +7 -0
  10. package/lib/commonjs/index.js.map +1 -1
  11. package/lib/commonjs/types.d.js.map +1 -1
  12. package/lib/module/PartnerPortal/api/index.js +133 -0
  13. package/lib/module/PartnerPortal/api/index.js.map +1 -1
  14. package/lib/module/PartnerPortal/components/PromoSelector.js +93 -0
  15. package/lib/module/PartnerPortal/components/PromoSelector.js.map +1 -0
  16. package/lib/module/PartnerPortal/components/ReferralCodeManager.js +490 -0
  17. package/lib/module/PartnerPortal/components/ReferralCodeManager.js.map +1 -0
  18. package/lib/module/PartnerPortal/index.js +334 -3
  19. package/lib/module/PartnerPortal/index.js.map +1 -1
  20. package/lib/module/index.js +2 -1
  21. package/lib/module/index.js.map +1 -1
  22. package/lib/module/types.d.js.map +1 -1
  23. package/lib/typescript/lib/commonjs/PartnerPortal/api/index.d.ts +23 -0
  24. package/lib/typescript/lib/commonjs/PartnerPortal/api/index.d.ts.map +1 -1
  25. package/lib/typescript/lib/commonjs/PartnerPortal/components/PromoSelector.d.ts +10 -0
  26. package/lib/typescript/lib/commonjs/PartnerPortal/components/PromoSelector.d.ts.map +1 -0
  27. package/lib/typescript/lib/commonjs/PartnerPortal/components/ReferralCodeManager.d.ts +12 -0
  28. package/lib/typescript/lib/commonjs/PartnerPortal/components/ReferralCodeManager.d.ts.map +1 -0
  29. package/lib/typescript/lib/commonjs/PartnerPortal/index.d.ts +2 -1
  30. package/lib/typescript/lib/commonjs/PartnerPortal/index.d.ts.map +1 -1
  31. package/lib/typescript/lib/commonjs/index.d.ts +1 -0
  32. package/lib/typescript/lib/commonjs/index.d.ts.map +1 -1
  33. package/lib/typescript/lib/module/PartnerPortal/api/index.d.ts +23 -0
  34. package/lib/typescript/lib/module/PartnerPortal/api/index.d.ts.map +1 -1
  35. package/lib/typescript/lib/module/PartnerPortal/components/PromoSelector.d.ts +10 -0
  36. package/lib/typescript/lib/module/PartnerPortal/components/PromoSelector.d.ts.map +1 -0
  37. package/lib/typescript/lib/module/PartnerPortal/components/ReferralCodeManager.d.ts +12 -0
  38. package/lib/typescript/lib/module/PartnerPortal/components/ReferralCodeManager.d.ts.map +1 -0
  39. package/lib/typescript/lib/module/PartnerPortal/index.d.ts +2 -1
  40. package/lib/typescript/lib/module/PartnerPortal/index.d.ts.map +1 -1
  41. package/lib/typescript/lib/module/index.d.ts +2 -1
  42. package/lib/typescript/lib/module/index.d.ts.map +1 -1
  43. package/lib/typescript/src/PartnerPortal/api/index.d.ts +19 -1
  44. package/lib/typescript/src/PartnerPortal/api/index.d.ts.map +1 -1
  45. package/lib/typescript/src/PartnerPortal/components/PromoSelector.d.ts +12 -0
  46. package/lib/typescript/src/PartnerPortal/components/PromoSelector.d.ts.map +1 -0
  47. package/lib/typescript/src/PartnerPortal/components/ReferralCodeManager.d.ts +15 -0
  48. package/lib/typescript/src/PartnerPortal/components/ReferralCodeManager.d.ts.map +1 -0
  49. package/lib/typescript/src/PartnerPortal/index.d.ts +3 -2
  50. package/lib/typescript/src/PartnerPortal/index.d.ts.map +1 -1
  51. package/lib/typescript/src/index.d.ts +2 -1
  52. package/lib/typescript/src/index.d.ts.map +1 -1
  53. package/package.json +1 -1
  54. package/src/PartnerPortal/api/index.ts +119 -1
  55. package/src/PartnerPortal/components/PromoSelector.tsx +61 -0
  56. package/src/PartnerPortal/components/ReferralCodeManager.tsx +303 -0
  57. package/src/PartnerPortal/index.tsx +163 -8
  58. package/src/index.tsx +2 -0
  59. package/src/types.d.ts +21 -0
@@ -0,0 +1,303 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Button, Text, TextInput, View } from "../../Components/Themed";
3
+ import type { FocusPositionProps, PlayerReferralProps, PromoProps } from '../../types';
4
+ import { PartnerPortalApi, PartnerPortalHelpers } from '../api';
5
+ import { FlatList, ImageBackground, type ViewStyle } from 'react-native';
6
+ import PromoSelector from './PromoSelector';
7
+ import { useColors } from '../../constants/useColors';
8
+ import { showConfirmAlert } from '../../Components/ConfirmAlert';
9
+
10
+ type ReferralCodeManagerProps = {
11
+ player_referral_id?:string,
12
+ company_id?:string,
13
+ onFocusPosition?:(pos:FocusPositionProps) => void,
14
+ float?:boolean,
15
+ onClose: () => void,
16
+ header_style?:ViewStyle,
17
+ footer_style?:ViewStyle
18
+ }
19
+ const sections = ['header','info','code','promo','inactivate','activate','delete']
20
+ const ReferralCodeManager = ({ float, player_referral_id, company_id, header_style, footer_style, onFocusPosition, onClose }:ReferralCodeManagerProps) => {
21
+ const Colors = useColors();
22
+ const [ action_loading, setActionLoading ] = useState(false);
23
+ const [ size, setSize ] = useState({ height:0, width:0 });
24
+ const [ state, setState ] = useState<{
25
+ checked:boolean,
26
+ available:boolean,
27
+ promos:PromoProps[],
28
+ player_referral?:PlayerReferralProps,
29
+ draft_referral?:PlayerReferralProps
30
+ }>({
31
+ draft_referral: undefined,
32
+ player_referral:undefined,
33
+ promos:[],
34
+ checked:false,
35
+ available:false
36
+ });
37
+ const { draft_referral, promos, player_referral, checked, available } = state;
38
+ const active_promo = promos.find(p => p.promo_id == draft_referral?.promo_id);
39
+ useEffect(() => {
40
+ PartnerPortalApi.setEnvironment();
41
+ getData(player_referral_id);
42
+ },[player_referral_id]);
43
+
44
+ const getData = async(id?:string) => {
45
+ const s_promos = await PartnerPortalApi.CompanyApi.getPromos();
46
+ let s_refer:PlayerReferralProps | undefined
47
+ if(id){
48
+ s_refer = await PartnerPortalApi.CompanyApi.getReferralById(id);
49
+ if(!s_refer){ return alert('Unable to get referral. Please try again') }
50
+ } else {
51
+ s_refer = PartnerPortalHelpers.CompanyHelpers.generateNewReferral()
52
+ }
53
+ setState({
54
+ checked:id ? true : false,
55
+ available: id ? true : false,
56
+ promos:s_promos,
57
+ draft_referral: s_refer,
58
+ player_referral: id ? s_refer : undefined
59
+ })
60
+ }
61
+
62
+ const isValid = () => {
63
+ let errors:string[] = []
64
+ if(!draft_referral){ return ['Please complete this form'] }
65
+ if(!draft_referral.referral_code){ errors.push('Please enter a valid code') }
66
+ if(!checked){ errors.push('Please check if the referral code is available') }
67
+ if(!available){ errors.push('This code is not available to use') }
68
+ if(!active_promo){ errors.push('Add a promo code') }
69
+ return errors
70
+ }
71
+ const errors = isValid();
72
+
73
+ const checkAvailability = async(code:string) => {
74
+ if(action_loading){ return }
75
+ if(!code){ return alert('Please enter a code') }
76
+ setActionLoading(true);
77
+ const resp = await PartnerPortalApi.CompanyApi.getReferralByCode(code.toLowerCase());
78
+ setState({ ...state, checked: true, available: resp.player_referral ? false : true });
79
+ setActionLoading(false)
80
+ }
81
+
82
+ const deactivate = async() => {
83
+ if(!player_referral){ return }
84
+ if(action_loading){ return }
85
+ setActionLoading(true);
86
+ const new_code = await PartnerPortalApi.CompanyApi.deactivateCode(player_referral.player_referral_id);
87
+ if(!new_code){ return alert('Unable to process. Please try again later') }
88
+ setState({ ...state, player_referral: new_code, draft_referral:new_code })
89
+ setActionLoading(false);
90
+ }
91
+
92
+ const activate = async() => {
93
+ if(!player_referral){ return }
94
+ if(action_loading){ return }
95
+ setActionLoading(true);
96
+ const new_code = await PartnerPortalApi.CompanyApi.activateCode(player_referral.player_referral_id);
97
+ if(!new_code){ return alert('Unable to process. Please try again later') }
98
+ setState({ ...state, player_referral: new_code, draft_referral:new_code })
99
+ setActionLoading(false);
100
+ }
101
+
102
+ const deleteCode = async() => {
103
+ if(!player_referral){ return }
104
+ if(action_loading){ return }
105
+ setActionLoading(true);
106
+ const new_code = await PartnerPortalApi.CompanyApi.deleteCode(player_referral.player_referral_id);
107
+ if(!new_code){ return alert('Unable to process. Please try again later') }
108
+ setState({ ...state, player_referral: new_code, draft_referral:new_code })
109
+ setActionLoading(false);
110
+ }
111
+
112
+ const handleUpdate = async(dr:PlayerReferralProps) => {
113
+ if(action_loading){ return }
114
+ setActionLoading(true);
115
+ const new_referral = await PartnerPortalApi.CompanyApi.updateCodeOnReferral(dr);
116
+ if(!new_referral){ return alert('Unable to process at this time') }
117
+ setState({
118
+ ...state,
119
+ draft_referral: new_referral,
120
+ player_referral: new_referral
121
+ });
122
+ setActionLoading(false);
123
+ }
124
+
125
+ const handleCreate = async() => {
126
+ if(action_loading){ return }
127
+ if(!draft_referral){ return }
128
+ if(errors.length > 0){ return alert(errors.map(e => e)) }
129
+ setActionLoading(true);
130
+ const new_code = await PartnerPortalApi.CompanyApi.createCode({ ...draft_referral, company_id});
131
+ if(!new_code){ return alert('Unable to process. Please try again later') }
132
+ setState({ ...state, player_referral: new_code, draft_referral:new_code })
133
+ setActionLoading(false);
134
+ }
135
+
136
+ const renderSections = (data: { item:string, index:number }) => {
137
+ switch(data.item){
138
+ case 'header':
139
+ return (
140
+ <View type='header' style={{ flexDirection:'row', alignItems:'center', padding:10, ...header_style }}>
141
+ <View transparent style={{ flex:1 }}>
142
+ <Text theme='h1'>Manage Referral Code</Text>
143
+ <Text theme='description' style={{ marginTop:3 }}>Update or create your referral code below</Text>
144
+ </View>
145
+ </View>
146
+ )
147
+ case 'info':
148
+ return (
149
+ <ImageBackground
150
+ source={{ uri: 'https://res.cloudinary.com/hoabts6mc/image/upload/w_1000,ar_16:9,c_fill,g_auto,e_sharpen/v1758727070/ChatGPT_Image_Sep_24_2025_10_17_44_AM_w39gdn.png' }}
151
+ style={{ width: size.width, height:225, justifyContent:'flex-end', overflow:'hidden', ...header_style}}>
152
+ <View type='dark_blur' style={{ padding:20 }}>
153
+ <Text theme='h1' size={36}>Referral Code</Text>
154
+ <Text theme='description' size={16} style={{ marginTop:3 }}>Track the users that sign up for BettorEdge with referral codes</Text>
155
+ </View>
156
+ </ImageBackground>
157
+ )
158
+ case 'code':
159
+ if(!draft_referral){ return <></> }
160
+ return (
161
+ <View transparent style={{ padding:20, borderBottomWidth:1, borderColor:Colors.borders.light }}>
162
+ <View transparent style={{ marginBottom:10 }}>
163
+ <Text theme='h1'>Referral Code</Text>
164
+ <Text theme='description' style={{ marginTop:4 }}>Enter the referral code and check its availability</Text>
165
+ </View>
166
+ <View transparent type='row'>
167
+ <TextInput
168
+ value={draft_referral.referral_code}
169
+ onFocusPosition={onFocusPosition}
170
+ editable={player_referral ? false : true}
171
+ style={{ flex:1, marginLeft:5, textAlign:'center', borderColor:available?Colors.text.success:checked?Colors.text.error:Colors.text.warning }}
172
+ onChangeText={(text) => setState({ ...state, checked:false, available: false, draft_referral: { ...draft_referral, referral_code: text } })}
173
+ />
174
+ {!player_referral ?
175
+ <Button
176
+ title='CHECK'
177
+ type='success'
178
+ loading={action_loading}
179
+ disabled={checked || !draft_referral.referral_code}
180
+ style={{ marginLeft:5, opacity: checked || !draft_referral.referral_code ? 0.5 : 1 }}
181
+ onPress={() => checkAvailability(draft_referral.referral_code)}
182
+ />
183
+ :<></>}
184
+ </View>
185
+ {player_referral ?
186
+ <Text theme='error' style={{ marginTop:4 }}>To change the referral code. Please inactivate this one and create a new one</Text>
187
+ :checked && available?
188
+ <Text theme='success' style={{ marginTop:4 }}>Great! This code is available</Text>
189
+ :checked && !available ?
190
+ <Text theme='error' style={{ marginTop:4 }}>Sorry! This code is already taken</Text>
191
+ :<></>}
192
+ </View>
193
+ )
194
+ case 'promo':
195
+ if(!draft_referral){ return <></> }
196
+ return (
197
+ <View transparent style={{ padding:20 }}>
198
+ <View transparent style={{ marginBottom:10 }}>
199
+ <Text theme='h1'>Promotion Type</Text>
200
+ <Text theme='description' style={{ marginTop:4 }}>Select the type of promotion for this code</Text>
201
+ </View>
202
+ <PromoSelector
203
+ promos={promos}
204
+ limited_type='promo_code'
205
+ max_value={20}
206
+ active_promo={active_promo}
207
+ onSelectPromo={(promo) => setState({ ...state, draft_referral: { ...draft_referral, promo_id: promo.promo_id } })}
208
+ />
209
+ </View>
210
+ )
211
+ case 'inactivate':
212
+ if(!player_referral){ return <></> }
213
+ if(player_referral.status != 'pending'){ return <></> }
214
+
215
+ return (
216
+ <View transparent style={{ padding:20 }}>
217
+ <Button
218
+ title='DEACTIVATE CODE'
219
+ loading={action_loading}
220
+ type='error'
221
+ onPress={() => deactivate()}
222
+ />
223
+ </View>
224
+ )
225
+ case 'activate':
226
+ if(!player_referral){ return <></> }
227
+ if(player_referral.status != 'inactive'){ return <></> }
228
+ return (
229
+ <View transparent style={{ flexDirection:'row', padding:20 }}>
230
+ <Button
231
+ title='ARCHVE'
232
+ loading={action_loading}
233
+ type='error'
234
+ style={{ flex:1, marginRight:5 }}
235
+ onPress={() => {
236
+ showConfirmAlert('Are You Sure?', 'Once archived the code can no longer be activated or used',
237
+ () => deleteCode(),
238
+ () => console.log('')
239
+ )
240
+ }}
241
+ />
242
+ <Button
243
+ title='ACTIVATE CODE'
244
+ loading={action_loading}
245
+ type='success'
246
+ style={{ flex:3 }}
247
+ onPress={() => activate()}
248
+ />
249
+ </View>
250
+ )
251
+ default: return <></>
252
+ }
253
+ }
254
+ const is_changed = JSON.stringify(player_referral) != JSON.stringify(draft_referral) ? true : false
255
+ return (
256
+ <View float={float} style={{ flex:1 }} onLayout={(ev) => {
257
+ const { width, height } = ev.nativeEvent.layout
258
+ setSize({ width, height })
259
+ }}>
260
+ <FlatList
261
+ data={sections}
262
+ key='code_sections'
263
+ keyExtractor={item => item}
264
+ renderItem={renderSections}
265
+ />
266
+ {player_referral?.status == 'closed' ?
267
+ <View type='blur' style={{ position:'absolute', top:0, left:0, right:0, bottom:0, justifyContent:'center', alignItems:'center' }}>
268
+ <View float style={{ height:200, width:200, justifyContent:'center', alignItems:'center' }}>
269
+ <Text theme='h1' textAlign='center'>CODE HAS BEEN ARCHIVED</Text>
270
+ </View>
271
+ </View>
272
+ :<></>}
273
+ <View type='footer' style={{ flexDirection:'row', alignItems:'center', padding:10, ...footer_style }}>
274
+ <Button
275
+ title='CLOSE'
276
+ type='close'
277
+ style={{ flex:1 }}
278
+ onPress={() => onClose()}
279
+ />
280
+ {player_referral && draft_referral ?
281
+ <Button
282
+ title='SAVE CODE'
283
+ style={{ flex:3, marginLeft:5, opacity: is_changed && !action_loading ? 1 : 0.5 }}
284
+ loading={action_loading}
285
+ type='success'
286
+ disabled={!is_changed || action_loading}
287
+ onPress={() => handleUpdate(draft_referral)}
288
+ />
289
+ :
290
+ <Button
291
+ title='CREATE CODE'
292
+ style={{ flex:3, marginLeft:5, opacity: errors.length == 0 && !action_loading ? 1 : 0.5 }}
293
+ loading={action_loading}
294
+ type='success'
295
+ disabled={action_loading}
296
+ onPress={() => handleCreate()}
297
+ />
298
+ }
299
+ </View>
300
+ </View>
301
+ )
302
+ }
303
+ export default ReferralCodeManager
@@ -1,19 +1,21 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import { Button, Text, View } from "../Components/Themed"
3
- import type { BracketCompetitionProps, CompanyEmbedProps, CompanyProps, CompetitionProps, EmbedPropertyProps, EmbedProps, ExternalKeyProps, MyPlayerProps, PollCampaignProps, PublicPlayerProps, SquaresCompetitionProps } from '../types';
3
+ import type { BracketCompetitionProps, CompanyEmbedProps, CompanyPlayerProps, CompanyPlayerStatProps, CompanyProps, CompetitionProps, EmbedPropertyProps, EmbedProps, ExternalKeyProps, MyPlayerProps, PlayerReferralProps, PollCampaignProps, PromoProps, PublicPlayerProps, SquaresCompetitionProps } from '../types';
4
4
  import type { CompanyMemberProps } from '../Authenticator/api/types';
5
5
  import { PartnerPortalApi } from './api';
6
- import { FlatList, Image } from 'react-native';
6
+ import { FlatList, Image, ScrollView } from 'react-native';
7
7
  import { useColors } from '../constants/useColors';
8
8
  import ImageUploader from '../Components/ImageUploader';
9
9
  import moment from 'moment-mini';
10
- import { Icons } from '../Components';
10
+ import { Icons, SearchBox } from '../Components';
11
+ import Pagination from '../Components/Pagination';
11
12
 
12
13
  type PartnerPortalProps = {
13
14
  me:MyPlayerProps,
14
15
  company_id:string,
15
16
  refresh_key?:string,
16
17
  onCreateEmbed:() => void,
18
+ onManageReferral: (pr?:PlayerReferralProps) => void,
17
19
  onCreateEngagement: (init_engagement?:string) => void,
18
20
  onSelectCompanyEmbed: (company_embed:CompanyEmbedProps) => void,
19
21
  onSelectCompetition: (competition:CompetitionProps) => void,
@@ -22,9 +24,9 @@ type PartnerPortalProps = {
22
24
  onSelectFlashCampaign: (flash_campaign:PollCampaignProps) => void
23
25
  }
24
26
 
25
- const sections = ['top_row','second_row','third_row']
27
+ const sections = ['top_row','stats','referrals','second_row','third_row']
26
28
 
27
- const PartnerPortal = ({ me, company_id, refresh_key, onCreateEngagement, onSelectBracketCompetition, onCreateEmbed, onSelectCompanyEmbed, onSelectCompetition, onSelectFlashCampaign, onSelectSquaresCompetition }:PartnerPortalProps) => {
29
+ const PartnerPortal = ({ me, company_id, refresh_key, onCreateEngagement, onSelectBracketCompetition, onManageReferral, onCreateEmbed, onSelectCompanyEmbed, onSelectCompetition, onSelectFlashCampaign, onSelectSquaresCompetition }:PartnerPortalProps) => {
28
30
  const Colors = useColors();
29
31
  const [ engagement_state, setEngagementState ] = useState<{
30
32
  loading: boolean,
@@ -50,17 +52,30 @@ const PartnerPortal = ({ me, company_id, refresh_key, onCreateEngagement, onSele
50
52
  loading: boolean,
51
53
  company?:CompanyProps,
52
54
  my_member?:CompanyMemberProps,
55
+ company_player_stats:CompanyPlayerStatProps[],
56
+ company_players:CompanyPlayerProps[],
57
+ company_players_offset:number,
58
+ player_referrals:PlayerReferralProps[],
59
+ promos:PromoProps[],
53
60
  company_members:CompanyMemberProps[],
54
61
  external_keys:ExternalKeyProps[],
55
62
  players:PublicPlayerProps[],
56
63
  }>({
57
64
  loading:false,
58
65
  company_members: [],
66
+ company_players_offset: 0,
59
67
  external_keys: [],
68
+ player_referrals:[],
69
+ company_player_stats:[],
70
+ company_players:[],
71
+ promos:[],
60
72
  players: []
61
- })
62
- const { company, external_keys, players, company_members } = state;
63
-
73
+ });
74
+ const [ referral_search, setReferralSearch ] = useState('');
75
+ const [ player_search, setPlayerSearch ] = useState('');
76
+ const { company, promos, company_players_offset, company_player_stats, company_players, player_referrals, external_keys, players, company_members } = state;
77
+ const filtered_referrals = player_referrals.filter(r => r.referral_code.toLowerCase().includes(referral_search.toLowerCase())).slice(0,5);
78
+ const filtered_players = company_players.sort((a,b) => b.revenue - a.revenue).filter(p => p.username.toLowerCase().includes(player_search.toLowerCase())).slice(0,5);
64
79
  useEffect(() => {
65
80
  PartnerPortalApi.setEnvironment();
66
81
  getStateData();
@@ -75,16 +90,32 @@ const PartnerPortal = ({ me, company_id, refresh_key, onCreateEngagement, onSele
75
90
  const s_playes = await PartnerPortalApi.getPlayersByPlayerIds(player_ids);
76
91
  const my_co_member = company_response?.company_members.find(cm => cm.player_id == me.player_id);
77
92
  const s_keys = await PartnerPortalApi.CompanyApi.getApiKeys(company_id);
93
+ const s_refer = await PartnerPortalApi.CompanyApi.getReferralCodesByCompanyId(company_id);
94
+ const s_stats = await PartnerPortalApi.CompanyApi.getCompanyPlayerStats(company_id);
95
+ const s_cps = await PartnerPortalApi.CompanyApi.getCompanyPlayers(company_id, 0);
78
96
  setState({
79
97
  ...state,
80
98
  loading: false,
81
99
  company: company_response?.company,
82
100
  external_keys: s_keys,
101
+ promos: s_refer.promos,
102
+ company_players: s_cps,
103
+ player_referrals: s_refer.player_referrals,
104
+ company_player_stats: s_stats,
83
105
  players: s_playes,
106
+ company_players_offset: 0,
84
107
  my_member:my_co_member,
85
108
  company_members: company_response?.company_members ?? []
86
109
  });
87
110
  }
111
+ const getAdditionalPlayers = async(page:number) => {
112
+ const s_cps = await PartnerPortalApi.CompanyApi.getCompanyPlayers(company_id, page);
113
+ setState({
114
+ ...state,
115
+ company_players: s_cps,
116
+ company_players_offset: page
117
+ })
118
+ }
88
119
 
89
120
  const getActiveEngagementData = async() => {
90
121
  setEngagementState({ ...engagement_state, loading:true });
@@ -217,6 +248,57 @@ const PartnerPortal = ({ me, company_id, refresh_key, onCreateEngagement, onSele
217
248
  )
218
249
  }
219
250
 
251
+ const renderPlayers = (data:{ item:CompanyPlayerProps, index:number }) => {
252
+ return (
253
+ <View transparent type='row' style={{ padding:10, margin:4, minWidth:300, flexGrow:1, borderBottomWidth:1, borderColor:Colors.borders.light }}>
254
+ <Image
255
+ source={{ uri: data.item.profile_pic }}
256
+ style={{ height:40, width:40, borderRadius:100 }}
257
+ resizeMode='cover'
258
+ />
259
+ <View float style={{ marginRight:10, marginLeft:10, padding:5, borderRadius:22, backgroundColor:data.item.vouched_status == 'verified' ? Colors.text.success : data.item.vouched_status == 'unverified' ? Colors.text.action : Colors.text.error }}>
260
+ <Text theme='h1' color={Colors.text.white}>{data.item.vouched_status.toUpperCase()}</Text>
261
+ </View>
262
+ <View transparent style={{ flex:1, minWidth:200, marginLeft:10 }}>
263
+ <Text theme='h1'>{data.item.username}</Text>
264
+ <Text theme='description' style={{ marginTop:3 }}>Used Code {data.item.code_used}</Text>
265
+ </View>
266
+ <View float style={{ marginRight:25, padding:5, borderRadius:22, backgroundColor:data.item.verified ? Colors.text.success : Colors.text.error }}>
267
+ <Text theme='h1' color={Colors.text.white}>Email</Text>
268
+ </View>
269
+ <View float style={{ marginRight:25, padding:5, borderRadius:22, backgroundColor:data.item.phone_verified ? Colors.text.success : Colors.text.error }}>
270
+ <Text theme='h1' color={Colors.text.white}>Phone</Text>
271
+ </View>
272
+ <View transparent style={{ alignItems:'flex-end' }}>
273
+ <Text theme='h1' color={Colors.text.success}>${data.item.revenue.toFixed(2)}</Text>
274
+ <Text theme='description' style={{ marginTop:3 }}>Revenue Generated</Text>
275
+ </View>
276
+ </View>
277
+ )
278
+ }
279
+
280
+ const renderReferrals = (data:{ item:PlayerReferralProps, index:number }) => {
281
+ const promo = promos.find(e => e.promo_id == data.item.promo_id);
282
+ if(!promo){ return <></> }
283
+ const stats = company_player_stats.filter(ps => ps.referral_code.toLowerCase() == data.item.referral_code.toLowerCase());
284
+ const players_generated = stats.reduce((a,b) => a + b.player_count, 0)
285
+ return (
286
+ <Button
287
+ transparent
288
+ style={{ padding:10, borderRadius:0, flexDirection:'row', alignItems:'center', borderBottomWidth:1, borderColor:Colors.borders.light }}
289
+ onPress={() => onManageReferral(data.item)}>
290
+ <View transparent style={{ flex:1, marginLeft:10 }}>
291
+ <Text theme='h1'>{data.item.referral_code}</Text>
292
+ <Text theme='description' style={{ marginTop:3 }}>{data.item.status == 'pending' ? 'ACTIVE': data.item.status.toUpperCase()} - {promo.description}</Text>
293
+ </View>
294
+ <View transparent style={{ alignItems:'flex-end' }}>
295
+ <Text theme='h1' color={Colors.text.action}>{players_generated}</Text>
296
+ <Text theme='description' style={{ marginTop:3 }}>Players Generated</Text>
297
+ </View>
298
+ </Button>
299
+ )
300
+ }
301
+
220
302
  const renderMembers = (data:{ item:CompanyMemberProps, index:number }) => {
221
303
  const player = players.find(p => p.player_id == data.item.player_id);
222
304
  if(!player){ return <></> }
@@ -235,6 +317,7 @@ const PartnerPortal = ({ me, company_id, refresh_key, onCreateEngagement, onSele
235
317
  )
236
318
  }
237
319
 
320
+
238
321
  const renderSections = (data:{ item:string, index:number }) => {
239
322
  switch(data.item){
240
323
  case 'top_row':
@@ -314,6 +397,78 @@ const PartnerPortal = ({ me, company_id, refresh_key, onCreateEngagement, onSele
314
397
 
315
398
  </View>
316
399
  )
400
+ case 'stats':
401
+ const player_count = company_player_stats.reduce((a,b) => a + b.player_count, 0);
402
+ return (
403
+ <View transparent style={{ flexDirection:'row', flexWrap:'wrap' }}>
404
+ <View float nativeID='player_count' style={{ flexGrow:1, minWidth: 250, margin:10 }}>
405
+ <View transparent style={{ justifyContent:'center', alignItems:'center', padding:10 }}>
406
+ <Text theme='h1' size={40}>{player_count}</Text>
407
+ </View>
408
+ <View type='footer' style={{ flexDirection:'row', alignItems:'center', padding:10, borderBottomRightRadius:8, borderBottomLeftRadius:8 }}>
409
+ <View transparent style={{ flex:1 }}>
410
+ <Text theme='h1' color={Colors.text.success}>Users Generated</Text>
411
+ </View>
412
+ </View>
413
+ </View>
414
+ <View float nativeID='company_referrals' style={{ flexGrow:4, minWidth:300, margin:10 }}>
415
+ <View type='header' style={{ flexDirection:'row', alignItems:'center', padding:10, borderTopRightRadius:8, borderTopLeftRadius:8 }}>
416
+ <View transparent style={{ flex:1 }}>
417
+ <Text theme='h1'>Players Generated</Text>
418
+ <Text theme='description' style={{ marginTop:3 }}>See all players that have joined BettorEdge using your referral code</Text>
419
+ </View>
420
+ </View>
421
+ <View style={{ padding:10 }}>
422
+ <SearchBox hide_search_button onChange={(text) => setPlayerSearch(text)} />
423
+ </View>
424
+ <ScrollView horizontal={true} contentContainerStyle={{ flexGrow: 1 }}>
425
+ <View transparent type='body' style={{ flex:1 }}>
426
+ <FlatList
427
+ data={filtered_players}
428
+ key={'company_players'}
429
+ keyExtractor={item => item.player_id.toString()}
430
+ renderItem={renderPlayers}
431
+ />
432
+ </View>
433
+ </ScrollView>
434
+ <Pagination offset={company_players_offset} onNext={() => getAdditionalPlayers(company_players_offset + 1)} onPrevious={() => getAdditionalPlayers(company_players_offset - 1)} />
435
+ </View>
436
+ <View />
437
+ </View>
438
+ )
439
+ case 'referrals':
440
+ return (
441
+ <View transparent style={{ flexDirection:'row', flexWrap:'wrap' }}>
442
+ <View float nativeID='company_referrals' style={{ flexGrow:4, flexBasis:4, minWidth:300, margin:10 }}>
443
+ <View type='header' style={{ flexDirection:'row', alignItems:'center', padding:10, borderTopRightRadius:8, borderTopLeftRadius:8 }}>
444
+ <View transparent style={{ flex:1 }}>
445
+ <Text theme='h1'>Referral Codes</Text>
446
+ <Text theme='description' style={{ marginTop:3 }}>Active Referral Codes</Text>
447
+ </View>
448
+ <View transparent style={{ padding:10 }}>
449
+ <Text theme='h1' color={Colors.text.action}>{player_referrals.length}</Text>
450
+ </View>
451
+ <Button
452
+ title='CREATE'
453
+ type='success'
454
+ style={{ padding:10 }}
455
+ onPress={() => onManageReferral()}
456
+ />
457
+ </View>
458
+ <View style={{ padding:10 }}>
459
+ <SearchBox hide_search_button onChange={(text) => setReferralSearch(text)} />
460
+ </View>
461
+ <View transparent type='body'>
462
+ <FlatList
463
+ data={filtered_referrals.sort((a,b) => moment(a.create_datetime).unix() - moment(b.create_datetime).unix())}
464
+ key={'company_referrals'}
465
+ keyExtractor={item => item.player_referral_id.toString()}
466
+ renderItem={renderReferrals}
467
+ />
468
+ </View>
469
+ </View>
470
+ </View>
471
+ )
317
472
  case 'second_row':
318
473
  const active_embeds = company_embeds.length
319
474
  return (
package/src/index.tsx CHANGED
@@ -66,10 +66,12 @@ import ManageFlashMarket from './FlashMarket/components/ManageFlashMarket';
66
66
  import PartnerPortal from './PartnerPortal';
67
67
  import EmbedManager from './PartnerPortal/components/EmbedManager';
68
68
  import CreateEmbed from './PartnerPortal/components/CreateEmbed';
69
+ import ReferralCodeManager from './PartnerPortal/components/ReferralCodeManager';
69
70
  export {
70
71
  Authenticator,
71
72
  Observer,
72
73
  CreateEmbed,
74
+ ReferralCodeManager,
73
75
  CreateEngagement,
74
76
  DiscordConnectionManager,
75
77
  BEEventApi,
package/src/types.d.ts CHANGED
@@ -436,6 +436,27 @@ export interface CompanyProps {
436
436
  last_update_datetime: any
437
437
  }
438
438
 
439
+ export interface CompanyPlayerStatProps {
440
+ player_count: number,
441
+ referral_code:string,
442
+ vouched_status:string,
443
+ revenue: number
444
+ }
445
+
446
+ export interface CompanyPlayerProps {
447
+ player_id:string,
448
+ username:string,
449
+ email:string,
450
+ profile_pic?:string,
451
+ phone:number,
452
+ verified:boolean,
453
+ phone_verified:boolean,
454
+ vouched_status:'verified'|'unverified'|'failed'
455
+ code_used:string,
456
+ revenue:number,
457
+ create_datetime:any
458
+ }
459
+
439
460
  export interface PlayerPodcastProps {
440
461
  player_podcast_id:string,
441
462
  player_id:string,