@bettoredge/calcutta 0.3.0 → 0.3.1

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": "@bettoredge/calcutta",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Calcutta auction competition components for BettorEdge applications",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react';
2
- import { StyleSheet, TouchableOpacity, ActivityIndicator, FlatList, ScrollView, Image, TextInput } from 'react-native';
2
+ import { StyleSheet, TouchableOpacity, ActivityIndicator, FlatList, ScrollView, Image, TextInput, Platform } from 'react-native';
3
3
  import { View, Text, useTheme } from '@bettoredge/styles';
4
4
  import { Ionicons } from '@expo/vector-icons';
5
5
  import type { CalcuttaEscrowProps } from '@bettoredge/types';
@@ -380,8 +380,8 @@ const SweepstakesWaiting: React.FC<CalcuttaAuctionProps & { competition: any }>
380
380
  : '#10B981';
381
381
 
382
382
  return (
383
- <View variant="transparent" style={styles.container}>
384
- <ScrollView style={{ flex: 1 }} contentContainerStyle={{ gap: 16, paddingBottom: 40 }}>
383
+ <View variant="base" style={styles.container}>
384
+ <ScrollView style={{ flex: 1 }} contentContainerStyle={{ gap: 16, paddingBottom: Platform.OS === 'web' ? 300 : 40 }} keyboardShouldPersistTaps="handled">
385
385
  {/* Hero with embedded title */}
386
386
  <View style={{ position: 'relative' }}>
387
387
  {competition.image?.url ? (
@@ -575,6 +575,11 @@ const SweepstakesWaiting: React.FC<CalcuttaAuctionProps & { competition: any }>
575
575
  onChangeText={setSearchQuery}
576
576
  autoCapitalize="none"
577
577
  autoCorrect={false}
578
+ onFocus={(e: any) => {
579
+ if (Platform.OS === 'web' && e?.target?.scrollIntoView) {
580
+ setTimeout(() => e.target.scrollIntoView({ behavior: 'smooth', block: 'center' }), 300);
581
+ }
582
+ }}
578
583
  />
579
584
  {filteredItems.map((item) => {
580
585
  const isMyItem = item.winning_player_id == player_id;
@@ -1,10 +1,11 @@
1
- import React, { useState, useMemo } from 'react';
2
- import { StyleSheet, TouchableOpacity, ActivityIndicator, ScrollView, Image, FlatList } from 'react-native';
1
+ import React, { useState, useMemo, useCallback } from 'react';
2
+ import { StyleSheet, TouchableOpacity, ActivityIndicator, ScrollView, Image, FlatList, TextInput, Platform } from 'react-native';
3
3
  import { View, Text, useTheme } from '@bettoredge/styles';
4
4
  import { Ionicons } from '@expo/vector-icons';
5
5
  import type { CalcuttaParticipantProps } from '@bettoredge/types';
6
6
  import { useCalcuttaCompetition } from '../hooks/useCalcuttaCompetition';
7
7
  import { useCalcuttaPlayers } from '../hooks/useCalcuttaPlayers';
8
+ import { useCalcuttaItemImages } from '../hooks/useCalcuttaItemImages';
8
9
  import { formatCurrency, getStatusLabel, resolveItemImageUrl } from '../helpers/formatting';
9
10
  import { startSweepstakesCompetition } from '@bettoredge/api';
10
11
 
@@ -51,10 +52,26 @@ export const CalcuttaDetail: React.FC<CalcuttaDetailProps> = ({
51
52
 
52
53
  const participantIds = useMemo(() => participants.map(p => p.player_id), [participants]);
53
54
  const { players: enrichedPlayers } = useCalcuttaPlayers(participantIds);
55
+ const { images: itemImages } = useCalcuttaItemImages(items);
54
56
 
55
57
  const [joining, setJoining] = useState(false);
56
58
  const [leaving, setLeaving] = useState(false);
57
59
  const [startingComp, setStartingComp] = useState(false);
60
+ const [itemSearch, setItemSearch] = useState('');
61
+
62
+ const filteredItems = useMemo(() => {
63
+ if (competition?.auction_type !== 'sweepstakes' || !itemSearch.trim()) return items;
64
+ const q = itemSearch.toLowerCase().trim();
65
+ return items.filter(item => {
66
+ if (item.item_name.toLowerCase().includes(q)) return true;
67
+ if (item.winning_player_id) {
68
+ const owner = enrichedPlayers[item.winning_player_id];
69
+ const ownerName = (owner?.username || owner?.show_name || '').toLowerCase();
70
+ if (ownerName.includes(q)) return true;
71
+ }
72
+ return false;
73
+ });
74
+ }, [items, itemSearch, enrichedPlayers, competition?.auction_type]);
58
75
 
59
76
  if (loading && !competition) {
60
77
  return (
@@ -362,6 +379,63 @@ export const CalcuttaDetail: React.FC<CalcuttaDetailProps> = ({
362
379
 
363
380
  case 'items':
364
381
  if (items.length === 0) return null;
382
+ if (isSweepstakes) {
383
+ return (
384
+ <View variant="transparent" style={{ paddingHorizontal: 16, paddingBottom: 8 }}>
385
+ <TextInput
386
+ style={{
387
+ height: 36,
388
+ borderRadius: 8,
389
+ borderWidth: 1,
390
+ borderColor: theme.colors.border.subtle,
391
+ backgroundColor: theme.colors.surface.input,
392
+ color: theme.colors.text.primary,
393
+ paddingHorizontal: 12,
394
+ fontSize: 14,
395
+ marginBottom: 8,
396
+ }}
397
+ placeholder="Search by team or owner..."
398
+ placeholderTextColor={theme.colors.text.tertiary}
399
+ value={itemSearch}
400
+ onChangeText={setItemSearch}
401
+ autoCapitalize="none"
402
+ autoCorrect={false}
403
+ onFocus={(e: any) => {
404
+ if (Platform.OS === 'web' && e?.target?.scrollIntoView) {
405
+ setTimeout(() => e.target.scrollIntoView({ behavior: 'smooth', block: 'center' }), 300);
406
+ }
407
+ }}
408
+ />
409
+ {filteredItems.map(item => {
410
+ const imgUrl = resolveItemImageUrl(item.item_image) || itemImages[item.item_id]?.url;
411
+ const owner = item.winning_player_id ? enrichedPlayers[item.winning_player_id] : undefined;
412
+ const ownerName = owner?.username || owner?.show_name;
413
+ const isMe = item.winning_player_id == player_id;
414
+ return (
415
+ <View key={item.calcutta_auction_item_id} variant="transparent" style={{ flexDirection: 'row', alignItems: 'center', paddingVertical: 8, borderBottomWidth: 1, borderColor: theme.colors.border.subtle }}>
416
+ {imgUrl ? (
417
+ <Image source={{ uri: imgUrl }} style={{ width: 28, height: 28, borderRadius: 6 }} resizeMode="cover" />
418
+ ) : (
419
+ <View variant="transparent" style={{ width: 28, height: 28, borderRadius: 6, backgroundColor: theme.colors.surface.elevated, alignItems: 'center', justifyContent: 'center' }}>
420
+ <Ionicons name="trophy-outline" size={14} color={theme.colors.text.tertiary} />
421
+ </View>
422
+ )}
423
+ <View variant="transparent" style={{ marginLeft: 8, flex: 1 }}>
424
+ <Text variant="body">{item.item_name}</Text>
425
+ {ownerName ? (
426
+ <Text variant="caption" color="tertiary">{isMe ? 'You' : ownerName}</Text>
427
+ ) : (
428
+ <Text variant="caption" color="tertiary">Available</Text>
429
+ )}
430
+ </View>
431
+ {item.seed != null && <Text variant="caption" color="tertiary">#{item.seed}</Text>}
432
+ {isMe && <Text variant="caption" bold style={{ color: theme.colors.primary.default, marginLeft: 8 }}>YOU</Text>}
433
+ </View>
434
+ );
435
+ })}
436
+ </View>
437
+ );
438
+ }
365
439
  return (
366
440
  <View variant="transparent" style={{ paddingHorizontal: 16 }}>
367
441
  <ScrollView horizontal showsHorizontalScrollIndicator={false}>
@@ -433,20 +507,25 @@ export const CalcuttaDetail: React.FC<CalcuttaDetailProps> = ({
433
507
  };
434
508
 
435
509
  return (
436
- <View variant="transparent" style={styles.container}>
437
- {/* Header bar */}
438
- <View variant="transparent" style={[styles.headerBar, { borderColor: theme.colors.border.subtle }]}>
439
- <TouchableOpacity onPress={onClose} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
440
- <Ionicons name="arrow-back" size={24} color={theme.colors.text.primary} />
441
- </TouchableOpacity>
442
- <Text variant="body" bold style={{ flex: 1, marginLeft: 12 }} numberOfLines={1}>{competition.competition_name}</Text>
443
- </View>
510
+ <View variant="base" style={styles.container}>
511
+ {/* Header bar — hidden for sweepstakes (title is in the hero) */}
512
+ {!isSweepstakes && (
513
+ <View variant="transparent" style={[styles.headerBar, { borderColor: theme.colors.border.subtle }]}>
514
+ <TouchableOpacity onPress={onClose} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
515
+ <Ionicons name="arrow-back" size={24} color={theme.colors.text.primary} />
516
+ </TouchableOpacity>
517
+ <Text variant="body" bold style={{ flex: 1, marginLeft: 12 }} numberOfLines={1}>{competition.competition_name}</Text>
518
+ </View>
519
+ )}
444
520
 
445
521
  <FlatList
446
522
  data={sections}
447
523
  keyExtractor={(item) => item.key}
448
524
  renderItem={renderSection}
449
525
  showsVerticalScrollIndicator={false}
526
+ style={{ backgroundColor: theme.colors.surface.base }}
527
+ contentContainerStyle={{ paddingBottom: Platform.OS === 'web' ? 300 : 40 }}
528
+ keyboardShouldPersistTaps="handled"
450
529
  />
451
530
  </View>
452
531
  );