@bettoredge/calcutta 0.4.0 → 0.4.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.
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
2
- import { StyleSheet, ActivityIndicator, TouchableOpacity } from 'react-native';
2
+ import { StyleSheet, ActivityIndicator, TouchableOpacity, ScrollView, Platform, useWindowDimensions } from 'react-native';
3
3
  import { Ionicons } from '@expo/vector-icons';
4
4
  import { View, Text, useTheme, toast } from '@bettoredge/styles';
5
5
  import { useCalcuttaAuction } from '../../hooks/useCalcuttaAuction';
@@ -65,6 +65,10 @@ export const SealedBidAuction: React.FC<SealedBidAuctionProps> = ({
65
65
  onLeave,
66
66
  }) => {
67
67
  const { theme } = useTheme();
68
+ const { width: windowWidth } = useWindowDimensions();
69
+ const [containerWidth, setContainerWidth] = useState(0);
70
+ const measuredWidth = containerWidth || windowWidth;
71
+ const isDesktop = Platform.OS === 'web' && measuredWidth >= 700;
68
72
  const [activeTab, setActiveTab] = useState<SealedBidTab>('items');
69
73
  const [escrowSheetVisible, setEscrowSheetVisible] = useState(false);
70
74
  const [refreshing, setRefreshing] = useState(false);
@@ -326,7 +330,7 @@ export const SealedBidAuction: React.FC<SealedBidAuctionProps> = ({
326
330
  );
327
331
 
328
332
  return (
329
- <View variant="transparent" style={styles.container}>
333
+ <View variant="transparent" style={[styles.container, { backgroundColor: theme.colors.surface.base }]} onLayout={e => setContainerWidth(e.nativeEvent.layout.width)}>
330
334
  <SealedBidHeader
331
335
  competition={competition}
332
336
  isAdmin={isAdmin}
@@ -336,171 +340,144 @@ export const SealedBidAuction: React.FC<SealedBidAuctionProps> = ({
336
340
  auctionExpired={auctionExpired}
337
341
  />
338
342
 
339
- <SealedBidTabBar
340
- activeTab={activeTab}
341
- onTabChange={setActiveTab}
342
- itemCount={items.length}
343
- myBidCount={myBidTabCount}
344
- playerCount={participants.length}
345
- lifecycleState={lifecycleState}
346
- />
347
-
348
- {/* Join banner for non-participants */}
349
- {!isParticipant && onJoin && (
350
- <View variant="transparent" style={[styles.joinBanner, { backgroundColor: theme.colors.primary.subtle, borderColor: theme.colors.primary.default + '30' }]}>
351
- <View variant="transparent" style={styles.joinInfo}>
352
- <Ionicons name="enter-outline" size={20} color={theme.colors.primary.default} />
353
- <View variant="transparent" style={{ marginLeft: 10, flex: 1 }}>
354
- <Text variant="body" bold>Join this auction</Text>
355
- <Text variant="caption" color="secondary">
356
- Join to deposit escrow and start placing bids
357
- {competition.entry_fee > 0 ? ` · ${formatCurrency(competition.entry_fee, competition.market_type)} entry fee` : ''}
358
- </Text>
343
+ {isDesktop ? (
344
+ /* ═══ DESKTOP: all panels visible ═══ */
345
+ <ScrollView style={{ flex: 1, backgroundColor: theme.colors.surface.base }} contentContainerStyle={{ padding: 12, paddingBottom: 40 }} keyboardShouldPersistTaps="handled">
346
+ {statusBar}
347
+
348
+ {/* Join banner */}
349
+ {!isParticipant && onJoin && (
350
+ <View variant="transparent" style={[styles.joinBanner, { backgroundColor: theme.colors.primary.subtle, borderColor: theme.colors.primary.default + '30', marginBottom: 12 }]}>
351
+ <View variant="transparent" style={styles.joinInfo}>
352
+ <Ionicons name="enter-outline" size={20} color={theme.colors.primary.default} />
353
+ <View variant="transparent" style={{ marginLeft: 10, flex: 1 }}>
354
+ <Text variant="body" bold>Join this auction</Text>
355
+ <Text variant="caption" color="secondary">
356
+ {competition.entry_fee > 0 ? `${formatCurrency(competition.entry_fee, competition.market_type)} entry fee` : 'Free to enter'}
357
+ </Text>
358
+ </View>
359
+ </View>
360
+ <TouchableOpacity style={[styles.joinBtn, { backgroundColor: theme.colors.primary.default, opacity: joining ? 0.7 : 1 }]} onPress={handleJoin} disabled={joining} activeOpacity={0.7}>
361
+ {joining ? <ActivityIndicator size="small" color="#FFFFFF" /> : <Text variant="body" bold style={{ color: '#FFFFFF' }}>Join</Text>}
362
+ </TouchableOpacity>
363
+ </View>
364
+ )}
365
+
366
+ {/* Row 1: Items + My Bids */}
367
+ <View variant="transparent" style={{ flexDirection: 'row', gap: 12 }}>
368
+ <View variant="transparent" style={[styles.desktopPanel, { flex: 3, backgroundColor: theme.colors.surface.elevated, borderColor: theme.colors.border.subtle }]}>
369
+ <SealedBidItemsTab
370
+ items={items} my_bids={my_bids} min_bid={competition.min_bid} bid_increment={competition.bid_increment}
371
+ escrow_balance={escrow?.escrow_balance ?? 0} market_type={competition.market_type} player_id={player_id}
372
+ lifecycleState={lifecycleState} itemImages={itemImages} onPlaceBid={handlePlaceBid} bidLoading={bidLoading}
373
+ onRefresh={handleRefresh} refreshing={refreshing} disabled={biddingDisabled}
374
+ />
375
+ </View>
376
+ <View variant="transparent" style={[styles.desktopPanel, { flex: 2, backgroundColor: theme.colors.surface.elevated, borderColor: theme.colors.border.subtle }]}>
377
+ <SealedBidMyBidsTab
378
+ items={items} my_bids={my_bids} escrow={escrow} market_type={competition.market_type} player_id={player_id}
379
+ lifecycleState={lifecycleState} itemImages={itemImages} item_results={item_results} rounds={rounds}
380
+ onCancelBid={handleCancelBid} onUpdateBid={handleUpdateBid} cancelLoading={bidLoading} auctionExpired={auctionExpired}
381
+ />
359
382
  </View>
360
383
  </View>
361
- <TouchableOpacity
362
- style={[styles.joinBtn, { backgroundColor: theme.colors.primary.default, opacity: joining ? 0.7 : 1 }]}
363
- onPress={handleJoin}
364
- disabled={joining}
365
- activeOpacity={0.7}
366
- >
367
- {joining ? (
368
- <ActivityIndicator size="small" color="#FFFFFF" />
369
- ) : (
370
- <Text variant="body" bold style={{ color: '#FFFFFF' }}>Join</Text>
371
- )}
372
- </TouchableOpacity>
373
- </View>
374
- )}
375
384
 
376
- {/* Tab content */}
377
- <View variant="transparent" style={styles.tabContent}>
378
- {activeTab === 'items' && (
379
- <SealedBidItemsTab
380
- items={items}
381
- my_bids={my_bids}
382
- min_bid={competition.min_bid}
383
- bid_increment={competition.bid_increment}
384
- escrow_balance={escrow?.escrow_balance ?? 0}
385
- market_type={competition.market_type}
386
- player_id={player_id}
387
- lifecycleState={lifecycleState}
388
- itemImages={itemImages}
389
- onPlaceBid={handlePlaceBid}
390
- bidLoading={bidLoading}
391
- onRefresh={handleRefresh}
392
- refreshing={refreshing}
393
- disabled={biddingDisabled}
394
- listHeader={statusBar}
395
- />
396
- )}
397
- {activeTab === 'my_bids' && (
398
- <SealedBidMyBidsTab
399
- items={items}
400
- my_bids={my_bids}
401
- escrow={escrow}
402
- market_type={competition.market_type}
403
- player_id={player_id}
404
- lifecycleState={lifecycleState}
405
- itemImages={itemImages}
406
- item_results={item_results}
407
- rounds={rounds}
408
- onCancelBid={handleCancelBid}
409
- onUpdateBid={handleUpdateBid}
410
- cancelLoading={bidLoading}
411
- auctionExpired={auctionExpired}
412
- listHeader={statusBar}
413
- />
414
- )}
415
- {activeTab === 'my_items' && (
416
- <SealedBidMyBidsTab
417
- items={items}
418
- my_bids={my_bids}
419
- escrow={escrow}
420
- market_type={competition.market_type}
421
- player_id={player_id}
422
- lifecycleState={lifecycleState}
423
- itemImages={itemImages}
424
- item_results={item_results}
425
- rounds={rounds}
426
- onCancelBid={handleCancelBid}
427
- onUpdateBid={handleUpdateBid}
428
- cancelLoading={bidLoading}
429
- auctionExpired={auctionExpired}
430
- listHeader={statusBar}
431
- />
432
- )}
433
- {activeTab === 'players' && (
434
- <SealedBidPlayersTab
435
- participants={participants}
436
- players={players}
437
- player_id={player_id}
438
- presence={presence}
439
- socketConnected={socketConnected}
440
- market_type={competition.market_type}
441
- lifecycleState={lifecycleState}
442
- listHeader={statusBar}
443
- />
444
- )}
445
- {activeTab === 'results' && (
446
- <CalcuttaRoundResults
447
- rounds={rounds}
448
- items={items}
449
- item_results={item_results}
450
- payout_rules={payout_rules}
451
- market_type={competition.market_type}
452
- total_pot={Number(competition.total_pot) || 0}
453
- unclaimed_pot={Number(competition.unclaimed_pot) || 0}
454
- />
455
- )}
456
- {activeTab === 'leaderboard' && (
457
- <CalcuttaLeaderboard
458
- participants={participants}
459
- players={players}
460
- player_id={player_id}
461
- market_type={competition.market_type}
462
- listHeader={statusBar}
463
- />
464
- )}
465
- {activeTab === 'info' && (
466
- <SealedBidInfoTab
467
- competition={competition}
468
- rounds={rounds}
469
- payout_rules={payout_rules}
470
- escrow={escrow}
471
- market_type={competition.market_type}
472
- player_balance={player_balance}
473
- onDepositFunds={onDepositFunds}
474
- onEscrowUpdate={handleEscrowUpdate}
385
+ {/* Row 2: Players + Info */}
386
+ <View variant="transparent" style={{ flexDirection: 'row', gap: 12, marginTop: 12 }}>
387
+ <View variant="transparent" style={[styles.desktopPanel, { flex: 1, backgroundColor: theme.colors.surface.elevated, borderColor: theme.colors.border.subtle }]}>
388
+ <SealedBidPlayersTab
389
+ participants={participants} players={players} player_id={player_id} presence={presence}
390
+ socketConnected={socketConnected} market_type={competition.market_type} lifecycleState={lifecycleState}
391
+ />
392
+ </View>
393
+ <View variant="transparent" style={[styles.desktopPanel, { flex: 1, backgroundColor: theme.colors.surface.elevated, borderColor: theme.colors.border.subtle }]}>
394
+ <SealedBidInfoTab
395
+ competition={competition} rounds={rounds} payout_rules={payout_rules} escrow={escrow}
396
+ market_type={competition.market_type} player_balance={player_balance} onDepositFunds={onDepositFunds}
397
+ onEscrowUpdate={handleEscrowUpdate} lifecycleState={lifecycleState}
398
+ />
399
+ </View>
400
+ </View>
401
+ </ScrollView>
402
+ ) : (
403
+ /* ═══ MOBILE: tab system ═══ */
404
+ <>
405
+ <SealedBidTabBar
406
+ activeTab={activeTab}
407
+ onTabChange={setActiveTab}
408
+ itemCount={items.length}
409
+ myBidCount={myBidTabCount}
410
+ playerCount={participants.length}
475
411
  lifecycleState={lifecycleState}
476
412
  />
477
- )}
478
- </View>
479
413
 
480
- {/* Escrow bottom sheet */}
414
+ {!isParticipant && onJoin && (
415
+ <View variant="transparent" style={[styles.joinBanner, { backgroundColor: theme.colors.primary.subtle, borderColor: theme.colors.primary.default + '30' }]}>
416
+ <View variant="transparent" style={styles.joinInfo}>
417
+ <Ionicons name="enter-outline" size={20} color={theme.colors.primary.default} />
418
+ <View variant="transparent" style={{ marginLeft: 10, flex: 1 }}>
419
+ <Text variant="body" bold>Join this auction</Text>
420
+ <Text variant="caption" color="secondary">
421
+ {competition.entry_fee > 0 ? `${formatCurrency(competition.entry_fee, competition.market_type)} entry fee` : 'Free to enter'}
422
+ </Text>
423
+ </View>
424
+ </View>
425
+ <TouchableOpacity style={[styles.joinBtn, { backgroundColor: theme.colors.primary.default, opacity: joining ? 0.7 : 1 }]} onPress={handleJoin} disabled={joining} activeOpacity={0.7}>
426
+ {joining ? <ActivityIndicator size="small" color="#FFFFFF" /> : <Text variant="body" bold style={{ color: '#FFFFFF' }}>Join</Text>}
427
+ </TouchableOpacity>
428
+ </View>
429
+ )}
430
+
431
+ <View variant="transparent" style={styles.tabContent}>
432
+ {activeTab === 'items' && (
433
+ <SealedBidItemsTab items={items} my_bids={my_bids} min_bid={competition.min_bid} bid_increment={competition.bid_increment}
434
+ escrow_balance={escrow?.escrow_balance ?? 0} market_type={competition.market_type} player_id={player_id}
435
+ lifecycleState={lifecycleState} itemImages={itemImages} onPlaceBid={handlePlaceBid} bidLoading={bidLoading}
436
+ onRefresh={handleRefresh} refreshing={refreshing} disabled={biddingDisabled} listHeader={statusBar} />
437
+ )}
438
+ {activeTab === 'my_bids' && (
439
+ <SealedBidMyBidsTab items={items} my_bids={my_bids} escrow={escrow} market_type={competition.market_type}
440
+ player_id={player_id} lifecycleState={lifecycleState} itemImages={itemImages} item_results={item_results}
441
+ rounds={rounds} onCancelBid={handleCancelBid} onUpdateBid={handleUpdateBid} cancelLoading={bidLoading}
442
+ auctionExpired={auctionExpired} listHeader={statusBar} />
443
+ )}
444
+ {activeTab === 'my_items' && (
445
+ <SealedBidMyBidsTab items={items} my_bids={my_bids} escrow={escrow} market_type={competition.market_type}
446
+ player_id={player_id} lifecycleState={lifecycleState} itemImages={itemImages} item_results={item_results}
447
+ rounds={rounds} onCancelBid={handleCancelBid} onUpdateBid={handleUpdateBid} cancelLoading={bidLoading}
448
+ auctionExpired={auctionExpired} listHeader={statusBar} />
449
+ )}
450
+ {activeTab === 'players' && (
451
+ <SealedBidPlayersTab participants={participants} players={players} player_id={player_id} presence={presence}
452
+ socketConnected={socketConnected} market_type={competition.market_type} lifecycleState={lifecycleState}
453
+ listHeader={statusBar} />
454
+ )}
455
+ {activeTab === 'results' && (
456
+ <CalcuttaRoundResults rounds={rounds} items={items} item_results={item_results} payout_rules={payout_rules}
457
+ market_type={competition.market_type} total_pot={Number(competition.total_pot) || 0}
458
+ unclaimed_pot={Number(competition.unclaimed_pot) || 0} />
459
+ )}
460
+ {activeTab === 'leaderboard' && (
461
+ <CalcuttaLeaderboard participants={participants} players={players} player_id={player_id}
462
+ market_type={competition.market_type} listHeader={statusBar} />
463
+ )}
464
+ {activeTab === 'info' && (
465
+ <SealedBidInfoTab competition={competition} rounds={rounds} payout_rules={payout_rules} escrow={escrow}
466
+ market_type={competition.market_type} player_balance={player_balance} onDepositFunds={onDepositFunds}
467
+ onEscrowUpdate={handleEscrowUpdate} lifecycleState={lifecycleState} />
468
+ )}
469
+ </View>
470
+ </>
471
+ )}
472
+
481
473
  <EscrowBottomSheet
482
- visible={escrowSheetVisible}
483
- onDismiss={() => setEscrowSheetVisible(false)}
484
- calcutta_competition_id={calcutta_competition_id}
485
- escrow={escrow}
486
- market_type={competition.market_type}
487
- max_escrow={competition.max_escrow}
488
- player_balance={player_balance}
489
- onDepositFunds={onDepositFunds}
490
- lifecycleState={lifecycleState}
491
- onUpdate={() => {
492
- handleEscrowUpdate();
493
- setEscrowSheetVisible(false);
494
- }}
474
+ visible={escrowSheetVisible} onDismiss={() => setEscrowSheetVisible(false)}
475
+ calcutta_competition_id={calcutta_competition_id} escrow={escrow} market_type={competition.market_type}
476
+ max_escrow={competition.max_escrow} player_balance={player_balance} onDepositFunds={onDepositFunds}
477
+ lifecycleState={lifecycleState} onUpdate={() => { handleEscrowUpdate(); setEscrowSheetVisible(false); }}
495
478
  />
496
479
 
497
- {/* Auction results celebration modal */}
498
- <AuctionResultsModal
499
- visible={showResultsModal}
500
- onDismiss={handleResultsDismiss}
501
- wonItems={wonItems}
502
- market_type={competition.market_type}
503
- />
480
+ <AuctionResultsModal visible={showResultsModal} onDismiss={handleResultsDismiss} wonItems={wonItems} market_type={competition.market_type} />
504
481
  </View>
505
482
  );
506
483
  };
@@ -536,4 +513,9 @@ const styles = StyleSheet.create({
536
513
  tabContent: {
537
514
  flex: 1,
538
515
  },
516
+ desktopPanel: {
517
+ borderRadius: 12,
518
+ borderWidth: 1,
519
+ padding: 8,
520
+ },
539
521
  });
package/src/index.ts CHANGED
@@ -9,6 +9,8 @@ export { CalcuttaCard } from './components/CalcuttaCard';
9
9
  export type { CalcuttaCardProps } from './components/CalcuttaCard';
10
10
  export { CalcuttaDetail } from './components/CalcuttaDetail';
11
11
  export type { CalcuttaDetailProps } from './components/CalcuttaDetail';
12
+ export { CalcuttaResults } from './components/CalcuttaResults';
13
+ export type { CalcuttaResultsProps } from './components/CalcuttaResults';
12
14
  export { CalcuttaAuction } from './components/CalcuttaAuction';
13
15
  export type { CalcuttaAuctionProps } from './components/CalcuttaAuction';
14
16
  export { CalcuttaAuctionItem } from './components/CalcuttaAuctionItem';
@@ -46,6 +48,8 @@ export { ItemSoldCelebration } from './components/ItemSoldCelebration';
46
48
  export type { ItemSoldCelebrationProps } from './components/ItemSoldCelebration';
47
49
  export { AuctionCompleteOverlay } from './components/AuctionCompleteOverlay';
48
50
  export type { AuctionCompleteOverlayProps } from './components/AuctionCompleteOverlay';
51
+ export { CalcuttaWalkthrough } from './components/CalcuttaWalkthrough';
52
+ export type { CalcuttaWalkthroughProps } from './components/CalcuttaWalkthrough';
49
53
 
50
54
  export { CalcuttaTemplateSelector } from './components/CalcuttaTemplateSelector';
51
55
  export type { CalcuttaTemplateSelectorProps } from './components/CalcuttaTemplateSelector';