@bettoredge/calcutta 0.2.0

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 (38) hide show
  1. package/package.json +46 -0
  2. package/src/components/CalcuttaAuction.tsx +453 -0
  3. package/src/components/CalcuttaAuctionItem.tsx +292 -0
  4. package/src/components/CalcuttaBidInput.tsx +214 -0
  5. package/src/components/CalcuttaCard.tsx +131 -0
  6. package/src/components/CalcuttaDetail.tsx +377 -0
  7. package/src/components/CalcuttaEscrow.tsx +464 -0
  8. package/src/components/CalcuttaItemResults.tsx +207 -0
  9. package/src/components/CalcuttaLeaderboard.tsx +179 -0
  10. package/src/components/CalcuttaPayoutPreview.tsx +194 -0
  11. package/src/components/CalcuttaRoundResults.tsx +250 -0
  12. package/src/components/CalcuttaTemplateSelector.tsx +124 -0
  13. package/src/components/sealed/AuctionResultsModal.tsx +165 -0
  14. package/src/components/sealed/EscrowBottomSheet.tsx +185 -0
  15. package/src/components/sealed/SealedBidAuction.tsx +541 -0
  16. package/src/components/sealed/SealedBidHeader.tsx +116 -0
  17. package/src/components/sealed/SealedBidInfoTab.tsx +247 -0
  18. package/src/components/sealed/SealedBidItemCard.tsx +385 -0
  19. package/src/components/sealed/SealedBidItemsTab.tsx +235 -0
  20. package/src/components/sealed/SealedBidMyBidsTab.tsx +512 -0
  21. package/src/components/sealed/SealedBidPlayersTab.tsx +220 -0
  22. package/src/components/sealed/SealedBidStatusBar.tsx +415 -0
  23. package/src/components/sealed/SealedBidTabBar.tsx +172 -0
  24. package/src/helpers/formatting.ts +56 -0
  25. package/src/helpers/lifecycleState.ts +71 -0
  26. package/src/helpers/payout.ts +39 -0
  27. package/src/helpers/validation.ts +64 -0
  28. package/src/hooks/useCalcuttaAuction.ts +164 -0
  29. package/src/hooks/useCalcuttaBid.ts +43 -0
  30. package/src/hooks/useCalcuttaCompetition.ts +63 -0
  31. package/src/hooks/useCalcuttaEscrow.ts +52 -0
  32. package/src/hooks/useCalcuttaItemImages.ts +79 -0
  33. package/src/hooks/useCalcuttaPlayers.ts +46 -0
  34. package/src/hooks/useCalcuttaResults.ts +58 -0
  35. package/src/hooks/useCalcuttaSocket.ts +131 -0
  36. package/src/hooks/useCalcuttaTemplates.ts +36 -0
  37. package/src/index.ts +74 -0
  38. package/src/types.ts +31 -0
