notificationDetailPage.tsx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // app/(auth)/(tabs)/(home)/notificationDetailPage.tsx
  2. import {
  3. View,
  4. Text,
  5. Pressable,
  6. Image,
  7. ScrollView,
  8. Alert,
  9. ImageBackground,
  10. ActivityIndicator,
  11. Dimensions
  12. } from 'react-native';
  13. import { SafeAreaView } from 'react-native-safe-area-context';
  14. import { router, useLocalSearchParams } from 'expo-router';
  15. import { CrossLogoSvg, PreviousPageBlackSvg } from '../../../../component/global/SVG';
  16. import { useEffect, useState } from 'react';
  17. import { chargeStationService } from '../../../../service/chargeStationService';
  18. import { formatToChineseDateTime } from '../../../../util/lib';
  19. import { useTranslation } from '../../../../util/hooks/useTranslation';
  20. const NotificationDetailPage = () => {
  21. const { t, getCurrentLanguageConfig } = useTranslation(); // 使用翻译钩子
  22. const isEn = getCurrentLanguageConfig()?.code === 'en';
  23. const screenHeight = Dimensions.get('window').height;
  24. const { promotion } = useLocalSearchParams();
  25. const promotionObj = JSON.parse(promotion as string);
  26. const [loading, setLoading] = useState(false);
  27. const [promotionImage, setPromotionImage] = useState('');
  28. const AdaptiveImage = ({ source }: { source: string }) => {
  29. const [aspectRatio, setAspectRatio] = useState(1);
  30. const [error, setError] = useState(false);
  31. const windowWidth = Dimensions.get('window').width;
  32. useEffect(() => {
  33. if (source) {
  34. // Remote image
  35. Image.getSize(
  36. source,
  37. (width, height) => {
  38. if (width && height) {
  39. setAspectRatio(width / height);
  40. setError(false);
  41. } else {
  42. setError(true);
  43. console.error('Invalid image dimensions received');
  44. }
  45. },
  46. (error) => {
  47. setError(true);
  48. console.error('Error getting image size:', error);
  49. }
  50. );
  51. } else {
  52. try {
  53. // Local image
  54. const dimensions = Image.resolveAssetSource({ uri: source });
  55. if (dimensions && dimensions.width && dimensions.height) {
  56. setAspectRatio(dimensions.width / dimensions.height);
  57. setError(false);
  58. } else {
  59. setError(true);
  60. console.error('Invalid dimensions from resolveAssetSource');
  61. }
  62. } catch (e) {
  63. setError(true);
  64. console.error('Error resolving asset source:', e);
  65. }
  66. }
  67. }, [source]);
  68. if (error) {
  69. return;
  70. }
  71. return (
  72. <Image
  73. source={{ uri: source }}
  74. style={{
  75. width: windowWidth / 1.1,
  76. aspectRatio,
  77. resizeMode: 'contain'
  78. }}
  79. />
  80. );
  81. };
  82. useEffect(() => {
  83. setLoading(true);
  84. const fetchPromotionImage = async () => {
  85. try {
  86. const promotionImage = await chargeStationService.getProcessedImageUrl(promotionObj.image_url);
  87. setPromotionImage(promotionImage);
  88. } catch (e) {
  89. } finally {
  90. setLoading(false);
  91. }
  92. };
  93. fetchPromotionImage();
  94. }, []);
  95. return (
  96. <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
  97. <ScrollView>
  98. {loading ? (
  99. <View className="items-center justify-center">
  100. <ActivityIndicator />
  101. <Text>{t('common.loading')}</Text>
  102. </View>
  103. ) : (
  104. <View style={{ minHeight: screenHeight, flex: 1 }} className="mx-[5%]">
  105. <View style={{ marginTop: 25 }}>
  106. <Pressable
  107. onPress={() => {
  108. if (router.canGoBack()) {
  109. router.back();
  110. } else {
  111. router.replace('/notificationPage');
  112. }
  113. }}
  114. hitSlop={{ top: 20, bottom: 20, left: 20, right: 20 }}
  115. >
  116. <CrossLogoSvg />
  117. </Pressable>
  118. <Text style={{ fontSize: 45, marginVertical: 25 }}>{t('notifications.charging_detail.title')}</Text>
  119. </View>
  120. <View className="space-y-2 ">
  121. <Text className="text-base lg:text-lg">{isEn?promotionObj.title_en:promotionObj.title}</Text>
  122. {promotionImage && (
  123. <View className="w-full flex items-center justify-center">
  124. <AdaptiveImage source={promotionImage} />
  125. </View>
  126. )}
  127. <Text className="text-sm">{isEn?promotionObj.text_en:promotionObj.text}</Text>
  128. <Text className="text-xs text-gray-500 pt-8 pb-4">
  129. {t('notifications.charging_detail.last_updated')}: {formatToChineseDateTime(promotionObj.updatedAt)}
  130. </Text>
  131. </View>
  132. </View>
  133. )}
  134. </ScrollView>
  135. </SafeAreaView>
  136. );
  137. };
  138. export default NotificationDetailPage;