notificationDetailPage.tsx 5.3 KB

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