This commit is contained in:
imeepos 2025-11-12 16:55:02 +08:00
parent 12a1df8481
commit 293e7a8427
7 changed files with 64 additions and 17 deletions

View File

@ -1,19 +1,19 @@
import { PageLayout } from '@/components/bestai/layout'; import { PageLayout } from '@/components/bestai/layout';
import { getTemplateGenerations, TemplateGeneration } from '@/lib/api/template-generations';
import { router } from 'expo-router';
import { StatusBar } from 'expo-status-bar'; import { StatusBar } from 'expo-status-bar';
import React, { useState, useEffect, useCallback, useMemo } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { import {
ActivityIndicator, ActivityIndicator,
Image, Image,
Platform,
RefreshControl,
ScrollView, ScrollView,
StyleSheet, StyleSheet,
Text, Text,
View, TouchableOpacity,
RefreshControl, View
Platform,
TouchableOpacity
} from 'react-native'; } from 'react-native';
import { getTemplateGenerations, TemplateGeneration } from '@/lib/api/template-generations';
import { router } from 'expo-router';
const LAYOUT_CONFIG = { const LAYOUT_CONFIG = {
VIDEO_HEIGHT: 280, VIDEO_HEIGHT: 280,
@ -392,8 +392,8 @@ export default function HistoryScreen() {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
scrollContent: { scrollContent: {
paddingTop: 24, paddingTop: 14,
paddingBottom: 48, paddingBottom: 14,
}, },
heading: { heading: {
fontSize: 24, fontSize: 24,

View File

@ -5,7 +5,6 @@ import { useRouter } from 'expo-router';
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { import {
ActivityIndicator, ActivityIndicator,
Alert,
ScrollView, ScrollView,
StyleSheet, StyleSheet,
Text, Text,
@ -14,6 +13,7 @@ import {
View View
} from 'react-native'; } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Alert } from '@/utils/alert';
type PurchaseTab = 'subscription' | 'pack'; type PurchaseTab = 'subscription' | 'pack';

View File

@ -19,7 +19,8 @@ export const Header = memo(function Header({ title = 'BESTAI' }: HeaderProps) {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
alignItems: 'center', alignItems: 'center',
marginBottom: 28, marginBottom: 14,
marginTop: 14
}, },
logo: { logo: {
width: 89, width: 89,

View File

@ -130,7 +130,8 @@ const styles = {
flexDirection: 'row' as const, flexDirection: 'row' as const,
alignItems: 'center' as const, alignItems: 'center' as const,
justifyContent: 'space-between' as const, justifyContent: 'space-between' as const,
marginBottom: 28, marginBottom: 14,
marginTop: 14
}, },
settingsButton: { settingsButton: {
width: 44, width: 44,

View File

@ -1,13 +1,14 @@
import React, { useState, useMemo } from 'react'; import React, { useMemo, useState } from 'react';
import { View, useWindowDimensions, type ImageSourcePropType, StyleSheet } from 'react-native'; import { StyleSheet, View, useWindowDimensions, type ImageSourcePropType } from 'react-native';
import { PageLayout } from '@/components/bestai/layout'; import { PageLayout } from '@/components/bestai/layout';
import { useAuth } from '@/hooks/use-auth'; import { useAuth } from '@/hooks/use-auth';
import { useBalance } from '@/hooks/use-balance'; import { useBalance } from '@/hooks/use-balance';
import { useProfileData } from '@/hooks/use-profile-data'; import { useProfileData } from '@/hooks/use-profile-data';
import { createStats, deriveAvatarSource, deriveDisplayName } from '@/utils/profile-data';
import { PROFILE_THEME } from '@/theme/profile'; import { PROFILE_THEME } from '@/theme/profile';
import { createStats, deriveAvatarSource, deriveDisplayName } from '@/utils/profile-data';
import { ContentGallery } from './content-gallery'; import { ContentGallery } from './content-gallery';
import { ContentSkeleton } from './content-skeleton';
import { ContentTabs } from './content-tabs'; import { ContentTabs } from './content-tabs';
import { Divider } from './divider'; import { Divider } from './divider';
import { ProfileEditModal } from './profile-edit-modal'; import { ProfileEditModal } from './profile-edit-modal';
@ -16,7 +17,6 @@ import { ProfileErrorState } from './profile-error-state';
import { ProfileHeader } from './profile-header'; import { ProfileHeader } from './profile-header';
import { ProfileIdentity } from './profile-identity'; import { ProfileIdentity } from './profile-identity';
import { ProfileLoadingState } from './profile-loading-state'; import { ProfileLoadingState } from './profile-loading-state';
import { ContentSkeleton } from './content-skeleton';
type TabKey = 'all' | 'image' | 'video'; type TabKey = 'all' | 'image' | 'video';
type BillingMode = 'monthly' | 'lifetime'; type BillingMode = 'monthly' | 'lifetime';

View File

@ -1,8 +1,9 @@
import { useState, useEffect, useRef, useMemo } from 'react'; import { useState, useEffect, useRef, useMemo } from 'react';
import { Alert, Linking } from 'react-native'; import { Linking } from 'react-native';
import { useRouter } from 'expo-router'; import { useRouter } from 'expo-router';
import { authClient, useSession } from '@/lib/auth/client'; import { authClient, useSession } from '@/lib/auth/client';
import { getStripePlans, getPlanNames } from '@/lib/api/pricing'; import { getStripePlans, getPlanNames } from '@/lib/api/pricing';
import { Alert } from '@/utils/alert';
import type { import type {
StripePricingTableResponse, StripePricingTableResponse,
CreditPlan, CreditPlan,

44
utils/alert.ts Normal file
View File

@ -0,0 +1,44 @@
import { Alert as RNAlert, Platform } from 'react-native';
interface AlertButton {
text: string;
onPress?: () => void;
style?: 'default' | 'cancel' | 'destructive';
}
class PlatformAlert {
alert(title: string, message?: string, buttons?: AlertButton[]) {
if (Platform.OS === 'web') {
this.webAlert(title, message, buttons);
} else {
RNAlert.alert(title, message, buttons);
}
}
private webAlert(title: string, message?: string, buttons?: AlertButton[]) {
const fullMessage = message ? `${title}\n\n${message}` : title;
if (!buttons || buttons.length === 0) {
window.alert(fullMessage);
return;
}
if (buttons.length === 1) {
window.alert(fullMessage);
buttons[0].onPress?.();
return;
}
const confirmed = window.confirm(fullMessage);
if (confirmed) {
const confirmButton = buttons.find(btn => btn.style !== 'cancel');
confirmButton?.onPress?.();
} else {
const cancelButton = buttons.find(btn => btn.style === 'cancel');
cancelButton?.onPress?.();
}
}
}
export const Alert = new PlatformAlert();