@@ -0,0 +1,512 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import { StyleSheet, TouchableOpacity, FlatList, Image } from 'react-native';
3
+ import { View, Text, useTheme } from '@bettoredge/styles';
4
+ import { Ionicons } from '@expo/vector-icons';
5
+ import type { CalcuttaAuctionItemProps, CalcuttaBidProps, CalcuttaEscrowProps, CalcuttaItemResultProps, CalcuttaRoundProps } from '@bettoredge/types';
6
+ import type { ItemImageMap } from '../../hooks/useCalcuttaItemImages';
7
+ import type { CalcuttaLifecycleState } from '../../helpers/lifecycleState';
8
+ import { formatCurrency, getBidStatusColor, getStatusLabel } from '../../helpers/formatting';
9
+
10
+ interface SealedBidMyBidsTabProps {
11
+ items: CalcuttaAuctionItemProps[];
12
+ my_bids: CalcuttaBidProps[];
13
+ escrow?: CalcuttaEscrowProps;
14
+ market_type: string;
15
+ player_id?: string;
16
+ lifecycleState: CalcuttaLifecycleState;
17
+ itemImages?: ItemImageMap;
18
+ item_results?: CalcuttaItemResultProps[];
19
+ rounds?: CalcuttaRoundProps[];
20
+ onCancelBid: (calcutta_bid_id: string) => void;
21
+ onUpdateBid: (calcutta_auction_item_id: string) => void;
22
+ cancelLoading: boolean;
23
+ auctionExpired?: boolean;
24
+ listHeader?: React.ReactNode;
25
+ }
26
+
27
+ interface BidRow {
28
+ bid: CalcuttaBidProps;
29
+ item?: CalcuttaAuctionItemProps;
30
+ }
31
+
32
+ export const SealedBidMyBidsTab: React.FC<SealedBidMyBidsTabProps> = ({
33
+ items,
34
+ my_bids,
35
+ escrow,
36
+ market_type,
37
+ player_id,
38
+ lifecycleState,
39
+ itemImages,
40
+ item_results = [],
41
+ rounds = [],
42
+ onCancelBid,
43
+ onUpdateBid,
44
+ cancelLoading,
45
+ auctionExpired,
46
+ listHeader,
47
+ }) => {
48
+ const { theme } = useTheme();
49
+ const [expandedItemId, setExpandedItemId] = useState<string | null>(null);
50
+
51
+ const isPostAuction = lifecycleState === 'tournament' || lifecycleState === 'completed';
52
+ const isPreAuction = lifecycleState === 'pending' || lifecycleState === 'scheduled';
53
+
54
+ // All items I won at auction — includes sold (active) AND eliminated
55
+ const myItems = useMemo(
56
+ () => items.filter(i => i.winning_player_id === player_id),
57
+ [items, player_id],
58
+ );
59
+
60
+ // For backward compat / badge counts — only active (non-eliminated) items
61
+ const wonItems = useMemo(
62
+ () => myItems.filter(i => i.status === 'sold'),
63
+ [myItems],
64
+ );
65
+
66
+ const totalSpent = useMemo(
67
+ () => myItems.reduce((s, i) => s + Number(i.winning_bid), 0),
68
+ [myItems],
69
+ );
70
+
71
+ const activeBids = useMemo(
72
+ () => my_bids.filter(b => b.bid_status === 'active'),
73
+ [my_bids],
74
+ );
75
+
76
+ const rows: BidRow[] = useMemo(
77
+ () => activeBids.map(bid => ({
78
+ bid,
79
+ item: items.find(i => i.calcutta_auction_item_id === bid.calcutta_auction_item_id),
80
+ })),
81
+ [activeBids, items],
82
+ );
83
+
84
+ const totalCommitted = useMemo(
85
+ () => activeBids.reduce((sum, b) => sum + Number(b.bid_amount), 0),
86
+ [activeBids],
87
+ );
88
+
89
+ const budgetRemaining = escrow ? Number(escrow.escrow_balance) : 0;
90
+
91
+ // Build per-item result map for tournament/completed
92
+ const itemResultMap = useMemo(() => {
93
+ const map: Record<string, CalcuttaItemResultProps[]> = {};
94
+ for (const r of item_results) {
95
+ const key = r.calcutta_auction_item_id;
96
+ if (!map[key]) map[key] = [];
97
+ map[key].push(r);
98
+ }
99
+ return map;
100
+ }, [item_results]);
101
+
102
+ // Round name lookup
103
+ const roundNameMap = useMemo(() => {
104
+ const map: Record<number, string> = {};
105
+ for (const r of rounds) map[r.round_number] = r.round_name;
106
+ return map;
107
+ }, [rounds]);
108
+
109
+ // ============================================
110
+ // PENDING / SCHEDULED — Empty state
111
+ // ============================================
112
+ if (isPreAuction) {
113
+ return (
114
+ <View variant="transparent" style={styles.container}>
115
+ <>{listHeader}</>
116
+ <View variant="transparent" style={styles.emptyContainer}>
117
+ <Ionicons name="time-outline" size={40} color={theme.colors.text.tertiary} />
118
+ <Text variant="body" color="tertiary" style={{ marginTop: 12 }}>Bidding hasn't started yet</Text>
119
+ <Text variant="caption" color="tertiary" style={{ marginTop: 4, textAlign: 'center' }}>
120
+ You'll be able to place bids once the auction begins
121
+ </Text>
122
+ </View>
123
+ </View>
124
+ );
125
+ }
126
+
127
+ // ============================================
128
+ // TOURNAMENT / COMPLETED — "My Items" ownership view with round results
129
+ // ============================================
130
+ if (isPostAuction) {
131
+ if (myItems.length === 0) {
132
+ return (
133
+ <View variant="transparent" style={styles.container}>
134
+ <>{listHeader}</>
135
+ <View variant="transparent" style={styles.emptyContainer}>
136
+ <Ionicons name="ribbon-outline" size={40} color={theme.colors.text.tertiary} />
137
+ <Text variant="body" color="tertiary" style={{ marginTop: 12 }}>No items won</Text>
138
+ <Text variant="caption" color="tertiary" style={{ marginTop: 4, textAlign: 'center' }}>
139
+ You didn't win any items in this auction
140
+ </Text>
141
+ </View>
142
+ </View>
143
+ );
144
+ }
145
+
146
+ const totalEarned = myItems.reduce((s, i) => {
147
+ const results = itemResultMap[i.calcutta_auction_item_id] || [];
148
+ return s + results.reduce((rs, r) => rs + Number(r.payout_earned || 0), 0);
149
+ }, 0);
150
+ const totalROI = totalEarned - totalSpent;
151
+
152
+ return (
153
+ <View variant="transparent" style={styles.container}>
154
+ <FlatList
155
+ data={myItems}
156
+ keyExtractor={i => i.calcutta_auction_item_id}
157
+ contentContainerStyle={styles.list}
158
+ ListHeaderComponent={
159
+ <View variant="transparent">
160
+ <>{listHeader}</>
161
+ <View variant="transparent" style={[styles.summary, {
162
+ backgroundColor: totalROI >= 0 ? theme.colors.status.successSubtle : theme.colors.status.error + '08',
163
+ borderColor: totalROI >= 0 ? theme.colors.status.success + '40' : theme.colors.status.error + '30',
164
+ }]}>
165
+ <View variant="transparent" style={styles.summaryItem}>
166
+ <Ionicons name="trophy" size={20} color="#F59E0B" />
167
+ <Text variant="caption" color="secondary" style={{ marginTop: 4 }}>Items</Text>
168
+ <Text variant="h3" bold>{myItems.length}</Text>
169
+ </View>
170
+ <View variant="transparent" style={[styles.summaryItem, { borderLeftWidth: 1, borderColor: theme.colors.border.subtle }]}>
171
+ <Ionicons name="arrow-down-circle-outline" size={20} color={theme.colors.text.tertiary} />
172
+ <Text variant="caption" color="secondary" style={{ marginTop: 4 }}>Spent</Text>
173
+ <Text variant="h3" bold>{formatCurrency(totalSpent, market_type)}</Text>
174
+ </View>
175
+ <View variant="transparent" style={[styles.summaryItem, { borderLeftWidth: 1, borderColor: theme.colors.border.subtle }]}>
176
+ <Ionicons name="arrow-up-circle-outline" size={20} color={theme.colors.status.success} />
177
+ <Text variant="caption" color="secondary" style={{ marginTop: 4 }}>Earned</Text>
178
+ <Text variant="h3" bold style={{ color: theme.colors.status.success }}>{formatCurrency(totalEarned, market_type)}</Text>
179
+ </View>
180
+ </View>
181
+ {/* ROI banner */}
182
+ <View variant="transparent" style={[styles.roiBanner, {
183
+ backgroundColor: totalROI >= 0 ? theme.colors.status.successSubtle : theme.colors.status.error + '10',
184
+ }]}>
185
+ <Text variant="caption" bold style={{ color: totalROI >= 0 ? theme.colors.status.success : theme.colors.status.error }}>
186
+ ROI: {totalROI >= 0 ? '+' : ''}{formatCurrency(totalROI, market_type)}
187
+ </Text>
188
+ </View>
189
+ <Text variant="caption" color="tertiary" style={styles.sectionLabel}>Your Items</Text>
190
+ </View>
191
+ }
192
+ renderItem={({ item }) => {
193
+ const results = itemResultMap[item.calcutta_auction_item_id] || [];
194
+ const totalPayout = results.reduce((s, r) => s + Number(r.payout_earned || 0), 0);
195
+ const itemROI = totalPayout - Number(item.winning_bid);
196
+ const isEliminated = item.status === 'eliminated';
197
+ const isExpanded = expandedItemId === item.calcutta_auction_item_id;
198
+
199
+ return (
200
+ <TouchableOpacity
201
+ activeOpacity={0.7}
202
+ onPress={() => setExpandedItemId(isExpanded ? null : item.calcutta_auction_item_id)}
203
+ style={[styles.ownedCard, {
204
+ backgroundColor: theme.colors.surface.elevated,
205
+ borderColor: isEliminated
206
+ ? theme.colors.status.error + '30'
207
+ : itemROI > 0
208
+ ? theme.colors.status.success + '40'
209
+ : theme.colors.border.subtle,
210
+ opacity: isEliminated ? 0.8 : 1,
211
+ }]}
212
+ >
213
+ <View variant="transparent" style={styles.ownedRow}>
214
+ <View variant="transparent" style={[styles.ownedIcon, {
215
+ backgroundColor: isEliminated ? theme.colors.status.error + '10' : theme.colors.status.successSubtle,
216
+ overflow: 'hidden',
217
+ }]}>
218
+ {(itemImages?.[item.item_id]?.url || item.item_image?.url) ? (
219
+ <Image source={{ uri: itemImages?.[item.item_id]?.url || item.item_image?.url }} style={styles.ownedItemImage} resizeMode="contain" />
220
+ ) : isEliminated ? (
221
+ <Ionicons name="close-circle" size={18} color={theme.colors.status.error} />
222
+ ) : (
223
+ <Ionicons name="trophy" size={18} color="#F59E0B" />
224
+ )}
225
+ </View>
226
+ <View variant="transparent" style={{ flex: 1 }}>
227
+ <Text variant="body" bold numberOfLines={1}>{item.item_name}</Text>
228
+ <View variant="transparent" style={{ flexDirection: 'row', alignItems: 'center', marginTop: 2 }}>
229
+ {isEliminated && (
230
+ <Text variant="caption" bold style={{ color: theme.colors.status.error, fontSize: 10, marginRight: 6 }}>ELIMINATED</Text>
231
+ )}
232
+ {item.seed != null && (
233
+ <Text variant="caption" color="tertiary">Seed #{item.seed}</Text>
234
+ )}
235
+ </View>
236
+ </View>
237
+ <View variant="transparent" style={{ alignItems: 'flex-end' }}>
238
+ <Text variant="caption" color="tertiary" style={{ fontSize: 10 }}>ROI</Text>
239
+ <Text variant="body" bold style={{
240
+ color: itemROI > 0
241
+ ? theme.colors.status.success
242
+ : itemROI < 0
243
+ ? theme.colors.status.error
244
+ : theme.colors.text.primary,
245
+ }}>
246
+ {itemROI >= 0 ? '+' : ''}{formatCurrency(itemROI, market_type)}
247
+ </Text>
248
+ </View>
249
+ <Ionicons
250
+ name={isExpanded ? 'chevron-up' : 'chevron-down'}
251
+ size={14}
252
+ color={theme.colors.text.tertiary}
253
+ style={{ marginLeft: 6 }}
254
+ />
255
+ </View>
256
+
257
+ {/* Expanded: cost + earnings + round progression */}
258
+ {isExpanded && (
259
+ <View variant="transparent" style={[styles.resultsExpanded, { borderColor: theme.colors.border.subtle }]}>
260
+ <View variant="transparent" style={styles.resultRow}>
261
+ <Text variant="caption" color="secondary" style={{ flex: 1 }}>Paid at auction</Text>
262
+ <Text variant="caption" bold>{formatCurrency(item.winning_bid, market_type)}</Text>
263
+ </View>
264
+ {results
265
+ .sort((a, b) => (a.round_number ?? 0) - (b.round_number ?? 0))
266
+ .map(r => {
267
+ const isAdvanced = r.result === 'advanced' || r.result === 'won';
268
+ const rn = r.round_number ?? 0;
269
+ const roundName = roundNameMap[rn] || `Round ${rn}`;
270
+ return (
271
+ <View key={r.calcutta_item_result_id} variant="transparent" style={styles.resultRow}>
272
+ <Ionicons
273
+ name={isAdvanced ? 'checkmark-circle' : 'close-circle'}
274
+ size={14}
275
+ color={isAdvanced ? theme.colors.status.success : theme.colors.status.error}
276
+ />
277
+ <Text variant="caption" style={{ flex: 1, marginLeft: 6 }}>{roundName}</Text>
278
+ <Text variant="caption" color="secondary">{getStatusLabel(r.result)}</Text>
279
+ {Number(r.payout_earned) > 0 && (
280
+ <Text variant="caption" bold style={{ color: theme.colors.status.success, marginLeft: 8 }}>
281
+ +{formatCurrency(r.payout_earned, market_type)}
282
+ </Text>
283
+ )}
284
+ </View>
285
+ );
286
+ })}
287
+ {results.length === 0 && (
288
+ <Text variant="caption" color="tertiary" style={{ textAlign: 'center', paddingVertical: 4 }}>
289
+ No round results yet
290
+ </Text>
291
+ )}
292
+ </View>
293
+ )}
294
+ </TouchableOpacity>
295
+ );
296
+ }}
297
+ />
298
+ </View>
299
+ );
300
+ }
301
+
302
+ // ============================================
303
+ // AUCTIONING — "My Bids" bidding view
304
+ // ============================================
305
+ if (rows.length === 0) {
306
+ return (
307
+ <View variant="transparent" style={styles.container}>
308
+ <>{listHeader}</>
309
+ <View variant="transparent" style={styles.emptyContainer}>
310
+ <Ionicons name="pricetag-outline" size={40} color={theme.colors.text.tertiary} />
311
+ <Text variant="body" color="tertiary" style={{ marginTop: 12 }}>No bids yet</Text>
312
+ <Text variant="caption" color="tertiary" style={{ marginTop: 4, textAlign: 'center' }}>
313
+ Browse the Items tab to start bidding
314
+ </Text>
315
+ </View>
316
+ </View>
317
+ );
318
+ }
319
+
320
+ return (
321
+ <View variant="transparent" style={styles.container}>
322
+ <FlatList
323
+ data={rows}
324
+ keyExtractor={r => r.bid.calcutta_bid_id}
325
+ contentContainerStyle={styles.list}
326
+ ListHeaderComponent={
327
+ <View variant="transparent">
328
+ <>{listHeader}</>
329
+ <View variant="transparent" style={[styles.summary, { backgroundColor: theme.colors.surface.elevated, borderColor: theme.colors.border.subtle }]}>
330
+ <View variant="transparent" style={styles.summaryItem}>
331
+ <Text variant="caption" color="tertiary">Total Bids</Text>
332
+ <Text variant="body" bold>{activeBids.length}</Text>
333
+ </View>
334
+ <View variant="transparent" style={[styles.summaryItem, { borderLeftWidth: 1, borderColor: theme.colors.border.subtle }]}>
335
+ <Text variant="caption" color="tertiary">Committed</Text>
336
+ <Text variant="body" bold>{formatCurrency(totalCommitted, market_type)}</Text>
337
+ </View>
338
+ <View variant="transparent" style={[styles.summaryItem, { borderLeftWidth: 1, borderColor: theme.colors.border.subtle }]}>
339
+ <Text variant="caption" color="tertiary">Remaining</Text>
340
+ <Text variant="body" bold>{formatCurrency(budgetRemaining, market_type)}</Text>
341
+ </View>
342
+ </View>
343
+ </View>
344
+ }
345
+ renderItem={({ item: row }) => (
346
+ <View
347
+ variant="transparent"
348
+ style={[styles.bidCard, { backgroundColor: theme.colors.surface.elevated, borderColor: theme.colors.border.subtle }]}
349
+ >
350
+ <View variant="transparent" style={styles.bidRow}>
351
+ <View variant="transparent" style={{ flex: 1 }}>
352
+ <Text variant="body" bold numberOfLines={1}>
353
+ {row.item?.item_name ?? 'Unknown Item'}
354
+ </Text>
355
+ <View variant="transparent" style={{ flexDirection: 'row', alignItems: 'center', marginTop: 2 }}>
356
+ <Ionicons
357
+ name="ellipse"
358
+ size={8}
359
+ color={getBidStatusColor(row.bid.bid_status)}
360
+ />
361
+ <Text variant="caption" style={{ color: getBidStatusColor(row.bid.bid_status), marginLeft: 4, fontSize: 11 }}>
362
+ {getStatusLabel(row.bid.bid_status)}
363
+ </Text>
364
+ </View>
365
+ </View>
366
+ <Text variant="h3" bold style={{ color: theme.colors.status.success }}>
367
+ {formatCurrency(row.bid.bid_amount, market_type)}
368
+ </Text>
369
+ </View>
370
+
371
+ {/* Actions — only when auctioning AND timer hasn't expired */}
372
+ {!auctionExpired ? (
373
+ <View variant="transparent" style={styles.actions}>
374
+ <TouchableOpacity
375
+ style={[styles.actionBtn, { borderColor: theme.colors.border.subtle }]}
376
+ onPress={() => onUpdateBid(row.bid.calcutta_auction_item_id)}
377
+ activeOpacity={0.7}
378
+ >
379
+ <Ionicons name="create-outline" size={14} color={theme.colors.primary.default} />
380
+ <Text variant="caption" bold style={{ color: theme.colors.primary.default, marginLeft: 4 }}>
381
+ Update
382
+ </Text>
383
+ </TouchableOpacity>
384
+ <TouchableOpacity
385
+ style={[styles.actionBtn, { borderColor: theme.colors.status.error + '40', marginLeft: 8 }]}
386
+ onPress={() => onCancelBid(row.bid.calcutta_bid_id)}
387
+ disabled={cancelLoading}
388
+ activeOpacity={0.7}
389
+ >
390
+ <Ionicons name="close-outline" size={14} color={theme.colors.status.error} />
391
+ <Text variant="caption" bold style={{ color: theme.colors.status.error, marginLeft: 4 }}>
392
+ Cancel
393
+ </Text>
394
+ </TouchableOpacity>
395
+ </View>
396
+ ) : (
397
+ <View variant="transparent" style={[styles.expiredNotice, { backgroundColor: theme.colors.surface.base }]}>
398
+ <Ionicons name="time-outline" size={14} color={theme.colors.text.tertiary} />
399
+ <Text variant="caption" color="tertiary" style={{ marginLeft: 6 }}>
400
+ Auction ended — resolving results...
401
+ </Text>
402
+ </View>
403
+ )}
404
+ </View>
405
+ )}
406
+ />
407
+ </View>
408
+ );
409
+ };
410
+
411
+ const styles = StyleSheet.create({
412
+ container: {
413
+ flex: 1,
414
+ },
415
+ emptyContainer: {
416
+ flex: 1,
417
+ alignItems: 'center',
418
+ justifyContent: 'center',
419
+ padding: 40,
420
+ },
421
+ summary: {
422
+ flexDirection: 'row',
423
+ margin: 12,
424
+ borderRadius: 10,
425
+ borderWidth: 1,
426
+ overflow: 'hidden',
427
+ },
428
+ summaryItem: {
429
+ flex: 1,
430
+ alignItems: 'center',
431
+ paddingVertical: 12,
432
+ },
433
+ roiBanner: {
434
+ marginHorizontal: 12,
435
+ marginTop: 8,
436
+ paddingVertical: 8,
437
+ borderRadius: 8,
438
+ alignItems: 'center',
439
+ },
440
+ sectionLabel: {
441
+ paddingHorizontal: 16,
442
+ paddingBottom: 8,
443
+ },
444
+ list: {
445
+ paddingHorizontal: 12,
446
+ paddingBottom: 40,
447
+ },
448
+ ownedCard: {
449
+ borderWidth: 1,
450
+ borderRadius: 10,
451
+ marginBottom: 8,
452
+ overflow: 'hidden',
453
+ },
454
+ ownedRow: {
455
+ flexDirection: 'row',
456
+ alignItems: 'center',
457
+ padding: 12,
458
+ },
459
+ ownedIcon: {
460
+ width: 40,
461
+ height: 40,
462
+ borderRadius: 20,
463
+ alignItems: 'center',
464
+ justifyContent: 'center',
465
+ marginRight: 12,
466
+ },
467
+ ownedItemImage: {
468
+ width: 40,
469
+ height: 40,
470
+ borderRadius: 20,
471
+ },
472
+ resultsExpanded: {
473
+ borderTopWidth: 1,
474
+ paddingHorizontal: 12,
475
+ paddingVertical: 6,
476
+ },
477
+ resultRow: {
478
+ flexDirection: 'row',
479
+ alignItems: 'center',
480
+ paddingVertical: 4,
481
+ },
482
+ bidCard: {
483
+ borderWidth: 1,
484
+ borderRadius: 10,
485
+ padding: 12,
486
+ marginBottom: 8,
487
+ },
488
+ bidRow: {
489
+ flexDirection: 'row',
490
+ alignItems: 'center',
491
+ },
492
+ actions: {
493
+ flexDirection: 'row',
494
+ marginTop: 10,
495
+ },
496
+ actionBtn: {
497
+ flexDirection: 'row',
498
+ alignItems: 'center',
499
+ paddingHorizontal: 12,
500
+ paddingVertical: 6,
501
+ borderRadius: 6,
502
+ borderWidth: 1,
503
+ },
504
+ expiredNotice: {
505
+ flexDirection: 'row',
506
+ alignItems: 'center',
507
+ marginTop: 10,
508
+ paddingHorizontal: 10,
509
+ paddingVertical: 8,
510
+ borderRadius: 6,
511
+ },
512
+ });