be-components 1.1.8 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/lib/commonjs/Squares/api/index.js +604 -0
  2. package/lib/commonjs/Squares/api/index.js.map +1 -1
  3. package/lib/commonjs/Squares/components/BoardStats.js +0 -22
  4. package/lib/commonjs/Squares/components/BoardStats.js.map +1 -1
  5. package/lib/commonjs/Squares/components/MySquaresCard.js +11 -1
  6. package/lib/commonjs/Squares/components/MySquaresCard.js.map +1 -1
  7. package/lib/commonjs/Squares/components/MyStatsCard.js +338 -0
  8. package/lib/commonjs/Squares/components/MyStatsCard.js.map +1 -0
  9. package/lib/commonjs/Squares/index.js +25 -3
  10. package/lib/commonjs/Squares/index.js.map +1 -1
  11. package/lib/module/Squares/api/index.js +604 -0
  12. package/lib/module/Squares/api/index.js.map +1 -1
  13. package/lib/module/Squares/components/BoardStats.js +0 -22
  14. package/lib/module/Squares/components/BoardStats.js.map +1 -1
  15. package/lib/module/Squares/components/MySquaresCard.js +11 -1
  16. package/lib/module/Squares/components/MySquaresCard.js.map +1 -1
  17. package/lib/module/Squares/components/MyStatsCard.js +329 -0
  18. package/lib/module/Squares/components/MyStatsCard.js.map +1 -0
  19. package/lib/module/Squares/index.js +25 -3
  20. package/lib/module/Squares/index.js.map +1 -1
  21. package/lib/typescript/src/Squares/api/index.d.ts +10 -1
  22. package/lib/typescript/src/Squares/api/index.d.ts.map +1 -1
  23. package/lib/typescript/src/Squares/components/BoardStats.d.ts +1 -2
  24. package/lib/typescript/src/Squares/components/BoardStats.d.ts.map +1 -1
  25. package/lib/typescript/src/Squares/components/MySquaresCard.d.ts +3 -2
  26. package/lib/typescript/src/Squares/components/MySquaresCard.d.ts.map +1 -1
  27. package/lib/typescript/src/Squares/components/MyStatsCard.d.ts +18 -0
  28. package/lib/typescript/src/Squares/components/MyStatsCard.d.ts.map +1 -0
  29. package/lib/typescript/src/Squares/index.d.ts.map +1 -1
  30. package/package.json +1 -1
  31. package/src/Squares/api/index.ts +662 -2
  32. package/src/Squares/components/BoardStats.tsx +3 -11
  33. package/src/Squares/components/MySquaresCard.tsx +9 -2
  34. package/src/Squares/components/MyStatsCard.tsx +167 -0
  35. package/src/Squares/index.tsx +25 -4
  36. package/src/types.d.ts +5 -0
@@ -1,5 +1,5 @@
1
1
  import { View, TouchableOpacity, FlatList } from 'react-native';
2
- import type { PlayerSquareProps, SquareOfferProps, SquareProps } from '../../types';
2
+ import type { PlayerSquareProps, SquareOfferProps, SquareProps, SquareValueProps } from '../../types';
3
3
  import { view_styles } from '../../constants/styles';
4
4
  import { Button, Icons, Text } from '../../Components';
5
5
  import React, { useState } from 'react';
@@ -12,22 +12,29 @@ type MySquaresCardProps = {
12
12
  square_offers:SquareOfferProps[],
13
13
  away_abbr?:string,
14
14
  home_abbr?:string,
15
+ my_square_values:SquareValueProps[],
15
16
  comp_status: string,
16
17
  onSquareOffer: (square:SquareProps, action:'add'|'remove') => void
17
18
  }
18
19
 
