reservationLocationPageComponent.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. import Svg, { Path, Rect } from 'react-native-svg';
  2. import * as React from 'react';
  3. import {
  4. View,
  5. Text,
  6. useWindowDimensions,
  7. StyleSheet,
  8. Image,
  9. ImageSourcePropType,
  10. Pressable
  11. } from 'react-native';
  12. import { TabView, SceneMap, TabBar } from 'react-native-tab-view';
  13. import { FlashList } from '@shopify/flash-list';
  14. import { SafeAreaView } from 'react-native-safe-area-context';
  15. import { router } from 'expo-router';
  16. import { CheckMarkLogoSvg, CrossLogoSvg } from '../global/SVG';
  17. interface TabItem {
  18. imgURL: ImageSourcePropType;
  19. date: string;
  20. time: string;
  21. chargeStationName: string;
  22. chargeStationAddress: string;
  23. distance: string;
  24. }
  25. interface TabViewComponentProps {
  26. titles: string[];
  27. tabItems: TabItem[];
  28. }
  29. const dummyTabItems: TabItem[] = [
  30. {
  31. imgURL: require('../../assets/dummyStationPicture.png'),
  32. date: '今天',
  33. time: '16:30',
  34. chargeStationName: '上環街市充電站',
  35. chargeStationAddress: '香港上環皇后大道中345號',
  36. distance: '400米'
  37. },
  38. {
  39. imgURL: require('../../assets/dummyStationPicture2.png'),
  40. date: '3月15',
  41. time: '17:45',
  42. chargeStationName: '中環IFC充電站',
  43. chargeStationAddress: '香港中環皇后大道中999號',
  44. distance: '680米'
  45. },
  46. {
  47. imgURL: require('../../assets/dummyStationPicture2.png'),
  48. date: '4月20',
  49. time: '12:30',
  50. chargeStationName: '中環IFC充電站',
  51. chargeStationAddress: '香港中環皇后大道中999號',
  52. distance: '680米'
  53. },
  54. {
  55. imgURL: require('../../assets/dummyStationPicture.png'),
  56. date: '今天',
  57. time: '16:30',
  58. chargeStationName: '上環街市充電站',
  59. chargeStationAddress: '香港上環皇后大道中345號',
  60. distance: '400米'
  61. },
  62. {
  63. imgURL: require('../../assets/dummyStationPicture.png'),
  64. date: '今天',
  65. time: '16:30',
  66. chargeStationName: '上環街市充電站',
  67. chargeStationAddress: '香港上環皇后大道中345號',
  68. distance: '400米'
  69. }
  70. ];
  71. const LocationTabComponent: React.FC<TabViewComponentProps> = ({
  72. titles,
  73. tabItems
  74. }) => {
  75. const layout = useWindowDimensions();
  76. const FirstRoute = () => (
  77. <View style={{ flex: 1, backgroundColor: 'white' }}>
  78. <FlashList
  79. data={tabItems}
  80. renderItem={({ item }) => {
  81. return (
  82. <Pressable
  83. // onPress={() => console.log('clicked')}
  84. onPress={() => router.push('resultDetailPage')}
  85. style={({ pressed }) => [
  86. styles.container,
  87. {
  88. backgroundColor: pressed
  89. ? '#e7f2f8'
  90. : '#ffffff'
  91. }
  92. ]}
  93. >
  94. <View style={styles.container}>
  95. <Image
  96. style={styles.image}
  97. source={item.imgURL}
  98. />
  99. <View style={styles.textContainer}>
  100. <Text
  101. style={{
  102. fontWeight: 400,
  103. fontSize: 18,
  104. color: '#222222'
  105. }}
  106. >
  107. {item.chargeStationName}
  108. </Text>
  109. <Text
  110. style={{
  111. fontWeight: 400,
  112. fontSize: 14,
  113. color: '#888888'
  114. }}
  115. >
  116. {item.chargeStationAddress}
  117. </Text>
  118. <View className=" flex-row space-x-2 items-center">
  119. <CheckMarkLogoSvg />
  120. <Text
  121. style={{
  122. fontWeight: 400,
  123. fontSize: 14,
  124. color: '#222222'
  125. }}
  126. >
  127. Walk-in
  128. </Text>
  129. </View>
  130. </View>
  131. <Text
  132. style={{
  133. fontWeight: 400,
  134. fontSize: 16,
  135. color: '#888888',
  136. marginTop: 22
  137. }}
  138. >
  139. {item.distance}
  140. </Text>
  141. </View>
  142. </Pressable>
  143. );
  144. }}
  145. estimatedItemSize={10}
  146. />
  147. </View>
  148. );
  149. //tab 2
  150. const SecondRoute = () => (
  151. <View style={{ flex: 1, backgroundColor: 'white' }}>
  152. <FlashList
  153. data={tabItems}
  154. renderItem={({ item }) => {
  155. return (
  156. <Pressable
  157. // onPress={() => console.log('clicked')}
  158. onPress={() => router.push('resultDetailPage')}
  159. style={({ pressed }) => [
  160. styles.container,
  161. {
  162. backgroundColor: pressed
  163. ? '#e7f2f8'
  164. : '#ffffff'
  165. }
  166. ]}
  167. >
  168. <View style={styles.container}>
  169. <Image
  170. style={styles.image}
  171. source={item.imgURL}
  172. />
  173. <View style={styles.textContainer}>
  174. <Text
  175. style={{
  176. fontWeight: 400,
  177. fontSize: 18,
  178. color: '#222222'
  179. }}
  180. >
  181. {item.chargeStationName}
  182. </Text>
  183. <Text
  184. style={{
  185. fontWeight: 400,
  186. fontSize: 14,
  187. color: '#888888'
  188. }}
  189. >
  190. {item.chargeStationAddress}
  191. </Text>
  192. <View className=" flex-row space-x-2 items-center">
  193. <CheckMarkLogoSvg />
  194. <Text
  195. style={{
  196. fontWeight: 400,
  197. fontSize: 14,
  198. color: '#222222'
  199. }}
  200. >
  201. Walk-in
  202. </Text>
  203. </View>
  204. </View>
  205. <Text
  206. style={{
  207. fontWeight: 400,
  208. fontSize: 16,
  209. color: '#888888',
  210. marginTop: 22
  211. }}
  212. >
  213. {item.distance}
  214. </Text>
  215. </View>
  216. </Pressable>
  217. );
  218. }}
  219. estimatedItemSize={10}
  220. />
  221. </View>
  222. );
  223. const renderScene = SceneMap({
  224. firstRoute: FirstRoute,
  225. secondRoute: SecondRoute
  226. });
  227. const [routes] = React.useState([
  228. { key: 'firstRoute', title: titles[0] },
  229. { key: 'secondRoute', title: titles[1] }
  230. ]);
  231. const [index, setIndex] = React.useState(0);
  232. const renderTabBar = (props: any) => (
  233. <TabBar
  234. {...props}
  235. renderLabel={({ route, focused }) => (
  236. <Text
  237. style={{
  238. color: focused ? '#025c72' : '#888888',
  239. fontWeight: focused ? '900' : 'thin',
  240. fontSize: 20
  241. }}
  242. >
  243. {route.title}
  244. </Text>
  245. )}
  246. indicatorStyle={{
  247. backgroundColor: '#025c72'
  248. }}
  249. style={{
  250. backgroundColor: 'white',
  251. borderColor: '#DBE4E8',
  252. elevation: 0,
  253. borderBottomWidth: 0.5
  254. }}
  255. />
  256. );
  257. return (
  258. <TabView
  259. navigationState={{ index, routes }}
  260. renderScene={renderScene}
  261. onIndexChange={setIndex}
  262. initialLayout={{ width: layout.width }}
  263. renderTabBar={renderTabBar}
  264. />
  265. );
  266. };
  267. const styles = StyleSheet.create({
  268. container: { flexDirection: 'row' },
  269. image: {
  270. width: 100,
  271. height: 100,
  272. marginTop: 15,
  273. marginRight: 15,
  274. borderRadius: 10
  275. },
  276. textContainer: { flexDirection: 'column', gap: 8, marginTop: 22 }
  277. });
  278. const ReservationLocationPage = () => {
  279. return (
  280. <SafeAreaView
  281. className="flex-1 bg-white"
  282. edges={['top', 'left', 'right']}
  283. >
  284. <View className="flex-1 mx-[5%] ">
  285. <View className="min-h-[250px] flex-column">
  286. <View className="flex-1 justify-center">
  287. <View className="pt-5 pl-4">
  288. <Pressable
  289. onPress={() => {
  290. if (router.canGoBack()) {
  291. router.back();
  292. } else {
  293. router.replace('/');
  294. }
  295. router.back();
  296. }}
  297. >
  298. <CrossLogoSvg />
  299. </Pressable>
  300. </View>
  301. </View>
  302. <View className="flex-1 justify-center ">
  303. <Text className="text-[50px] font-normal ">
  304. 預約地點
  305. </Text>
  306. </View>
  307. <View className="flex-1 justify-center ">
  308. <Pressable onPress={() => router.push('searchPage')}>
  309. <View
  310. style={{
  311. borderWidth: 1,
  312. padding: 24,
  313. borderRadius: 12,
  314. borderColor: '#bbbbbb',
  315. maxWidth: '100%'
  316. }}
  317. >
  318. <Text
  319. style={{ color: '#888888', fontSize: 16 }}
  320. >
  321. 搜尋充電站或地區..
  322. </Text>
  323. </View>
  324. </Pressable>
  325. </View>
  326. </View>
  327. <View className="flex-1 mt-2">
  328. <LocationTabComponent
  329. titles={['附近的充電站', '所有的充電站']}
  330. tabItems={dummyTabItems}
  331. />
  332. </View>
  333. </View>
  334. </SafeAreaView>
  335. );
  336. };
  337. export default ReservationLocationPage;