import { useState, useEffect, useCallback } from 'react' import { View, Text, StyleSheet, ScrollView, Dimensions, Pressable, StatusBar as RNStatusBar, } from 'react-native' import { StatusBar } from 'expo-status-bar' import { SafeAreaView } from 'react-native-safe-area-context' import { Image } from 'expo-image' import { useRouter } from 'expo-router' import { useTranslation } from 'react-i18next' import { PointsIcon, SearchIcon, SettingsIcon } from '@/components/icon' import EditProfileDrawer from '@/components/drawer/EditProfileDrawer' import Dropdown from '@/components/ui/dropdown' import Toast from '@/components/ui/Toast' import { signOut } from '@/lib/auth' import { useTemplateGenerations, type TemplateGeneration } from '@/hooks' import { MySkeleton } from '@/components/skeleton/MySkeleton' import { useSession } from '@/lib/auth' const { width: screenWidth } = Dimensions.get('window') const GALLERY_GAP = 2 const GALLERY_HORIZONTAL_PADDING = 0 const GALLERY_ITEM_SIZE = Math.floor( (screenWidth - GALLERY_HORIZONTAL_PADDING * 2 - GALLERY_GAP * 2) / 3 ) // 获取作品封面图 const getCoverUrl = (item: TemplateGeneration) => item.resultUrl?.[0] || item.template?.coverImageUrl export default function My() { const router = useRouter() const { t, i18n } = useTranslation() const [editDrawerVisible, setEditDrawerVisible] = useState(false) // 获取当前登录用户信息 const { data: session } = useSession() const userName = session?.user?.name || session?.user?.username || '用户' const [profileName, setProfileName] = useState(userName) // 当 session 变化时更新用户名 useEffect(() => { if (session?.user?.name || session?.user?.username) { setProfileName(session?.user?.name || session?.user?.username || '用户') } }, [session]) // 使用 useTemplateGenerations hook 获取用户作品列表 const { generations, loading, error, execute: loadGenerations, refetch, } = useTemplateGenerations() // 初始化加载作品列表 useEffect(() => { loadGenerations({ page: 1, limit: 50 }) }, []) // 处理设置菜单选择 const handleSettingsSelect = async (value: string) => { if (value === 'changePassword') { router.push('/changePassword' as any) } else if (value === 'language') { // 切换语言 const newLang = i18n.language === 'zh-CN' ? 'en-US' : 'zh-CN' i18n.changeLanguage(newLang) } else if (value === 'logout') { // 退出登录 console.log('🚪 点击退出登录') const confirmText = i18n.language === 'zh-CN' ? '确定' : 'OK' const cancelText = i18n.language === 'zh-CN' ? '取消' : 'Cancel' const message = i18n.language === 'zh-CN' ? '确定要退出登录吗?' : 'Are you sure you want to logout?' Toast.showActionSheet({ itemList: [message, confirmText, cancelText] }).then(async (index) => { // index 1 是确定按钮 if (index === 1) { console.log('🚪 开始执行退出登录') try { Toast.showLoading({ title: i18n.language === 'zh-CN' ? '退出中...' : 'Logging out...' }) // 调用 better-auth 的 signOut 方法 await signOut() Toast.hideLoading() console.log('✅ 退出登录成功,跳转到登录页') Toast.show(i18n.language === 'zh-CN' ? '退出登录成功' : 'Logged out successfully') // 跳转到登录页面(注意:路由是 /auth 不是 /login) router.replace('/auth') } catch (error) { Toast.hideLoading() console.error('❌ 退出登录失败:', error) Toast.show(i18n.language === 'zh-CN' ? '退出登录失败,请稍后重试' : 'Failed to logout, please try again later') } } }).catch(() => { console.log('❌ 取消退出登录') }) } } // 设置菜单选项 const getLanguageLabel = () => { if (i18n.language === 'zh-CN') { return t('my.languageSwitch') } else { return t('my.languageSwitchEn') } } const settingsOptions = [ { label: t('my.changePassword'), value: 'changePassword' }, { label: getLanguageLabel(), value: 'language' }, { label: t('my.logout'), value: 'logout' }, ] return ( {/* 顶部积分与设置 */} router.push('/membership' as any)} > 60 handleSettingsSelect(value)} renderTrigger={(selectedOption, isOpen, toggle) => ( )} dropdownStyle={{ minWidth: 160, right: 10, backgroundColor: '#2A2A2A80', }} /> {/* 个人信息区 */} {profileName} ID {session?.user?.id?.slice(0, 8) || '--------'} setEditDrawerVisible(true)} > {t('my.editProfile')} {/* "生成作品" 标题行 */} {t('my.generatedWorks')} router.push('/worksList' as any)} > {/* 作品九宫格 */} {loading ? ( ) : ( {generations.map((item, index) => ( { if (item.status === 'completed') { router.push({ pathname: '/generationRecord' as any, params: { id: item.id }, }) } }} disabled={item.status !== 'completed'} > {/* 遮罩:非完成状态 */} {item.status !== 'completed' && ( )} {/* 数量角标:已完成且有结果 */} {item.status === 'completed' && (item.resultUrl?.length || 0) > 0 && ( {item.resultUrl?.length || 1} )} {/* 状态角标 */} {item.status === 'running' && ( {t('my.generating')} )} {item.status === 'pending' && ( {t('my.queuing')} )} ))} {/* 空状态提示 */} {!loading && generations.length === 0 && ( {t('my.noWorks')} )} )} {/* 编辑资料抽屉 */} setEditDrawerVisible(false)} initialName={profileName} initialAvatar={session?.user?.image} onSave={(data) => { setProfileName(data.name) }} /> ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#090A0B', }, topBar: { paddingHorizontal: GALLERY_HORIZONTAL_PADDING, paddingTop: 19, paddingRight: 16, flexDirection: 'row', justifyContent: 'flex-end', backgroundColor: '#090A0B', gap: 12, }, pointsPill: { flexDirection: 'row', alignItems: 'center', gap: 1, paddingHorizontal: 10, paddingVertical: 4, borderRadius: 100, backgroundColor: '#1C1E22', }, pointsPillText: { color: '#FFCF00', fontSize: 12, fontWeight: '600', }, scrollView: { flex: 1, backgroundColor: '#090A0B', }, scrollContent: { backgroundColor: '#090A0B', paddingHorizontal: GALLERY_HORIZONTAL_PADDING, }, profileSection: { flexDirection: 'row', alignItems: 'center', paddingLeft: 16, paddingRight: 16, marginTop: 20, marginBottom: 32, backgroundColor: '#090A0B', }, avatar: { width: 64, height: 64, borderRadius: 32, overflow: 'hidden', marginRight: 16, }, profileInfo: { flex: 1, }, profileName: { color: '#F5F5F5', fontSize: 18, fontWeight: '600', marginBottom: 4, }, profileSubTitle: { color: '#FFFFFF', fontSize: 12, opacity: 0.7, }, editButton: { paddingHorizontal: 8, paddingVertical: 6, borderRadius: 6, backgroundColor: '#1C1E22', }, editButtonText: { color: '#FFFFFF', fontSize: 12, }, sectionHeader: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12, marginHorizontal: 12, backgroundColor: '#090A0B', }, sectionTitle: { color: '#FFFFFF', fontSize: 14, fontWeight: '600', }, sectionMoreButton: { width: 20, height: 20, alignItems: 'center', justifyContent: 'center', }, galleryGrid: { flexDirection: 'row', flexWrap: 'wrap', marginBottom: 10, }, galleryItem: { width: GALLERY_ITEM_SIZE, aspectRatio: 1, overflow: 'hidden', backgroundColor: '#1C1E22', position: 'relative', }, galleryItemMarginRight: { marginRight: GALLERY_GAP, }, galleryItemMarginBottom: { marginBottom: GALLERY_GAP, }, galleryImage: { width: '100%', height: undefined, aspectRatio: 1, }, generatingOverlay: { ...StyleSheet.absoluteFillObject, backgroundColor: '#00000080', }, counterBadge: { position: 'absolute', right: 8, bottom: 8, paddingHorizontal: 10, paddingVertical: 1, borderRadius: 6, backgroundColor: '#16181B1A', }, counterText: { color: '#FFFFFF', fontSize: 10, fontWeight: '600', }, generatingBadge: { position: 'absolute', left: 8, bottom: 8, }, generatingBadgeText: { color: '#F5F5F5', fontSize: 9, fontWeight: '500', }, emptyState: { width: '100%', alignItems: 'center', justifyContent: 'center', paddingVertical: 60, }, emptyStateText: { color: '#FFFFFF80', fontSize: 14, }, })