249 lines
8.3 KiB
TypeScript
249 lines
8.3 KiB
TypeScript
import { useState, useEffect } from 'react'
|
|
import {
|
|
View,
|
|
Text,
|
|
StyleSheet,
|
|
ScrollView,
|
|
StatusBar as RNStatusBar,
|
|
Pressable,
|
|
} from 'react-native'
|
|
import { LinearGradient } from 'expo-linear-gradient'
|
|
import { StatusBar } from 'expo-status-bar'
|
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
|
import { useActivities } from '@/hooks/data/use-activities'
|
|
|
|
type MessageType = 'all' | 'notice' | 'other'
|
|
|
|
export default function MessageScreen() {
|
|
const [activeTab, setActiveTab] = useState<MessageType>('all')
|
|
const { load, loading, error, data } = useActivities()
|
|
|
|
useEffect(() => {
|
|
load({ page: 1, limit: 20, orderBy: 'createdAt', order: 'desc' })
|
|
}, [])
|
|
|
|
const activities = data?.activities || []
|
|
|
|
const filteredActivities = activities.filter((activity) => {
|
|
if (activeTab === 'all') return true
|
|
return activeTab === 'notice'
|
|
})
|
|
|
|
return (
|
|
<SafeAreaView style={styles.container} edges={['top']}>
|
|
<StatusBar style="light" />
|
|
<RNStatusBar barStyle="light-content" />
|
|
|
|
{/* 固定在顶部的标签选择器 */}
|
|
<View style={styles.segment}>
|
|
<Pressable onPress={() => setActiveTab('all')}>
|
|
{activeTab === 'all' ? (
|
|
<View style={styles.segmentTextActiveWrapper}>
|
|
<LinearGradient
|
|
colors={['#FF9966', '#FF6699', '#9966FF']}
|
|
start={{ x: 0, y: 0 }}
|
|
end={{ x: 1, y: 0 }}
|
|
style={styles.segmentTextActiveBg}
|
|
/>
|
|
<Text
|
|
style={[
|
|
styles.segmentText,
|
|
styles.segmentTextActiveText,
|
|
]}
|
|
>
|
|
全部
|
|
</Text>
|
|
</View>
|
|
) : (
|
|
<Text style={styles.segmentText}>全部</Text>
|
|
)}
|
|
</Pressable>
|
|
<Pressable onPress={() => setActiveTab('notice')}>
|
|
{activeTab === 'notice' ? (
|
|
<View style={styles.segmentTextActiveWrapper}>
|
|
<LinearGradient
|
|
colors={['#FF9966', '#FF6699', '#9966FF']}
|
|
start={{ x: 0, y: 0 }}
|
|
end={{ x: 1, y: 0 }}
|
|
style={styles.segmentTextActiveBg}
|
|
/>
|
|
<Text
|
|
style={[
|
|
styles.segmentText,
|
|
styles.segmentTextActiveText,
|
|
]}
|
|
>
|
|
活动通知
|
|
</Text>
|
|
</View>
|
|
) : (
|
|
<Text style={styles.segmentText}>活动通知</Text>
|
|
)}
|
|
</Pressable>
|
|
<Pressable onPress={() => setActiveTab('other')}>
|
|
{activeTab === 'other' ? (
|
|
<View style={styles.segmentTextActiveWrapper}>
|
|
<LinearGradient
|
|
colors={['#FF9966', '#FF6699', '#9966FF']}
|
|
start={{ x: 0, y: 0 }}
|
|
end={{ x: 1, y: 0 }}
|
|
style={styles.segmentTextActiveBg}
|
|
/>
|
|
<Text
|
|
style={[
|
|
styles.segmentText,
|
|
styles.segmentTextActiveText,
|
|
]}
|
|
>
|
|
其他
|
|
</Text>
|
|
</View>
|
|
) : (
|
|
<Text style={styles.segmentText}>其他</Text>
|
|
)}
|
|
</Pressable>
|
|
</View>
|
|
|
|
<ScrollView
|
|
style={styles.scrollView}
|
|
contentContainerStyle={styles.scrollContent}
|
|
showsVerticalScrollIndicator={false}
|
|
>
|
|
{loading ? (
|
|
<View style={styles.emptyContainer}>
|
|
<Text style={styles.emptyText}>加载中...</Text>
|
|
</View>
|
|
) : error ? (
|
|
<View style={styles.emptyContainer}>
|
|
<Text style={styles.emptyText}>加载失败</Text>
|
|
</View>
|
|
) : filteredActivities.length > 0 ? (
|
|
filteredActivities.map((activity) => (
|
|
<View key={activity.id} style={styles.cardContainer}>
|
|
<Text style={styles.cardTitle}>
|
|
{activity.title}
|
|
</Text>
|
|
<Text style={styles.cardSubtitle} numberOfLines={2}>
|
|
{activity.titleEn || activity.desc}
|
|
</Text>
|
|
|
|
<View style={styles.cardBody}>
|
|
<Text style={styles.cardBodyText}>
|
|
{activity.desc}
|
|
</Text>
|
|
</View>
|
|
|
|
<Text style={styles.cardTime}>
|
|
{new Date(activity.createdAt).toLocaleString('zh-CN', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
hour12: false,
|
|
}).replace(/\//g, '-')}
|
|
</Text>
|
|
</View>
|
|
))
|
|
) : (
|
|
<View style={styles.emptyContainer}>
|
|
<Text style={styles.emptyText}>💭</Text>
|
|
<Text style={styles.emptyText}>暂无消息</Text>
|
|
</View>
|
|
)}
|
|
</ScrollView>
|
|
</SafeAreaView>
|
|
)
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: '#090A0B',
|
|
},
|
|
scrollView: {
|
|
flex: 1,
|
|
backgroundColor: '#090A0B',
|
|
},
|
|
scrollContent: {
|
|
paddingHorizontal: 4,
|
|
paddingTop: 12,
|
|
paddingBottom: 24,
|
|
},
|
|
segment: {
|
|
flexDirection: 'row',
|
|
paddingHorizontal: 8,
|
|
paddingTop: 19,
|
|
paddingBottom: 12,
|
|
backgroundColor: '#090A0B',
|
|
gap: 16,
|
|
},
|
|
|
|
segmentText: {
|
|
fontSize: 14,
|
|
color: '#FFFFFF',
|
|
},
|
|
segmentTextActiveWrapper: {
|
|
position: 'relative',
|
|
paddingBottom: 2,
|
|
justifyContent: 'flex-end',
|
|
alignSelf: 'flex-start',
|
|
},
|
|
segmentTextActiveBg: {
|
|
position: 'absolute',
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
height: 10,
|
|
backgroundColor: '#FF9966',
|
|
},
|
|
segmentTextActiveText: {
|
|
zIndex: 1,
|
|
},
|
|
cardContainer: {
|
|
backgroundColor: '#16181B',
|
|
borderRadius: 16,
|
|
padding: 16,
|
|
marginBottom: 12,
|
|
marginHorizontal: 4,
|
|
},
|
|
cardTitle: {
|
|
color: '#FFFFFF',
|
|
fontSize: 15,
|
|
fontWeight: '600',
|
|
marginBottom: 8,
|
|
},
|
|
cardSubtitle: {
|
|
color: '#ABABAB',
|
|
fontSize: 11,
|
|
marginBottom: 16,
|
|
},
|
|
cardBody: {
|
|
backgroundColor: '#26292E',
|
|
borderRadius: 12,
|
|
height:100,
|
|
marginBottom: 12,
|
|
},
|
|
cardBodyText: {
|
|
color: '#FFFFFF',
|
|
fontSize: 12,
|
|
opacity: 0.8,
|
|
},
|
|
cardTime: {
|
|
color: '#8A8A8A',
|
|
fontSize: 10,
|
|
},
|
|
emptyContainer: {
|
|
flex: 1,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
paddingTop: 200,
|
|
},
|
|
emptyText: {
|
|
color: '#8A8A8A',
|
|
fontSize: 12,
|
|
marginTop: 16,
|
|
},
|
|
})
|