@dubsdotapp/expo 0.5.16 → 0.5.17

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dubsdotapp/expo",
3
- "version": "0.5.16",
3
+ "version": "0.5.17",
4
4
  "description": "React Native SDK for the Dubs betting platform",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -288,11 +288,14 @@ export function JoinGameSheet({
288
288
 
289
289
  {/* Team Selection — hidden in pool mode and custom games */}
290
290
  {!isCustomGame && !isPoolModeEnabled && !alreadyJoined && (
291
- <View style={styles.section}>
292
- <Text style={[styles.sectionLabel, { color: t.textSecondary }]}>Pick Your Side</Text>
293
- <View style={styles.teamsRow}>
294
- <TeamButton
291
+ hasDrawOption ? (
292
+ /* ── 3-way layout: Home / VS / Away / OR / Draw ── */
293
+ <View style={styles.section}>
294
+ <Text style={[styles.sectionLabel, { color: t.textSecondary }]}>Who will win?</Text>
295
+
296
+ <PickRow
295
297
  name={homeName}
298
+ subtitle="Home Team"
296
299
  imageUrl={opponents[0]?.imageUrl}
297
300
  odds={homeOdds}
298
301
  bets={homeBets}
@@ -302,8 +305,16 @@ export function JoinGameSheet({
302
305
  ImageComponent={ImageComponent}
303
306
  t={t}
304
307
  />
305
- <TeamButton
308
+
309
+ <View style={styles.dividerRow}>
310
+ <View style={[styles.dividerLine, { backgroundColor: t.border }]} />
311
+ <Text style={[styles.dividerText, { color: t.textMuted }]}>VS</Text>
312
+ <View style={[styles.dividerLine, { backgroundColor: t.border }]} />
313
+ </View>
314
+
315
+ <PickRow
306
316
  name={awayName}
317
+ subtitle="Away Team"
307
318
  imageUrl={opponents[1]?.imageUrl}
308
319
  odds={awayOdds}
309
320
  bets={awayBets}
@@ -313,21 +324,54 @@ export function JoinGameSheet({
313
324
  ImageComponent={ImageComponent}
314
325
  t={t}
315
326
  />
327
+
328
+ <View style={styles.dividerRow}>
329
+ <View style={[styles.dividerLine, { backgroundColor: t.border }]} />
330
+ <Text style={[styles.dividerText, { color: t.textMuted }]}>OR</Text>
331
+ <View style={[styles.dividerLine, { backgroundColor: t.border }]} />
332
+ </View>
333
+
334
+ <PickRow
335
+ name="Draw"
336
+ subtitle="Match ends in a tie"
337
+ odds={drawOdds}
338
+ bets={drawBets}
339
+ color={drawColor}
340
+ selected={selectedTeam === 'draw'}
341
+ onPress={() => { setSelectedTeam('draw' as any); onTeamSelect?.('draw' as any); }}
342
+ t={t}
343
+ />
316
344
  </View>
317
- {hasDrawOption && (
318
- <View style={styles.drawRow}>
345
+ ) : (
346
+ /* ── 2-way layout: side by side ── */
347
+ <View style={styles.section}>
348
+ <Text style={[styles.sectionLabel, { color: t.textSecondary }]}>Pick Your Side</Text>
349
+ <View style={styles.teamsRow}>
319
350
  <TeamButton
320
- name="Draw"
321
- odds={drawOdds}
322
- bets={drawBets}
323
- color={drawColor}
324
- selected={selectedTeam === 'draw'}
325
- onPress={() => { setSelectedTeam('draw' as any); onTeamSelect?.('draw' as any); }}
351
+ name={homeName}
352
+ imageUrl={opponents[0]?.imageUrl}
353
+ odds={homeOdds}
354
+ bets={homeBets}
355
+ color={homeColor}
356
+ selected={selectedTeam === 'home'}
357
+ onPress={() => { setSelectedTeam('home'); onTeamSelect?.('home'); }}
358
+ ImageComponent={ImageComponent}
359
+ t={t}
360
+ />
361
+ <TeamButton
362
+ name={awayName}
363
+ imageUrl={opponents[1]?.imageUrl}
364
+ odds={awayOdds}
365
+ bets={awayBets}
366
+ color={awayColor}
367
+ selected={selectedTeam === 'away'}
368
+ onPress={() => { setSelectedTeam('away'); onTeamSelect?.('away'); }}
369
+ ImageComponent={ImageComponent}
326
370
  t={t}
327
371
  />
328
372
  </View>
329
- )}
330
- </View>
373
+ </View>
374
+ )
331
375
  )}
332
376
 
333
377
  {/* Already joined — show which side */}
@@ -443,6 +487,105 @@ export function JoinGameSheet({
443
487
  }
444
488
 
445
489
 
490
+ // ── PickRow (vertical 3-way layout for draw-supported leagues) ──
491
+
492
+ function PickRow({
493
+ name, subtitle, imageUrl, odds, bets, color, selected, onPress, ImageComponent, t,
494
+ }: {
495
+ name: string; subtitle?: string; imageUrl?: string | null; odds: string; bets: number;
496
+ color: string; selected: boolean; onPress: () => void;
497
+ ImageComponent?: React.ComponentType<any>; t: any;
498
+ }) {
499
+ const [imgFailed, setImgFailed] = useState(false);
500
+ const Img = ImageComponent || require('react-native').Image;
501
+ const showImage = imageUrl && !imgFailed;
502
+
503
+ return (
504
+ <TouchableOpacity
505
+ style={[pickStyles.row, { borderColor: selected ? color : t.border, backgroundColor: selected ? color + '12' : t.background }]}
506
+ onPress={onPress}
507
+ activeOpacity={0.7}
508
+ >
509
+ {showImage ? (
510
+ <Img source={{ uri: imageUrl }} style={pickStyles.logo} resizeMode="contain" onError={() => setImgFailed(true)} />
511
+ ) : (
512
+ <View style={[pickStyles.logoPlaceholder, { backgroundColor: color + '20' }]}>
513
+ <Text style={[pickStyles.logoEmoji, { color }]}>{name === 'Draw' ? '🤝' : name.charAt(0)}</Text>
514
+ </View>
515
+ )}
516
+ <View style={pickStyles.info}>
517
+ <Text style={[pickStyles.name, { color: t.text }]}>{name}</Text>
518
+ {subtitle && <Text style={[pickStyles.subtitle, { color: t.textMuted }]}>{subtitle}</Text>}
519
+ </View>
520
+ {odds !== '—' && <Text style={[pickStyles.odds, { color }]}>{odds}x</Text>}
521
+ {bets > 0 && <Text style={[pickStyles.bets, { color: t.textMuted }]}>{bets}</Text>}
522
+ {selected && (
523
+ <View style={[pickStyles.check, { backgroundColor: color }]}>
524
+ <Text style={pickStyles.checkText}>✓</Text>
525
+ </View>
526
+ )}
527
+ </TouchableOpacity>
528
+ );
529
+ }
530
+
531
+ const pickStyles = StyleSheet.create({
532
+ row: {
533
+ flexDirection: 'row',
534
+ alignItems: 'center',
535
+ borderWidth: 1.5,
536
+ borderRadius: 14,
537
+ paddingVertical: 12,
538
+ paddingHorizontal: 14,
539
+ gap: 12,
540
+ },
541
+ logo: {
542
+ width: 36,
543
+ height: 36,
544
+ borderRadius: 18,
545
+ },
546
+ logoPlaceholder: {
547
+ width: 36,
548
+ height: 36,
549
+ borderRadius: 18,
550
+ alignItems: 'center',
551
+ justifyContent: 'center',
552
+ },
553
+ logoEmoji: {
554
+ fontSize: 16,
555
+ fontWeight: '800',
556
+ },
557
+ info: {
558
+ flex: 1,
559
+ },
560
+ name: {
561
+ fontSize: 15,
562
+ fontWeight: '700',
563
+ },
564
+ subtitle: {
565
+ fontSize: 12,
566
+ marginTop: 1,
567
+ },
568
+ odds: {
569
+ fontSize: 16,
570
+ fontWeight: '800',
571
+ },
572
+ bets: {
573
+ fontSize: 12,
574
+ },
575
+ check: {
576
+ width: 22,
577
+ height: 22,
578
+ borderRadius: 11,
579
+ alignItems: 'center',
580
+ justifyContent: 'center',
581
+ },
582
+ checkText: {
583
+ color: '#FFF',
584
+ fontSize: 13,
585
+ fontWeight: '800',
586
+ },
587
+ });
588
+
446
589
  const styles = StyleSheet.create({
447
590
  overlay: {
448
591
  ...StyleSheet.absoluteFillObject,
@@ -568,6 +711,20 @@ const styles = StyleSheet.create({
568
711
  drawRow: {
569
712
  marginTop: 8,
570
713
  },
714
+ dividerRow: {
715
+ flexDirection: 'row',
716
+ alignItems: 'center',
717
+ gap: 12,
718
+ marginVertical: 6,
719
+ },
720
+ dividerLine: {
721
+ flex: 1,
722
+ height: 1,
723
+ },
724
+ dividerText: {
725
+ fontSize: 12,
726
+ fontWeight: '700',
727
+ },
571
728
  summaryCard: {
572
729
  marginTop: 20,
573
730
  borderRadius: 16,