be-components 6.6.1 → 6.6.2
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.
- package/lib/commonjs/Engage/components/CompetitionCard.js +54 -1
- package/lib/commonjs/Engage/components/CompetitionCard.js.map +1 -1
- package/lib/commonjs/Group/api/index.js +203 -0
- package/lib/commonjs/Group/api/index.js.map +1 -0
- package/lib/commonjs/Group/components/GroupCTAButton.js +85 -0
- package/lib/commonjs/Group/components/GroupCTAButton.js.map +1 -0
- package/lib/commonjs/Group/components/GroupPlayerActionForm.js +166 -0
- package/lib/commonjs/Group/components/GroupPlayerActionForm.js.map +1 -0
- package/lib/commonjs/Group/components/ManageGroupForm.js +476 -0
- package/lib/commonjs/Group/components/ManageGroupForm.js.map +1 -0
- package/lib/commonjs/Group/index.js +671 -0
- package/lib/commonjs/Group/index.js.map +1 -0
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/Engage/components/CompetitionCard.js +54 -1
- package/lib/module/Engage/components/CompetitionCard.js.map +1 -1
- package/lib/module/Group/api/index.js +197 -0
- package/lib/module/Group/api/index.js.map +1 -0
- package/lib/module/Group/components/GroupCTAButton.js +78 -0
- package/lib/module/Group/components/GroupCTAButton.js.map +1 -0
- package/lib/module/Group/components/GroupPlayerActionForm.js +159 -0
- package/lib/module/Group/components/GroupPlayerActionForm.js.map +1 -0
- package/lib/module/Group/components/ManageGroupForm.js +469 -0
- package/lib/module/Group/components/ManageGroupForm.js.map +1 -0
- package/lib/module/Group/index.js +663 -0
- package/lib/module/Group/index.js.map +1 -0
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/lib/commonjs/Engage/components/CompetitionCard.d.ts +4 -1
- package/lib/typescript/lib/commonjs/Engage/components/CompetitionCard.d.ts.map +1 -1
- package/lib/typescript/lib/commonjs/Group/api/index.d.ts +38 -0
- package/lib/typescript/lib/commonjs/Group/api/index.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/Group/components/GroupCTAButton.d.ts +10 -0
- package/lib/typescript/lib/commonjs/Group/components/GroupCTAButton.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/Group/components/GroupPlayerActionForm.d.ts +9 -0
- package/lib/typescript/lib/commonjs/Group/components/GroupPlayerActionForm.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/Group/components/ManageGroupForm.d.ts +10 -0
- package/lib/typescript/lib/commonjs/Group/components/ManageGroupForm.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/Group/index.d.ts +12 -0
- package/lib/typescript/lib/commonjs/Group/index.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/index.d.ts +1 -0
- package/lib/typescript/lib/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/lib/module/Engage/components/CompetitionCard.d.ts +4 -1
- package/lib/typescript/lib/module/Engage/components/CompetitionCard.d.ts.map +1 -1
- package/lib/typescript/lib/module/Group/api/index.d.ts +37 -0
- package/lib/typescript/lib/module/Group/api/index.d.ts.map +1 -0
- package/lib/typescript/lib/module/Group/components/GroupCTAButton.d.ts +10 -0
- package/lib/typescript/lib/module/Group/components/GroupCTAButton.d.ts.map +1 -0
- package/lib/typescript/lib/module/Group/components/GroupPlayerActionForm.d.ts +9 -0
- package/lib/typescript/lib/module/Group/components/GroupPlayerActionForm.d.ts.map +1 -0
- package/lib/typescript/lib/module/Group/components/ManageGroupForm.d.ts +10 -0
- package/lib/typescript/lib/module/Group/components/ManageGroupForm.d.ts.map +1 -0
- package/lib/typescript/lib/module/Group/index.d.ts +12 -0
- package/lib/typescript/lib/module/Group/index.d.ts.map +1 -0
- package/lib/typescript/lib/module/index.d.ts +2 -1
- package/lib/typescript/lib/module/index.d.ts.map +1 -1
- package/lib/typescript/src/Engage/components/CompetitionCard.d.ts +5 -2
- package/lib/typescript/src/Engage/components/CompetitionCard.d.ts.map +1 -1
- package/lib/typescript/src/Group/api/index.d.ts +47 -0
- package/lib/typescript/src/Group/api/index.d.ts.map +1 -0
- package/lib/typescript/src/Group/components/GroupCTAButton.d.ts +13 -0
- package/lib/typescript/src/Group/components/GroupCTAButton.d.ts.map +1 -0
- package/lib/typescript/src/Group/components/GroupPlayerActionForm.d.ts +12 -0
- package/lib/typescript/src/Group/components/GroupPlayerActionForm.d.ts.map +1 -0
- package/lib/typescript/src/Group/components/ManageGroupForm.d.ts +12 -0
- package/lib/typescript/src/Group/components/ManageGroupForm.d.ts.map +1 -0
- package/lib/typescript/src/Group/index.d.ts +14 -0
- package/lib/typescript/src/Group/index.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +2 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Engage/components/CompetitionCard.tsx +29 -2
- package/src/Group/api/index.ts +176 -0
- package/src/Group/components/GroupCTAButton.tsx +57 -0
- package/src/Group/components/GroupPlayerActionForm.tsx +137 -0
- package/src/Group/components/ManageGroupForm.tsx +239 -0
- package/src/Group/index.tsx +497 -0
- package/src/index.tsx +2 -0
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Image } from 'react-native';
|
|
3
|
-
import type { CompanyProps, CompetitionProps, CompetitionResultTypeProps, CompetitionTypeProps, PublicPlayerProps } from '../../types';
|
|
3
|
+
import type { CompanyProps, CompetitionProps, CompetitionRecordProps, CompetitionResultProps, CompetitionResultTypeProps, CompetitionTypeProps, MyPlayerProps, PublicPlayerProps } from '../../types';
|
|
4
4
|
import { Icons } from '../../Components';
|
|
5
5
|
import moment from 'moment-mini';
|
|
6
6
|
import { useColors } from '../../constants/useColors';
|
|
7
7
|
import { Button, Text, View } from '../../Components/Themed';
|
|
8
|
+
import { CompetitionHelpers } from '../../Competition/api';
|
|
8
9
|
|
|
9
10
|
type CompetitionCardProps = {
|
|
10
11
|
competition:CompetitionProps,
|
|
12
|
+
player?:MyPlayerProps,
|
|
11
13
|
competition_type:CompetitionTypeProps,
|
|
14
|
+
competition_result?:CompetitionResultProps,
|
|
15
|
+
competition_record?:CompetitionRecordProps,
|
|
12
16
|
competition_result_type:CompetitionResultTypeProps,
|
|
13
17
|
company?:CompanyProps,
|
|
14
18
|
admin?:PublicPlayerProps,
|
|
15
19
|
pacer?:PublicPlayerProps,
|
|
16
20
|
onCompetitionSelect:(c:CompetitionProps) => void
|
|
17
21
|
}
|
|
18
|
-
const CompetitionCard = ({ competition, competition_type, company, admin, onCompetitionSelect }:CompetitionCardProps) => {
|
|
22
|
+
const CompetitionCard = ({ competition, competition_record, player, competition_result, competition_type, company, admin, onCompetitionSelect }:CompetitionCardProps) => {
|
|
19
23
|
const Colors = useColors();
|
|
20
24
|
const cl = competition.market_type == 'FOR_MONEY' ? '$' : 'E'
|
|
21
25
|
let current_payout = competition.ticket_revenue
|
|
@@ -79,6 +83,29 @@ const CompetitionCard = ({ competition, competition_type, company, admin, onComp
|
|
|
79
83
|
</View>
|
|
80
84
|
</View>
|
|
81
85
|
</View>
|
|
86
|
+
{player && competition_result && competition_record ?
|
|
87
|
+
<View type='footer' style={{ padding:10, flexDirection:'row', alignItems:'center', borderBottomWidth:1, borderColor:Colors.borders.light }}>
|
|
88
|
+
<Image
|
|
89
|
+
source={{ uri: player.profile_pic }}
|
|
90
|
+
style={{ height:30, width:30, borderRadius:100 }}
|
|
91
|
+
resizeMode='contain'
|
|
92
|
+
/>
|
|
93
|
+
<View transparent style={{ flex:1, marginLeft:10 }}>
|
|
94
|
+
<Text theme='h1'>@{player.username}</Text>
|
|
95
|
+
<View transparent style={{ marginTop:3 }}>
|
|
96
|
+
{competition_type.type == 'pick' ?
|
|
97
|
+
<Text theme="description">{competition_record.wins} - {competition_record.losses} - {competition_record.draws} ({competition_record.remaining_picks} Remaining)</Text>
|
|
98
|
+
:competition_type.type == 'wager' ?
|
|
99
|
+
<Text theme="description">{competition_record.earnings.toFixed(2)} Earned ({competition_record.remaining_stakes.toFixed(2)} at risk)</Text>
|
|
100
|
+
:<></>}
|
|
101
|
+
</View>
|
|
102
|
+
</View>
|
|
103
|
+
<View transparent style={{ alignItems:'flex-end' }}>
|
|
104
|
+
<Text theme='h2' color={competition_result.winnings > 0 ? Colors.text.success : Colors.text.warning}>{cl}{competition_result.winnings.toFixed(2)}</Text>
|
|
105
|
+
<Text theme='description' style={{ marginTop:3 }}>{CompetitionHelpers.formatPlace(competition_result.place)} / {competition.tickets_sold}</Text>
|
|
106
|
+
</View>
|
|
107
|
+
</View>
|
|
108
|
+
:<></>}
|
|
82
109
|
<View type='footer' style={{ flexDirection:'row', alignItems:'center', padding:10, borderBottomRightRadius:8, borderBottomLeftRadius:8 }}>
|
|
83
110
|
{company ?
|
|
84
111
|
<Image
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { APIOverrides } from "../../ApiOverrides"
|
|
3
|
+
import type { CompetitionPayoutTypeProps, CompetitionPlayerProps, CompetitionProps, CompetitionRecordProps, CompetitionResultProps, CompetitionResultTypeProps, CompetitionTypeProps, GroupMessageProps, GroupPlayerProps, GroupProps, NewOverallAnalytics, OrderAnalyticsProps, OrderProps, PostProps, PublicPlayerProps } from "../../types";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
//let EVENT_SVC_API = ''
|
|
7
|
+
let AUTH_SVC_API = ''
|
|
8
|
+
let MK_SVC_API = ''
|
|
9
|
+
let SOCIAL_SVC_API = ''
|
|
10
|
+
let TP_SVC_API = ''
|
|
11
|
+
|
|
12
|
+
export { GroupApi, GroupHelpers }
|
|
13
|
+
|
|
14
|
+
const GroupApi = {
|
|
15
|
+
setEnvironment: () => {
|
|
16
|
+
const endpoints = APIOverrides.getEndpoints();
|
|
17
|
+
//EVENT_SVC_API = endpoints['EVENT_SVC_API'] as string;
|
|
18
|
+
MK_SVC_API = endpoints['MK_SVC_API'] as string;
|
|
19
|
+
TP_SVC_API = endpoints['TP_SVC_API'] as string;
|
|
20
|
+
AUTH_SVC_API = endpoints['AUTH_SVC_API'] as string;
|
|
21
|
+
SOCIAL_SVC_API = endpoints['SOCIAL_SVC_API'] as string;
|
|
22
|
+
},
|
|
23
|
+
getGroupById: async(group_id:string):Promise<undefined|{ group:GroupProps, group_messages:GroupMessageProps[], group_players:GroupPlayerProps[], my_group_player?:GroupPlayerProps }> => {
|
|
24
|
+
try {
|
|
25
|
+
const resp = await axios.get(`${SOCIAL_SVC_API}/v2/groups/group/${group_id}`);
|
|
26
|
+
return resp.data
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.log(e);
|
|
29
|
+
return undefined
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
acceptInvite:async(group_player_id:string):Promise<GroupPlayerProps | undefined> => {
|
|
33
|
+
try {
|
|
34
|
+
const resp = await axios.post(`${SOCIAL_SVC_API}/v2/groups/player/accept`, { group_player_id });
|
|
35
|
+
return resp.data.group_player
|
|
36
|
+
} catch (e) {
|
|
37
|
+
return undefined
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
declineInvite:async(group_player_id:string):Promise<GroupPlayerProps | undefined> => {
|
|
41
|
+
try {
|
|
42
|
+
const resp = await axios.post(`${SOCIAL_SVC_API}/v2/groups/player/decline`, { group_player_id });
|
|
43
|
+
return resp.data.group_player
|
|
44
|
+
} catch (e) {
|
|
45
|
+
return undefined
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
join:async(group_id:string):Promise<GroupPlayerProps | undefined> => {
|
|
49
|
+
try {
|
|
50
|
+
const resp = await axios.post(`${SOCIAL_SVC_API}/v2/groups/player/join`, { group_id });
|
|
51
|
+
return resp.data.group_player
|
|
52
|
+
} catch (e) {
|
|
53
|
+
return undefined
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
leave:async(group_player_id:string):Promise<GroupPlayerProps | undefined> => {
|
|
57
|
+
try {
|
|
58
|
+
const resp = await axios.post(`${SOCIAL_SVC_API}/v2/groups/player/leave`, { group_player_id });
|
|
59
|
+
return resp.data.group_player
|
|
60
|
+
} catch (e) {
|
|
61
|
+
return undefined
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
updateGroup: async(group:GroupProps):Promise<GroupProps|undefined> => {
|
|
65
|
+
try {
|
|
66
|
+
const resp = await axios.post(`${SOCIAL_SVC_API}/v2/groups/group/update`, {group});
|
|
67
|
+
return resp.data.group
|
|
68
|
+
} catch (e) {
|
|
69
|
+
console.log(e);
|
|
70
|
+
return undefined
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
getPlayersByIds: async(player_ids:string[]):Promise<PublicPlayerProps[]> => {
|
|
74
|
+
try {
|
|
75
|
+
if(player_ids.length == 0){ return [] }
|
|
76
|
+
const resp = await axios.post(`${AUTH_SVC_API}/v1/players/bulk/get`, { player_ids });
|
|
77
|
+
return resp.data.players
|
|
78
|
+
} catch (e) {
|
|
79
|
+
return []
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
getGroupAnalytics: async(group_id:string, to:number, from:number):Promise<OrderAnalyticsProps[]> => {
|
|
83
|
+
try {
|
|
84
|
+
const resp = await axios.get(`${MK_SVC_API}/v1/analytics/group/details/${group_id}?to=${to}&from=${from}`);
|
|
85
|
+
console.log(resp.data)
|
|
86
|
+
return resp.data.analytics
|
|
87
|
+
} catch (e) {
|
|
88
|
+
return []
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
getCompetitionOptions: async():Promise<{competition_types:CompetitionTypeProps[], competition_result_types:CompetitionResultTypeProps[], competition_payout_types:CompetitionPayoutTypeProps[]}> => {
|
|
92
|
+
const resp = await axios.get(`${TP_SVC_API}/v1/competitions/options`)
|
|
93
|
+
return resp.data
|
|
94
|
+
},
|
|
95
|
+
getActiveCompetitions: async(group_id:string):Promise<{ competitions:CompetitionProps[], competition_players:CompetitionPlayerProps[], competition_records:CompetitionRecordProps[], competition_results:CompetitionResultProps[] }> => {
|
|
96
|
+
try {
|
|
97
|
+
const resp = await axios.get(`${TP_SVC_API}/v2/competitions/group/active/${group_id}`);
|
|
98
|
+
return resp.data
|
|
99
|
+
} catch (e) {
|
|
100
|
+
console.log(e);
|
|
101
|
+
return { competition_players:[], competition_records:[], competition_results:[], competitions:[] }
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
getHistoryCompetitions: async(group_id:string, offset:number):Promise<{ competitions:CompetitionProps[], competition_players:CompetitionPlayerProps[], competition_records:CompetitionRecordProps[], competition_results:CompetitionResultProps[] }> => {
|
|
105
|
+
try {
|
|
106
|
+
const resp = await axios.get(`${TP_SVC_API}/v2/competitions/group/history/${group_id}?offset=${offset}`);
|
|
107
|
+
return resp.data
|
|
108
|
+
} catch (e) {
|
|
109
|
+
console.log(e);
|
|
110
|
+
return { competition_players:[], competition_records:[], competition_results:[], competitions:[] }
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
getPostsByGroupId: async(group_id:string, offset:number):Promise<PostProps[]> => {
|
|
114
|
+
try {
|
|
115
|
+
const resp = await axios.get(`${SOCIAL_SVC_API}/v1/posts/group/${group_id}?offset=${offset}`);
|
|
116
|
+
return resp.data.posts
|
|
117
|
+
} catch (e) {
|
|
118
|
+
console.log(e)
|
|
119
|
+
return []
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
getBulkOrders: async(order_ids:string[]):Promise<OrderProps[]> => {
|
|
123
|
+
try {
|
|
124
|
+
const resp = await axios.post(`${MK_SVC_API}/v1/orders/bulk/get`, { order_ids })
|
|
125
|
+
return resp.data.orders
|
|
126
|
+
} catch (e) {
|
|
127
|
+
console.log(e);
|
|
128
|
+
return []
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
const GroupHelpers = {
|
|
135
|
+
sortMembers: (group_players:GroupPlayerProps[], order_analytics:OrderAnalyticsProps[]) => {
|
|
136
|
+
let player_analytics: { [key:string]: NewOverallAnalytics } = {}
|
|
137
|
+
group_players.map(p => {
|
|
138
|
+
let my_analytics = order_analytics.filter(oa => oa.player_id == p.player_id);
|
|
139
|
+
player_analytics[p.player_id] = GroupHelpers.aggregateAnalytics(my_analytics);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
let sorted_players = group_players.filter(gp => gp.status == 'active').sort((a,b) => {
|
|
143
|
+
let a_analytics = player_analytics[a.player_id]?.roi_pct ?? 0
|
|
144
|
+
let b_analytcs = player_analytics[b.player_id]?.roi_pct ?? 0
|
|
145
|
+
return b_analytcs - a_analytics
|
|
146
|
+
});
|
|
147
|
+
return { sorted_players, player_analytics }
|
|
148
|
+
},
|
|
149
|
+
aggregateAnalytics: (analytics:OrderAnalyticsProps[]):NewOverallAnalytics => {
|
|
150
|
+
const wins = analytics.reduce((a,b) => a + b.wins, 0);
|
|
151
|
+
const losses = analytics.reduce((a,b) => a + b.losses, 0);
|
|
152
|
+
const draws = analytics.reduce((a,b) => a + b.draws, 0);
|
|
153
|
+
const fulfilled_positions = analytics.reduce((a,b) => a + parseFloat(b.fulfilled_positions as any), 0);
|
|
154
|
+
const winnings = analytics.reduce((a,b) => a + b.winnings, 0);
|
|
155
|
+
const original_stake = analytics.reduce((a,b) => a + b.original_stake, 0);
|
|
156
|
+
const cash_rcvd = analytics.reduce((a,b) => a + b.cash_rcvd, 0);
|
|
157
|
+
|
|
158
|
+
const win_pct = (wins + (draws / 2)) / fulfilled_positions
|
|
159
|
+
const earnings = (winnings + cash_rcvd) - original_stake
|
|
160
|
+
const roi_pct = original_stake > 0 ? earnings / original_stake : 0
|
|
161
|
+
return {
|
|
162
|
+
winnings,
|
|
163
|
+
original_stake,
|
|
164
|
+
wins,
|
|
165
|
+
losses,
|
|
166
|
+
draws,
|
|
167
|
+
net_winnings: 0,
|
|
168
|
+
player_id: '',
|
|
169
|
+
fulfilled_positions,
|
|
170
|
+
cash_rcvd,
|
|
171
|
+
earnings,
|
|
172
|
+
win_pct,
|
|
173
|
+
roi_pct
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import moment from "moment-mini"
|
|
3
|
+
import { useEffect } from "react"
|
|
4
|
+
import type { GroupMessageProps, GroupPlayerProps, GroupProps, PublicPlayerProps } from "../../types"
|
|
5
|
+
import { useColors } from "../../constants/useColors"
|
|
6
|
+
import { Button, Text, View } from "../../Components/Themed"
|
|
7
|
+
import { Icons } from '../../Components';
|
|
8
|
+
import { Image } from 'react-native';
|
|
9
|
+
|
|
10
|
+
type GroupCTAButtonProps = {
|
|
11
|
+
group:GroupProps,
|
|
12
|
+
message_length?:number,
|
|
13
|
+
group_messages:GroupMessageProps[],
|
|
14
|
+
players:PublicPlayerProps[],
|
|
15
|
+
group_players:GroupPlayerProps[],
|
|
16
|
+
onSelectChat:(group:GroupProps) => void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const GroupCTAButton = ({ group, players, message_length, group_messages, onSelectChat }:GroupCTAButtonProps) => {
|
|
20
|
+
const Colors = useColors();
|
|
21
|
+
|
|
22
|
+
useEffect(( ) => {
|
|
23
|
+
if(!group){ return }
|
|
24
|
+
//setUpCta();
|
|
25
|
+
},[group.group_id]);
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
let last_message = group_messages.sort((a,b) => moment(b.create_datetime).unix() - moment(a.create_datetime).unix())[0]
|
|
29
|
+
let cta_message = group.name
|
|
30
|
+
if(last_message?.message){ cta_message = `${last_message.message.slice(0, message_length ?? 15)}...` }
|
|
31
|
+
const last_player = players.find(p => p.player_id == last_message?.player_id)
|
|
32
|
+
return (
|
|
33
|
+
<View transparent>
|
|
34
|
+
<Button transparent style={{ flexDirection:'row', alignItems:'center', padding:2 }} onPress={() => onSelectChat(group)}>
|
|
35
|
+
{last_player ?
|
|
36
|
+
<Image
|
|
37
|
+
source={{ uri: last_player.profile_pic }}
|
|
38
|
+
style={{ height:30, width:30, borderRadius:100 }}
|
|
39
|
+
resizeMode='contain'
|
|
40
|
+
/>
|
|
41
|
+
:<></>}
|
|
42
|
+
<View transparent style={{ flex:1, marginLeft:10, marginRight:10 }}>
|
|
43
|
+
<Text theme='h2'>{cta_message}</Text>
|
|
44
|
+
{last_player ?
|
|
45
|
+
<Text theme='description' style={{ marginTop:3 }}>@{last_player.username}</Text>
|
|
46
|
+
:<></>}
|
|
47
|
+
</View>
|
|
48
|
+
<View float style={{ padding:10, flexDirection:'row', alignItems:'center' }}>
|
|
49
|
+
<Icons.ChatIcon size={16} color={Colors.text.h1}/>
|
|
50
|
+
<Text theme='h2' size={12}> Chat</Text>
|
|
51
|
+
</View>
|
|
52
|
+
</Button>
|
|
53
|
+
</View>
|
|
54
|
+
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
export default GroupCTAButton
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Button, Text, View } from "../../Components/Themed"
|
|
3
|
+
import type { GroupPlayerProps, GroupProps, MyPlayerProps } from '../../types';
|
|
4
|
+
import { GroupApi } from '../api';
|
|
5
|
+
|
|
6
|
+
type GroupPlayerActionFormProps = {
|
|
7
|
+
me:MyPlayerProps,
|
|
8
|
+
group:GroupProps,
|
|
9
|
+
group_player?:GroupPlayerProps,
|
|
10
|
+
onResponse:(gp:GroupPlayerProps) => void,
|
|
11
|
+
onClose:() => void
|
|
12
|
+
}
|
|
13
|
+
const GroupPlayerActionForm = ({ group, group_player, onResponse, onClose }:GroupPlayerActionFormProps) => {
|
|
14
|
+
const [ action_loading, setActionLoading ] = useState(false);
|
|
15
|
+
|
|
16
|
+
const handleAccept = async() => {
|
|
17
|
+
if(!group_player){ return }
|
|
18
|
+
setActionLoading(true)
|
|
19
|
+
const new_gp = await GroupApi.acceptInvite(group_player.group_player_id);
|
|
20
|
+
if(!new_gp){ alert('Unable to process') }
|
|
21
|
+
else {
|
|
22
|
+
onResponse(new_gp);
|
|
23
|
+
}
|
|
24
|
+
setActionLoading(false)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const handleDecline = async() => {
|
|
28
|
+
if(!group_player){ return }
|
|
29
|
+
setActionLoading(true)
|
|
30
|
+
const new_gp = await GroupApi.declineInvite(group_player.group_player_id);
|
|
31
|
+
if(!new_gp){ alert('Unable to process') }
|
|
32
|
+
else {
|
|
33
|
+
onResponse(new_gp);
|
|
34
|
+
}
|
|
35
|
+
setActionLoading(false)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const handleJoin= async() => {
|
|
39
|
+
setActionLoading(true)
|
|
40
|
+
const new_gp = await GroupApi.join(group.group_id);
|
|
41
|
+
if(!new_gp){ alert('Unable to process') }
|
|
42
|
+
else {
|
|
43
|
+
onResponse(new_gp);
|
|
44
|
+
}
|
|
45
|
+
setActionLoading(false)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const handleLeave = async() => {
|
|
49
|
+
if(!group_player){ return }
|
|
50
|
+
setActionLoading(true)
|
|
51
|
+
const new_gp = await GroupApi.leave(group_player.group_player_id);
|
|
52
|
+
if(!new_gp){ alert('Unable to process') }
|
|
53
|
+
else {
|
|
54
|
+
onResponse(new_gp);
|
|
55
|
+
}
|
|
56
|
+
setActionLoading(false)
|
|
57
|
+
}
|
|
58
|
+
return (
|
|
59
|
+
<View float>
|
|
60
|
+
<View type='header' style={{ flexDirection:'row', alignItems:'center', padding:10, borderTopRightRadius:8, borderTopLeftRadius:8 }}>
|
|
61
|
+
<View transparent style={{ flex:1 }}>
|
|
62
|
+
<Text theme='h1'>{group.name}</Text>
|
|
63
|
+
<Text theme='description' style={{ marginTop:3 }}>{group.description}</Text>
|
|
64
|
+
</View>
|
|
65
|
+
<Button
|
|
66
|
+
title='X'
|
|
67
|
+
float
|
|
68
|
+
style={{ padding:10 }}
|
|
69
|
+
onPress={() => onClose()}
|
|
70
|
+
/>
|
|
71
|
+
</View>
|
|
72
|
+
<View type='body' style={{ padding:10 }}>
|
|
73
|
+
{group_player ?
|
|
74
|
+
<View>
|
|
75
|
+
{group_player.status == 'invited' ?
|
|
76
|
+
<Text theme='h1'>YOU HAVE BEEN INVITED</Text>
|
|
77
|
+
:<></>}
|
|
78
|
+
{group_player.status == 'active' ?
|
|
79
|
+
<Text theme='h1'>YOU ARE A MEMBER OF THIS GROUP</Text>
|
|
80
|
+
:<></>}
|
|
81
|
+
{group_player.status == 'inactive' ?
|
|
82
|
+
<Text theme='h1'>JOIN THIS GROUP NOW</Text>
|
|
83
|
+
:<></>}
|
|
84
|
+
</View>
|
|
85
|
+
:
|
|
86
|
+
<View>
|
|
87
|
+
<Text theme='h1'>JOIN THIS GROUP NOW</Text>
|
|
88
|
+
</View>
|
|
89
|
+
}
|
|
90
|
+
</View>
|
|
91
|
+
<View type='footer' style={{ flexDirection:'row', alignItems:'center', padding:5, borderBottomRightRadius:8, borderBottomLeftRadius:8 }}>
|
|
92
|
+
{group_player?.status == 'invited' ?
|
|
93
|
+
<Button
|
|
94
|
+
title='DECLINE'
|
|
95
|
+
type='error'
|
|
96
|
+
loading={action_loading}
|
|
97
|
+
style={{ flex:1, opacity: action_loading ? 0.5:1, margin:5 }}
|
|
98
|
+
disabled={action_loading}
|
|
99
|
+
onPress={() => handleDecline()}
|
|
100
|
+
/>
|
|
101
|
+
:<></>}
|
|
102
|
+
{group_player?.status == 'invited' ?
|
|
103
|
+
<Button
|
|
104
|
+
title='ACCEPT'
|
|
105
|
+
type='success'
|
|
106
|
+
loading={action_loading}
|
|
107
|
+
style={{ flex:1, opacity: action_loading ? 0.5:1, margin:5 }}
|
|
108
|
+
disabled={action_loading}
|
|
109
|
+
onPress={() => handleAccept()}
|
|
110
|
+
/>
|
|
111
|
+
:<></>}
|
|
112
|
+
{group_player?.status == 'active' ?
|
|
113
|
+
<Button
|
|
114
|
+
title='LEAVE GROUP'
|
|
115
|
+
type='error'
|
|
116
|
+
loading={action_loading}
|
|
117
|
+
style={{ flex:1, opacity: action_loading ? 0.5:1, margin:5 }}
|
|
118
|
+
disabled={action_loading}
|
|
119
|
+
onPress={() => handleLeave()}
|
|
120
|
+
/>
|
|
121
|
+
:<></>}
|
|
122
|
+
{!group_player || group_player.status == 'inactive' ?
|
|
123
|
+
<Button
|
|
124
|
+
title='JOIN GROUP'
|
|
125
|
+
type='success'
|
|
126
|
+
loading={action_loading}
|
|
127
|
+
style={{ flex:1, opacity: action_loading ? 0.5:1, margin:5 }}
|
|
128
|
+
disabled={action_loading}
|
|
129
|
+
onPress={() => handleJoin()}
|
|
130
|
+
/>
|
|
131
|
+
:<></>}
|
|
132
|
+
</View>
|
|
133
|
+
</View>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export default GroupPlayerActionForm
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { Button, Text, TextInput, View } from "../../Components/Themed";
|
|
3
|
+
import { FlatList } from 'react-native';
|
|
4
|
+
import type { FocusPositionProps, GroupProps } from '../../types';
|
|
5
|
+
import { Switch, Toggle } from '../../Components';
|
|
6
|
+
import { GroupApi } from '../api';
|
|
7
|
+
|
|
8
|
+
const sections = ['header','toggle','information', 'settings', 'invite', 'options']
|
|
9
|
+
type ManageGroupFormProps = {
|
|
10
|
+
group:GroupProps,
|
|
11
|
+
onUpdateGroup:(group:GroupProps) => void,
|
|
12
|
+
onInvitePlayer: () => void,
|
|
13
|
+
onClose:() => void,
|
|
14
|
+
onFocusPosition?:(position:FocusPositionProps) => void,
|
|
15
|
+
}
|
|
16
|
+
const ManageGroupForm = ({ group, onFocusPosition, onUpdateGroup, onClose, onInvitePlayer }: ManageGroupFormProps ) => {
|
|
17
|
+
const [ manage_state, setState ] = useState<{
|
|
18
|
+
loading:boolean,
|
|
19
|
+
draft_group:GroupProps,
|
|
20
|
+
active_toggle:string
|
|
21
|
+
}>({
|
|
22
|
+
draft_group: group,
|
|
23
|
+
loading:false,
|
|
24
|
+
active_toggle: 'information'
|
|
25
|
+
});
|
|
26
|
+
const { loading, draft_group, active_toggle } = manage_state;
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if(!group){ return }
|
|
30
|
+
setState({ ...manage_state,draft_group: group })
|
|
31
|
+
},[group]);
|
|
32
|
+
|
|
33
|
+
const handleSave = async(dg:GroupProps) => {
|
|
34
|
+
if(!dg){ return }
|
|
35
|
+
if(loading){ return }
|
|
36
|
+
console.log(dg)
|
|
37
|
+
setState({ ...manage_state, loading: true });
|
|
38
|
+
const new_group = await GroupApi.updateGroup(dg);
|
|
39
|
+
if(!new_group){
|
|
40
|
+
setState({ ...manage_state, loading:false })
|
|
41
|
+
return alert('Unable to update this group')
|
|
42
|
+
}
|
|
43
|
+
onUpdateGroup(new_group);
|
|
44
|
+
setState({ ...manage_state, loading:false })
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const renderSections = (data:{ item:string, index:number }) => {
|
|
48
|
+
switch(data.item){
|
|
49
|
+
case 'header':
|
|
50
|
+
return (
|
|
51
|
+
<View type='header' style={{ flexDirection:'row', alignItems:'center', padding:10, borderTopRightRadius:8, borderTopLeftRadius:8 }}>
|
|
52
|
+
<View transparent style={{ flex:1 }}>
|
|
53
|
+
<Text theme='h1'>EDIT YOUR GROUP</Text>
|
|
54
|
+
<Text theme='description' style={{ marginTop:3 }}>Use the form below to make updates to this group</Text>
|
|
55
|
+
</View>
|
|
56
|
+
<Button
|
|
57
|
+
title='X'
|
|
58
|
+
float
|
|
59
|
+
style={{ padding:10 }}
|
|
60
|
+
onPress={() => onClose()}
|
|
61
|
+
/>
|
|
62
|
+
</View>
|
|
63
|
+
)
|
|
64
|
+
case 'information':
|
|
65
|
+
if(!draft_group){ return <></> }
|
|
66
|
+
if(active_toggle != 'information'){ return <></> }
|
|
67
|
+
const is_changed = JSON.stringify({ name: draft_group.name, description: draft_group.description }) != JSON.stringify({ name: group.name, description:group.description }) ? true : false
|
|
68
|
+
return (
|
|
69
|
+
<View float style={{ margin:10 }}>
|
|
70
|
+
<View type='header' style={{ flexDirection:'row', alignItems:'center', padding:10 }}>
|
|
71
|
+
<View transparent style={{ flex:1 }}>
|
|
72
|
+
<Text theme='h1'>Edit Group Information</Text>
|
|
73
|
+
</View>
|
|
74
|
+
<Button
|
|
75
|
+
title='UPDATE'
|
|
76
|
+
type='success'
|
|
77
|
+
disabled={!is_changed}
|
|
78
|
+
loading={loading}
|
|
79
|
+
style={{ opacity: is_changed && !loading ? 1 : 0.5, padding:10 }}
|
|
80
|
+
onPress={() => handleSave(draft_group)}
|
|
81
|
+
/>
|
|
82
|
+
</View>
|
|
83
|
+
<View transparent nativeID='title' type='row' style={{ flexWrap:"wrap", padding:10 }}>
|
|
84
|
+
<View transparent style={{ flexGrow:1, minWidth:150 }}>
|
|
85
|
+
<Text theme='h1'>Group Name</Text>
|
|
86
|
+
<Text theme='description' style={{ marginTop:3 }}>Give this group a unique name</Text>
|
|
87
|
+
</View>
|
|
88
|
+
<TextInput
|
|
89
|
+
value={draft_group.name}
|
|
90
|
+
style={{ minWidth:150, flexGrow:1, margin:5 }}
|
|
91
|
+
onFocusPosition={onFocusPosition}
|
|
92
|
+
onChangeText={(text) => setState({ ...manage_state, draft_group: { ...draft_group, name: text } })}
|
|
93
|
+
/>
|
|
94
|
+
</View>
|
|
95
|
+
<View transparent nativeID='description' type='row' style={{ flexWrap:"wrap", padding:10 }}>
|
|
96
|
+
<View transparent style={{ flexGrow:1, minWidth:150 }}>
|
|
97
|
+
<Text theme='h1'>Group Description</Text>
|
|
98
|
+
<Text theme='description' style={{ marginTop:3 }}>Give this group a fun description</Text>
|
|
99
|
+
</View>
|
|
100
|
+
<TextInput
|
|
101
|
+
value={draft_group.description}
|
|
102
|
+
style={{ minWidth:300, flexGrow:1, margin:5 }}
|
|
103
|
+
onFocusPosition={onFocusPosition}
|
|
104
|
+
onChangeText={(text) => setState({ ...manage_state, draft_group: { ...draft_group, description: text } })}
|
|
105
|
+
/>
|
|
106
|
+
</View>
|
|
107
|
+
</View>
|
|
108
|
+
)
|
|
109
|
+
case 'invite':
|
|
110
|
+
if(!draft_group){ return <></> }
|
|
111
|
+
if(active_toggle != 'information'){ return <></> }
|
|
112
|
+
const code_changed = draft_group.invite_code != group.invite_code ? true : false
|
|
113
|
+
return (
|
|
114
|
+
<View float style={{ margin:10 }}>
|
|
115
|
+
<View type='header' style={{ flexDirection:'row', alignItems:'center', padding:10 }}>
|
|
116
|
+
<View transparent style={{ flex:1 }}>
|
|
117
|
+
<Text theme='h1'>Group Players</Text>
|
|
118
|
+
</View>
|
|
119
|
+
<Button
|
|
120
|
+
title='INVITE'
|
|
121
|
+
type='success'
|
|
122
|
+
loading={loading}
|
|
123
|
+
style={{ padding:10 }}
|
|
124
|
+
onPress={() => onInvitePlayer()}
|
|
125
|
+
/>
|
|
126
|
+
</View>
|
|
127
|
+
<View transparent type='body'>
|
|
128
|
+
<View transparent type='row' style={{ padding:10 }}>
|
|
129
|
+
<View transparent style={{flex:1 }}>
|
|
130
|
+
<Text theme='h1'>INVITE ONLY</Text>
|
|
131
|
+
<Text theme='description' style={{ marginTop:3 }}>Make this group invite only so players can only join if invited by you</Text>
|
|
132
|
+
</View>
|
|
133
|
+
<Switch
|
|
134
|
+
value={draft_group.invite_only}
|
|
135
|
+
onChange={(value) => handleSave({ ...draft_group, invite_only: value, invite_code: value ? `IC${group.group_id}`: '' }) }
|
|
136
|
+
switch_type='on_off'
|
|
137
|
+
/>
|
|
138
|
+
</View>
|
|
139
|
+
{draft_group.invite_only ?
|
|
140
|
+
<View transparent nativeID='title' type='row' style={{ flexWrap:"wrap" }}>
|
|
141
|
+
<View transparent style={{ flexGrow:1, minWidth:150, padding:10 }}>
|
|
142
|
+
<Text theme='h1'>INVITE CODE</Text>
|
|
143
|
+
<Text theme='description' style={{ marginTop:3 }}>You can set a custom code for users to find your group</Text>
|
|
144
|
+
</View>
|
|
145
|
+
<View transparent style={{ flexDirection:'row', alignItems:'center', minWidth:200, flexGrow:1, padding:10 }}>
|
|
146
|
+
<TextInput
|
|
147
|
+
value={draft_group.invite_code}
|
|
148
|
+
style={{ flexGrow:1, marginRight:5 }}
|
|
149
|
+
onFocusPosition={onFocusPosition}
|
|
150
|
+
onChangeText={(text) => setState({ ...manage_state, draft_group: { ...draft_group, invite_code: text } })}
|
|
151
|
+
/>
|
|
152
|
+
<Button
|
|
153
|
+
title='SAVE'
|
|
154
|
+
type='success'
|
|
155
|
+
disabled={!code_changed}
|
|
156
|
+
loading={loading}
|
|
157
|
+
style={{ opacity: code_changed && !loading ? 1 : 0.5, padding:10 }}
|
|
158
|
+
onPress={() => handleSave(draft_group)}
|
|
159
|
+
/>
|
|
160
|
+
</View>
|
|
161
|
+
</View>
|
|
162
|
+
:<></>}
|
|
163
|
+
</View>
|
|
164
|
+
</View>
|
|
165
|
+
)
|
|
166
|
+
case 'toggle':
|
|
167
|
+
return (
|
|
168
|
+
<View style={{ padding:10 }}>
|
|
169
|
+
<Toggle
|
|
170
|
+
options={[
|
|
171
|
+
{key: 'information', label: 'Information'},
|
|
172
|
+
{ key: 'settings', label: 'settings'}
|
|
173
|
+
]}
|
|
174
|
+
onSelectOption={(option) => setState({ ...manage_state, active_toggle: option })}
|
|
175
|
+
selected_option={active_toggle}
|
|
176
|
+
/>
|
|
177
|
+
</View>
|
|
178
|
+
)
|
|
179
|
+
case 'settings':
|
|
180
|
+
if(active_toggle != 'settings'){ return <></> }
|
|
181
|
+
return (
|
|
182
|
+
<View float style={{ margin:10 }}>
|
|
183
|
+
<View type='header' style={{ flexDirection:'row', alignItems:'center', padding:10, borderTopRightRadius:8, borderTopLeftRadius:8 }}>
|
|
184
|
+
<View transparent style={{ flex:1 }}>
|
|
185
|
+
<Text theme='h1'>Edit Group Settings</Text>
|
|
186
|
+
</View>
|
|
187
|
+
</View>
|
|
188
|
+
<View transparent nativeID='title' type='row' style={{ padding:10 }}>
|
|
189
|
+
<View transparent style={{ flexGrow:1, minWidth:150 }}>
|
|
190
|
+
<Text theme='h1'>Show Leaderboard</Text>
|
|
191
|
+
<Text theme='description' style={{ marginTop:3 }}>Include a leaderboard for all players in this group</Text>
|
|
192
|
+
</View>
|
|
193
|
+
<Switch
|
|
194
|
+
value={draft_group.leaderboard_ind}
|
|
195
|
+
onChange={(value) => handleSave({ ...draft_group, leaderboard_ind: value }) }
|
|
196
|
+
switch_type='on_off'
|
|
197
|
+
/>
|
|
198
|
+
</View>
|
|
199
|
+
<View transparent nativeID='title' type='row' style={{ padding:10 }}>
|
|
200
|
+
<View transparent style={{ flexGrow:1, minWidth:150 }}>
|
|
201
|
+
<Text theme='h1'>Order Alerts</Text>
|
|
202
|
+
<Text theme='description' style={{ marginTop:3 }}>Log each order a player in this group makes.</Text>
|
|
203
|
+
</View>
|
|
204
|
+
<Switch
|
|
205
|
+
value={draft_group.order_alerts}
|
|
206
|
+
onChange={(value) => handleSave({ ...draft_group, order_alerts: value }) }
|
|
207
|
+
switch_type='on_off'
|
|
208
|
+
/>
|
|
209
|
+
</View>
|
|
210
|
+
<View transparent nativeID='title' type='row' style={{ padding:10 }}>
|
|
211
|
+
<View transparent style={{ flexGrow:1, minWidth:150 }}>
|
|
212
|
+
<Text theme='h1'>Competition Alerts</Text>
|
|
213
|
+
<Text theme='description' style={{ marginTop:3 }}>Log each competition a player in this group joins.</Text>
|
|
214
|
+
</View>
|
|
215
|
+
<Switch
|
|
216
|
+
value={draft_group.competition_alerts}
|
|
217
|
+
onChange={(value) => handleSave({ ...draft_group, competition_alerts: value }) }
|
|
218
|
+
switch_type='on_off'
|
|
219
|
+
/>
|
|
220
|
+
</View>
|
|
221
|
+
</View>
|
|
222
|
+
)
|
|
223
|
+
default: return <></>
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<View float style={{ flex:1 }}>
|
|
229
|
+
<FlatList
|
|
230
|
+
data={sections}
|
|
231
|
+
key={'group_sections_manage'}
|
|
232
|
+
keyExtractor={item => item}
|
|
233
|
+
renderItem={renderSections}
|
|
234
|
+
/>
|
|
235
|
+
</View>
|
|
236
|
+
)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export default ManageGroupForm
|