@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.
- package/package.json +4 -4
- package/src/components/CalcuttaActionCard.tsx +31 -2
- package/src/components/CalcuttaAuction.tsx +0 -7
- package/src/components/CalcuttaDetail.tsx +247 -168
- package/src/components/CalcuttaResults.tsx +461 -0
- package/src/components/CalcuttaWalkthrough.tsx +371 -0
- package/src/components/sealed/SealedBidAuction.tsx +140 -158
- package/src/index.ts +4 -0
|
@@ -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
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
{
|
|
358
|
-
</
|
|
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
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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
|
-
|
|
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
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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
|
-
{
|
|
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';
|