import { useLocalSearchParams, useRouter } from 'expo-router'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { ActivityIndicator, Alert, Dimensions, ImageBackground, ScrollView, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { RecordModal, RecordModalRef } from '@/app/award-detail/components/RecordModal'; import { BoxSelectionModal, BoxSelectionModalRef } from '@/components/award-detail-yfs/BoxSelectionModal'; import FirstLast from '@/components/award-detail-yfs/FirstLast'; import { NumSelectionModal, NumSelectionModalRef } from '@/components/award-detail-yfs/NumSelectionModal'; import ProductListYfs from '@/components/award-detail-yfs/ProductListYfs'; import ProductSwiper from '@/components/award-detail-yfs/ProductSwiper'; import PurchaseBar from '@/components/award-detail-yfs/PurchaseBar'; import { RuleModal, RuleModalRef } from '@/components/award-detail-yfs/RuleModal'; import { Images } from '@/constants/images'; import { getBoxDetail, getNextBox, getPoolDetail, getPreBox, lockBox, poolIn, poolOut, unlockBox } from '@/services/award'; import { CheckoutModal, CheckoutModalRef } from '../award-detail/components/CheckoutModal'; const { width } = Dimensions.get('window'); const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#1a1a2e' }, background: { flex: 1 }, loading: { flex: 1, backgroundColor: '#1a1a2e', justifyContent: 'center', alignItems: 'center' }, nav: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 15, height: 90, zIndex: 100, position: 'absolute', top: 0, left: 0, right: 0, }, backBtn: { width: 40 }, backText: { color: '#fff', fontSize: 24 }, navTitle: { color: '#fff', fontSize: 16, fontWeight: 'bold', maxWidth: '60%' }, placeholder: { width: 40 }, scrollView: { flex: 1 }, detailWrapper: { position: 'relative', minHeight: 800, paddingBottom: 100, }, mainGoodsSection: { width: '100%', height: 504, position: 'relative', zIndex: 1, }, mainGoodsSectionBtext: { width: '100%', height: 74, marginTop: -10, zIndex: 2, }, positionBgLeftBg: { position: 'absolute', left: 0, top: 225, width: 32, height: 188, zIndex: 2, }, positionBgRightBg: { position: 'absolute', right: 0, top: 225, width: 32, height: 188, zIndex: 2, }, positionBut: { position: 'absolute', zIndex: 10, width: 35, height: 34, }, btnBg: { width: '100%', height: '100%', justifyContent: 'center', alignItems: 'center', }, slantedL: { color: '#fff', fontSize: 12, fontWeight: 'bold', transform: [{ rotate: '14deg' }], marginTop: -2, textShadowColor: '#000', textShadowOffset: { width: 1, height: 1 }, textShadowRadius: 1, }, slantedR: { color: '#fff', fontSize: 12, fontWeight: 'bold', transform: [{ rotate: '-16deg' }], marginTop: -2, textShadowColor: '#000', textShadowOffset: { width: 1, height: 1 }, textShadowRadius: 1, }, positionRule: { top: 256, left: 0, }, positionStore: { top: 256, right: 0, }, positionRecord: { top: 300, left: 0, }, positionRefresh: { top: 345, right: 0, }, bottomBar: { position: 'absolute', bottom: 0, left: 0, right: 0, zIndex: 200, } }); export default function AwardDetailYfsScreen() { const { poolId } = useLocalSearchParams<{ poolId: string }>(); const router = useRouter(); const insets = useSafeAreaInsets(); const [loading, setLoading] = useState(true); const [data, setData] = useState(null); const [scrollTop, setScrollTop] = useState(0); const [currentBox, setCurrentBox] = useState(null); const boxRef = useRef(null); const numRef = useRef(null); const checkoutRef = useRef(null); const ruleRef = useRef(null); const recordRef = useRef(null); const getSafePoolId = () => Array.isArray(poolId) ? poolId[0] : poolId; const loadBox = async (boxNum?: string) => { try { const id = getSafePoolId(); console.log(`[DEBUG-ICHIBAN] loadBox called for pool: ${id}, boxNum: ${boxNum}`); const res = await getBoxDetail(id, boxNum); console.log(`[DEBUG-ICHIBAN] getBoxDetail res:`, res ? `ID: ${res.number}, UsedStatKeys: ${Object.keys(res.usedStat || {})}` : 'null'); if (res) setCurrentBox(res); } catch (error) { console.error('[DEBUG-ICHIBAN] Failed to load box', error); } }; const loadData = useCallback(async () => { if (!poolId) return; setLoading(true); try { const safePoolId = getSafePoolId(); // calling getSafePoolId inside loadData too to be sure console.log(`[DEBUG-ICHIBAN] loadData called for pool: ${safePoolId}`); const res = await getPoolDetail(safePoolId); setData(res); console.log(`[DEBUG-ICHIBAN] Pool detail loaded, calling loadBox...`); await loadBox(); // Initial box } catch (error) { console.error('[DEBUG-ICHIBAN] Failed to load detail', error); } finally { setLoading(false); // Assuming setRefreshing is defined elsewhere or will be added by the user // setRefreshing(false); } }, [poolId]); useEffect(() => { if (poolId) { poolIn(poolId); return () => { poolOut(poolId); }; } }, [poolId]); const handleBoxSelect = (box: any) => { // Must load full detail to get usedStat loadBox(box.number); }; const handlePrevBox = async () => { if (!currentBox) return; try { const res = await getPreBox(getSafePoolId(), currentBox.number); if (res) setCurrentBox(res); else Alert.alert('提示', '已经是第一盒了'); } catch (e) { Alert.alert('提示', '切换失败'); } }; const handleNextBox = async () => { if (!currentBox) return; try { const res = await getNextBox(getSafePoolId(), currentBox.number); if (res) setCurrentBox(res); else Alert.alert('提示', '已经是最后一盒了'); } catch (e) { Alert.alert('提示', '切换失败'); } }; const handlePay = ({ previewRes, chooseNum, boxNum }: any) => { checkoutRef.current?.show(chooseNum.length, previewRes, boxNum, chooseNum); }; useEffect(() => { loadData(); }, [loadData]); const headerBg = scrollTop > 50 ? '#333' : 'transparent'; if (loading) { return ( ); } return ( {/* Navigation Bar */} router.back()} style={styles.backBtn}> {data?.name || '详情'} setScrollTop(e.nativeEvent.contentOffset.y)} scrollEventThrottle={16} showsVerticalScrollIndicator={false} > {/* Main Goods Section */} ({ cover: item.spu.cover, name: item.spu.name, level: item.level, quantity: item.quantity, id: item.id, // Ensure IDs are passed spu: item.spu })) || []} /> {/* Bottom Text Graphic */} {/* FirstLast (Box Info & Nav) */} boxRef.current?.show()} onProductClick={(spu) => console.log(spu)} /> {/* Product List (A/B/C/D) */} { const list = data?.luckGoodsList || []; const getPId = (p: any) => String(p.id || p.spu?.id || p.spuId || ''); const targetId = getPId(product); const index = list.findIndex((p: any) => getPId(p) === targetId); console.log(`[DEBUG-NAV] Clicked ${targetId} (${product.name}). Found index: ${index}`); if (index !== -1) { router.push({ pathname: '/award-detail/swipe', params: { poolId: getSafePoolId(), index } }); } }} /> {/* Floating Buttons */} ruleRef.current?.show()}> 规则 recordRef.current?.show()}> 记录 router.push('/store')}> 仓库 {/* Lock Button */} { if (!currentBox) return; const isLocked = currentBox.lockTime && new Date(currentBox.lockTime).getTime() > Date.now(); Alert.alert('提示', isLocked ? '是否解锁盒子?' : '是否锁定盒子(锁定后他人无法购买)?', [ { text: '取消', style: 'cancel' }, { text: '确定', onPress: async () => { try { const poolId = getSafePoolId(); let success = false; if (isLocked) { success = await unlockBox(poolId, currentBox.number); } else { success = await lockBox(poolId, currentBox.number); } if (success) { Alert.alert('成功', isLocked ? '解锁成功' : '锁定成功'); loadBox(currentBox.number); // Refresh } // System handles error msg via interceptor, no need for manual alert } catch (e) { // console.error(e); // Silent error } }} ]); }}> {currentBox?.lockTime && new Date(currentBox.lockTime).getTime() > Date.now() ? '解锁' : '锁盒'} loadBox(currentBox?.number)}> 刷新 { if (!currentBox) { boxRef.current?.show(); } else { numRef.current?.show(currentBox); } }} onBuyMany={() => { if (!currentBox) { boxRef.current?.show(); } else { numRef.current?.show(currentBox); } }} /> {/* Modals */} { console.log('Success', res); loadData(); // Refresh }} /> ); }