19
- const MySquaresCard = ({ player_squares, squares, away_abbr, home_abbr, square_offers, comp_status, onSquareOffer }: MySquaresCardProps) => {
20
+ const MySquaresCard = ({ player_squares, squares, away_abbr, home_abbr, square_offers, my_square_values, comp_status, onSquareOffer }: MySquaresCardProps) => {
20
21
  const [ expanded, setExpanded ] = useState(false);
21
22
  const renderPlayerSquares = (data: { item:PlayerSquareProps, index: number }) => {
22
23
  const square = squares.find(s => s.sq_square_id == data.item.sq_square_id);
23
24
  if(!square){ return <></> }
24
25
  const square_offer = square_offers.find(so => so.sq_player_square_id == data.item.sq_player_square_id && so.status == 'offered');
26
+ const square_value = my_square_values.find(sv => sv.sq_square_id == data.item.sq_square_id);
25
27
  return (
26
28
  <View style={{ ...view_styles.body_row, borderBottomWidth:1, borderColor:Colors.shades.shade600 }}>
27
29
  <View style={{ flex:1 }}>
28
30
  <Text theme='header_2'>SQUARE: {home_abbr}: {square.square_score_x}, {away_abbr}: {square.square_score_y}</Text>
29
31
  <Text style={{ marginTop:3 }} theme='body_2'>${data.item.purchase_price.toFixed(2)}</Text>
30
32
  </View>
33
+ {square_value ?
34
+ <View style={{ paddingRight:20, paddingLeft:20 }}>
35
+ <Text size={14} color={square_value.expected_value > 0 ? Colors.utility.success : Colors.utility.error}>${square_value.expected_payout.toFixed(2)}</Text>
36
+ </View>
37
+ :<></>}
31
38
  {comp_status == 'in_progress' ?
32
39
  <View>
33
40
  {square_offer ?
@@ -0,0 +1,167 @@
1
+ import { View, TouchableOpacity, FlatList } from "react-native"
2
+ import { Button, Icons, Text } from "../../Components"
3
+ import { view_styles } from "../../constants/styles"
4
+ import Colors from "../../constants/colors"
5
+ import type { PlayerSquareProps, PublicPlayerProps, SquareProps, SquareResultProps, SquaresCompetitionProps, SquaresExpectedValueProps, SquareValueProps } from "../../types"
6
+ import React, { useState } from "react"
7
+ import moment from "moment-mini"
8
+
9
+ type MyStatsCardProps = {
10
+ player_id?:string,
11
+ squares:SquareProps[],
12
+ home_abbr?:string,
13
+ away_abbr?:string,
14
+ squares_expected_value: SquaresExpectedValueProps
15
+ players:PublicPlayerProps[],
16
+ squares_competition:SquaresCompetitionProps,
17
+ player_squares:PlayerSquareProps[],
18
+ onSquareBid:(square:SquareProps, action:'add'|'remove') => void,
19
+ player_square_history:PlayerSquareProps[],
20
+ square_results: SquareResultProps[]
21
+ }
22
+
23
+ const MyStatsCard = ({ player_id, players, squares_expected_value, away_abbr, home_abbr, squares_competition, player_squares, player_square_history, squares, square_results, onSquareBid}:MyStatsCardProps) => {
24
+ const [ expanded, setExpanded ] = useState(false);
25
+
26
+ const comp_started = moment(squares_competition.begin_datetime).isBefore(moment()) ? true : false
27
+
28
+ let total_payout = squares_competition.potential_winnings
29
+ if(squares_competition.guaranteed_payout && squares_competition.guaranteed_payout > total_payout){ total_payout = squares_competition.guaranteed_payout }
30
+ let active_ps = player_squares.filter(ps => ps.status == 'active');
31
+ const my_ps = active_ps.filter(ps => ps.player_id == player_id)
32
+ let my_outbid_squares = [ ...new Set(player_square_history.filter(psh => psh.status == 'inactive').map(ps => ps.sq_square_id)) ]
33
+ my_outbid_squares = my_outbid_squares.filter(id => !my_ps.map(ps => ps.sq_square_id.toString()).includes(id.toString()))
34
+ const me = players.find(p => p.player_id == player_id);
35
+ console.log(me?.type)
36
+ const my_ownership = my_ps.length / active_ps.length * 100
37
+ const money_in = my_ps.reduce((a,b) => a + b.purchase_price, 0);
38
+ const money_out = square_results.filter(sr => sr.sq_player_square_id && my_ps.map(mp => mp.sq_player_square_id.toString()).includes(sr.sq_player_square_id.toString())).reduce((a,b) => a + b.winnings, 0)
39
+ const earnings = money_out - money_in
40
+ let roi = 0
41
+ if(money_in > 0){
42
+ roi = earnings / money_in
43
+ }
44
+
45
+ const suggested_squares = squares_expected_value.other_square_values.filter(sv => sv.after_purchase_expected_value > 0).sort((a,b) => b.after_purchase_expected_value - a.after_purchase_expected_value).slice(0, 3)
46
+
47
+ const renderSuggestions = (data: { item:SquareValueProps, index:number }) => {
48
+ const square = squares.find(s => s.sq_square_id == data.item.sq_square_id);
49
+ if(!square){ return <></> }
50
+
51
+ return (
52
+ <View style={{ backgroundColor:Colors.shades.white, borderRadius:8, width:110, margin:3, ...view_styles.float }}>
53
+ <View style={{ flexDirection:'row', alignItems:'center', padding:5, borderBottomWidth:1, borderBottomColor:Colors.shades.shade600, borderTopRightRadius:8, borderTopLeftRadius:8 }}>
54
+ <View style={{flex:1}}>
55
+ <Icons.ChevronIcon direction="up" color={Colors.utility.success} size={8} />
56
+ </View>
57
+ <Text color={Colors.utility.success} weight='bold' size={14}>EV ${data.item.after_purchase_expected_payout.toFixed(2)}</Text>
58
+ </View>
59
+ <View style={{ padding:10, justifyContent:'center' }}>
60
+ <View style={{ flexDirection:'row', alignItems:'center' }}>
61
+ <Text style={{ flex:1 }} theme='body'>{home_abbr}</Text>
62
+ <Text theme='header_2'>{square.square_score_x}</Text>
63
+ </View>
64
+ <View style={{ flexDirection:'row', alignItems:'center' }}>
65
+ <Text style={{ flex:1 }} theme='body'>{away_abbr}</Text>
66
+ <Text theme='header_2'>{square.square_score_y}</Text>
67
+ </View>
68
+ </View>
69
+ <View style={{ padding:5 }}>
70
+ <Button
71
+ title={`$${data.item.next_purchase_price}`}
72
+ title_color={Colors.shades.white}
73
+ backgroundColor={Colors.brand.electric}
74
+ onPress={() => onSquareBid(square, 'add')}
75
+ />
76
+ </View>
77
+ </View>
78
+ )
79
+ }
80
+
81
+
82
+ let ev_pct = 0
83
+ if(!isNaN(squares_expected_value.ev_pct)){ ev_pct = squares_expected_value.ev_pct }
84
+
85
+ return (
86
+ <View style={{ ...view_styles.section, minWidth:350 }}>
87
+ <TouchableOpacity style={view_styles.section_header} onPress={() => setExpanded(!expanded)}>
88
+ <View style={{ justifyContent:'center', alignItems:'center' }}>
89
+ <Text size={14} color={squares_expected_value.expected_value > 0 ? Colors.utility.success: Colors.utility.error} weight='bold'>{(ev_pct * 100).toFixed(2)}%</Text>
90
+ <Text style={{ marginTop:3 }} size={12} color={Colors.brand.midnight} weight='regular'>EV</Text>
91
+ </View>
92
+ <View style={{ flex:1, marginLeft:10 }}>
93
+ <Text theme="header">MY STATS (BETA)</Text>
94
+ <Text style={{ marginTop: 4 }} theme="body_2">Current statistics from the squares board</Text>
95
+ </View>
96
+ <Icons.ChevronIcon direction={expanded ? 'up' : 'down'} color={Colors.brand.midnight} size={8} />
97
+ </TouchableOpacity>
98
+ {expanded && !comp_started ?
99
+ <View style={{ padding:5, backgroundColor:Colors.incentive.gold_faded}}>
100
+ <View style={{ padding:5 }}>
101
+ <Text theme="header">Suggested Squares</Text>
102
+ <Text style={{ marginTop:3 }} theme="body_2">Suggestion are determined by running thousands of simulations based on the board in its current state. These will change frequently as the board changes.</Text>
103
+ </View>
104
+ <View style={{ marginTop:3, padding:10, justifyContent:'center', alignItems:'center' }}>
105
+ <FlatList
106
+ data={suggested_squares}
107
+ horizontal
108
+ renderItem={renderSuggestions}
109
+ keyExtractor={(item) => item.sq_square_id.toString()}
110
+ />
111
+ </View>
112
+ </View>
113
+ :<></>}
114
+ {expanded ?
115
+ <View style={view_styles.section_body}>
116
+ <View style={{ ...view_styles.body_row, borderBottomWidth:1, borderColor:Colors.shades.shade600 }}>
117
+ <View style={{flex:1, marginRight:10}}>
118
+ <Text theme="header_2">Expected Value (pct)</Text>
119
+ <Text style={{ marginTop:3 }} theme="body_2">Based on your owned squares and ownership pct (for extrapolation), we can calculate the probable earnings of your squares over thousands of simulations</Text>
120
+ </View>
121
+ <View style={{ justifyContent:'center', alignItems:'center' }}>
122
+ <Text color={squares_expected_value.expected_value > 0 ? Colors.utility.success: Colors.utility.error} weight='bold' size={14}>${squares_expected_value.expected_value.toFixed(2)}</Text>
123
+ <Text style={{ marginTop:3 }} color={squares_expected_value.expected_value > 0 ? Colors.utility.success: Colors.utility.error} weight='regular' size={14}>({(ev_pct * 100).toFixed(2)}%)</Text>
124
+ </View>
125
+ </View>
126
+ <View style={{ ...view_styles.body_row, borderBottomWidth:1, borderColor:Colors.shades.shade600 }}>
127
+ <View style={{flex:1, marginRight:10}}>
128
+ <Text theme="header_2">Outbid Squares</Text>
129
+ <Text style={{ marginTop:3 }} theme="body_2">Number of squares you bid on but were outbid or sold</Text>
130
+ </View>
131
+ <Text theme="header_2">{my_outbid_squares.length} Squares</Text>
132
+ </View>
133
+ <View style={{ ...view_styles.body_row, borderBottomWidth:1, borderColor:Colors.shades.shade600 }}>
134
+ <View style={{flex:1, marginRight:10}}>
135
+ <Text theme="header_2">My Ownership (Pct)</Text>
136
+ <Text style={{ marginTop:3 }} theme="body_2">How much of the total board do I own? (All unbid squares will be extrapolated based on this ownership pct)</Text>
137
+ </View>
138
+ <Text theme="header_2">{my_ps.length} Squares ({(my_ownership).toFixed()}%)</Text>
139
+ </View>
140
+ <View style={{ ...view_styles.body_row, borderBottomWidth:1, borderColor:Colors.shades.shade600 }}>
141
+ <View style={{flex:1, marginRight:10}}>
142
+ <Text theme="header_2">My Total Paid</Text>
143
+ <Text style={{ marginTop:3 }} theme="body_2">How much have I paid for my ownership pct</Text>
144
+ </View>
145
+ <Text theme="header_2">${(money_in).toFixed(2)} ({((money_in / total_payout)*100).toFixed(2)}%)</Text>
146
+ </View>
147
+ <View style={{ ...view_styles.body_row, borderBottomWidth:1, borderColor:Colors.shades.shade600 }}>
148
+ <View style={{flex:1, marginRight:10}}>
149
+ <Text theme="header_2">Winnings Received</Text>
150
+ <Text style={{ marginTop:3 }} theme="body_2">How much have I received from winning or selling squares</Text>
151
+ </View>
152
+ <Text theme="header_2">${(money_out).toFixed(2)}</Text>
153
+ </View>
154
+ <View style={{ ...view_styles.body_row, borderBottomWidth:1, borderColor:Colors.shades.shade600 }}>
155
+ <View style={{flex:1, marginRight:10}}>
156
+ <Text theme="header_2">ROI</Text>
157
+ <Text style={{ marginTop:3 }} theme="body_2">What is my current return on investment (earnings / total paid)</Text>
158
+ </View>
159
+ <Text color={roi > 0 ? Colors.utility.success : Colors.utility.error} weight='bold' size={14}>{(roi * 100).toFixed(2)}%</Text>
160
+ </View>
161
+ </View>
162
+ :<></>}
163
+ </View>
164
+ )
165
+ }
166
+
167
+ export default MyStatsCard
@@ -16,6 +16,7 @@ import type { BEEventProps } from "../Observer/api/types";
16
16
  import OfferForm from "./components/OfferForm";
17
17
  import MySquaresCard from "./components/MySquaresCard";
18
18
  import { view_styles } from "../constants/styles";
19
+ import MyStatsCard from "./components/MyStatsCard";
19
20
 
20
21
  type SquaresModuleProps = {
21
22
  player_id?:string,
@@ -68,11 +69,12 @@ const SquaresModule = ({ sq_comp_id, player_id, distinct_id, onRequestAuthentica
68
69
  const { square_bids, draft_square_offers, submit_ready } = board_data;
69
70
  const { loading, league, event, players, loaded, squares_competition, squares, squares_type, squares_payout_type, square_results, square_offers, player_square_history, player_squares } = module_data;
70
71
 
72
+ const squares_expected_value = SqauresHelpers.getMyExpectedValue(squares, player_squares.filter(ps => ps.status == 'active' && ps.player_id == player_id), squares_competition, player_id)
71
73
 
72
74
  const my_squares = player_squares.filter(ps => ps.status == 'active' && ps.player_id == player_id);
73
75
  const home_abbr = event?.home?.abbr??squares_competition?.event_backup?.home?.abbr
74
76
  const away_abbr = event?.away?.abbr??squares_competition?.event_backup?.away?.abbr
75
-
77
+ const joined = SqauresHelpers.amIParticipating(player_squares, player_square_history, player_id);
76
78
 
77
79
  useEffect(() => {
78
80
  if(!sq_comp_id){ return }
@@ -85,7 +87,9 @@ const SquaresModule = ({ sq_comp_id, player_id, distinct_id, onRequestAuthentica
85
87
  const d = await SquaresApi.getSquareCompetitionById(sq_comp_id);
86
88
  const evs = await SquaresApi.getEventsByEventIds([d.squares_competition.event_id]);
87
89
  const league_id = evs[0]?.league_id
88
- let ps = await SquaresApi.getPlayersByPlayerIds([ ...new Set(d.player_squares.map(ps => ps.player_id)) ])
90
+ let unique_player_ids = [ ...new Set(d.player_squares.map(ps => ps.player_id)) ]
91
+ if(player_id){ unique_player_ids.push(player_id) }
92
+ let ps = await SquaresApi.getPlayersByPlayerIds(unique_player_ids)
89
93
  let l:LeagueProps | undefined = undefined
90
94
  if(league_id){
91
95
  l = await SquaresApi.getLeagueById(league_id);
@@ -281,12 +285,28 @@ const SquaresModule = ({ sq_comp_id, player_id, distinct_id, onRequestAuthentica
281
285
  />
282
286
  :<></>}
283
287
  <BoardStats
284
- player_id={player_id}
285
288
  squares_competition={squares_competition}
286
289
  squares={squares}
287
290
  player_squares={player_squares}
288
291
  />
289
-
292
+ {joined ?
293
+ <MyStatsCard
294
+ player_id={player_id}
295
+ players={players}
296
+ home_abbr={home_abbr}
297
+ squares_expected_value={squares_expected_value}
298
+ away_abbr={away_abbr}
299
+ onSquareBid={(square, action) => {
300
+ handleSquareBid(square, action)
301
+ setBidFormExpanded(true);
302
+ }}
303
+ squares={squares}
304
+ player_square_history={player_square_history}
305
+ player_squares={player_squares}
306
+ square_results={square_results}
307
+ squares_competition={squares_competition}
308
+ />
309
+ :<></>}
290
310
  {square_results.length > 0 ?
291
311
  <ResultsCard
292
312
  home_abbr={home_abbr}
@@ -330,6 +350,7 @@ const SquaresModule = ({ sq_comp_id, player_id, distinct_id, onRequestAuthentica
330
350
  squares={squares}
331
351
  square_offers={square_offers}
332
352
  away_abbr={away_abbr}
353
+ my_square_values={squares_expected_value.my_square_values}
333
354
  home_abbr={home_abbr}
334
355
  comp_status={comp_status}
335
356
  onSquareOffer={handleSquareOffer}
package/src/types.d.ts CHANGED
@@ -1458,6 +1458,9 @@ export interface SquaresCompetitionProps {
1458
1458
  auth_strategy_id?:string
1459
1459
  }
1460
1460
 
1461
+ export interface SquaresExpectedValueProps {
1462
+ ev_pct:number, money_in:number, expected_payout:number, expected_value:number, other_square_values:SquareValueProps[], my_square_values:SquareValueProps[]
1463
+ }
1461
1464
 
1462
1465
  export interface SquaresTypeProps {
1463
1466
  sq_type_id:string, sq_type_name:string, sq_type_description:string, empty_square_action:string,
@@ -1475,6 +1478,8 @@ export interface SquareProps {
1475
1478
  create_datetime:any, last_update_datetime:any
1476
1479
  }
1477
1480
 
1481
+ export interface SquareValueProps { sq_square_id:string, probability:number, expected_value: number, expected_payout:number, next_purchase_price:number, after_purchase_expected_payout:number, after_purchase_expected_value:number }
1482
+
1478
1483
  export interface OfferResponseProps { squares_competition?:SquaresCompetitionProps, updated_offers:SquareOfferProps[], saved_player_squares:PlayerSquareProps[], removed_player_squares:PlayerSquareProps[] }
1479
1484
  export interface BuySquaresResponseProps { squares_competition:SquaresCompetitionProps, saved_player_squares:PlayerSquareProps[], removed_player_squares:PlayerSquareProps[], updated_squares:SquareProps[] }
1480
1485