BottomSiteCard.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /**
  2. * 地图底部充电站信息组件
  3. * @邠心vbe on 2022/12/23
  4. */
  5. import React, { useEffect, useState } from 'react';
  6. import { Pressable, StyleSheet, View, Text } from 'react-native';
  7. import { ElevationObject } from '../../../components/Button';
  8. import utils from '../../../utils/utils';
  9. import { ChargeStyle } from '../../charge/Charging';
  10. import { PageList } from '../../Router';
  11. import ConnectType, { ConnectTypeV2 } from '../../search/ConnectType';
  12. import app from '../../../../app.json';
  13. import TextView from '../../../components/TextView';
  14. import BottomModal from '../../../components/BottomModal';
  15. import SiteLabelView from '../../../components/SiteLabelView';
  16. import VbeSkeleton from '../../../components/VbeSkeleton';
  17. export const BottomSiteCard = ({
  18. visible=false,
  19. stationInfo = {},
  20. onFavorite,
  21. onClose
  22. }) => {
  23. const [loading, showDialog] = useState(true);
  24. useEffect(() => {
  25. if (stationInfo.id) {
  26. showDialog(false)
  27. }
  28. }, [stationInfo]);
  29. useEffect(() => {
  30. showDialog(true);
  31. }, [visible]);
  32. const getAvailable = (type) => {
  33. const all = stationInfo.allConnector;
  34. if (all) {
  35. if (type == 'box') {
  36. return all.boxAvailable + '/' + all.boxAll;
  37. } else {
  38. return all.available + '/' + all.all;
  39. }
  40. } else {
  41. return '0/0';
  42. }
  43. }
  44. const getOperatingHours = () => {
  45. if (stationInfo.endlessService) {
  46. return "24/7";
  47. } else if (stationInfo.operatingHours) {
  48. return stationInfo.operatingHours;
  49. } else {
  50. return $t('charging.toBeUpdated');
  51. }
  52. }
  53. const getParkingFee = () => {
  54. if (stationInfo.parkingFeeFree) {
  55. return $t('charging.free');
  56. } else if (stationInfo.parkingFee) {
  57. return stationInfo.parkingFee;
  58. } else {
  59. return $t('charging.toBeUpdated');
  60. }
  61. }
  62. const toChargePage = () => {
  63. onClose();
  64. if (stationInfo.upcoming) {
  65. toastShort($t("home.upcoming"))
  66. } else {
  67. utils.toChargeDetailPage(stationInfo.id, 'view', PageList.home);
  68. //startPage(PageList.chargeDetailPage, {stationInfo: stationInfo, action: 'view', from: PageList.home});
  69. }
  70. }
  71. return (
  72. <BottomModal
  73. visible={visible}
  74. onHide={() => {
  75. onClose()
  76. }}
  77. backdropOpacity={0}
  78. contentStyle={styles.bottomModal}>
  79. { loading
  80. ? <View style={styles.stationBarView}>
  81. <View style={ui.flex}>
  82. <VbeSkeleton
  83. style={ui.flex1}
  84. layout={[
  85. {width: '80%', height: 20},
  86. {width: '100%', height: 15, marginTop: 16},
  87. {width: '60%', height: 15, marginTop: 4}
  88. ]}
  89. animationDirection={"horizontalRight"}
  90. />
  91. </View>
  92. <EndView/>
  93. <View style={ui.flex}>
  94. <VbeSkeleton
  95. style={[ui.flexc, ui.flex1]}
  96. viewStyle={ui.flex1}
  97. layout={[
  98. {width: '16%', height: 15, marginRight: 8, borderRadius: 30},
  99. {width: '16%', height: 15, marginRight: 8, borderRadius: 30},
  100. {width: '16%', height: 15, marginRight: 8, borderRadius: 30},
  101. {width: '16%', height: 15, borderRadius: 30}
  102. ]}
  103. animationDirection={"horizontalRight"}
  104. />
  105. </View>
  106. <EndView/>
  107. <View style={ui.flex}>
  108. <VbeSkeleton
  109. style={[ui.flexc, ui.flex1]}
  110. viewStyle={ui.flex1}
  111. layout={[
  112. {width: '20%', height: 25, marginRight: 12, borderRadius: 30},
  113. {width: '20%', height: 25, marginRight: 12, borderRadius: 30},
  114. {width: '20%', height: 25, marginRight: 12, borderRadius: 30}
  115. ]}
  116. animationDirection={"horizontalRight"}
  117. />
  118. </View>
  119. </View>
  120. : <View style={styles.stationBarView}>
  121. <View style={ui.flexc}>
  122. <TextView
  123. ellipsizeMode='tail'
  124. numberOfLines={1}
  125. style={styles.stationTitle}>{stationInfo.name}</TextView>
  126. <Pressable
  127. style={styles.closeIcon}
  128. android_ripple={rippleLess}
  129. onPress={onClose}>
  130. <MaterialCommunityIcons
  131. name="close"
  132. size={22}
  133. color={textSecondary}/>
  134. </Pressable>
  135. </View>
  136. <TextView
  137. style={styles.stationAddress}
  138. ellipsizeMode='tail'
  139. numberOfLines={3}>{stationInfo.address}</TextView>
  140. <View style={ui.flexc}>
  141. <TextView style={styles.siteTypes}>{stationInfo.siteType}</TextView>
  142. { (stationInfo.allConnector && stationInfo.allConnector.available > 0) &&
  143. <TextView style={styles.stationAvailable}>
  144. <MaterialCommunityIcons
  145. name="circle"
  146. size={10}
  147. color={colorAccent}/>
  148. <Text> </Text>
  149. {$t("charging.statusAvailable")}
  150. </TextView>
  151. }
  152. <ConnectTypeV2 {...stationInfo?.acConnector}/>
  153. <ConnectTypeV2 {...stationInfo?.dcConnector}/>
  154. </View>
  155. <View style={styles.infoDetailsView}>
  156. <View style={ui.flex1}>
  157. <TextView style={styles.infoTitle}>{$t("charging.operatingHours")}</TextView>
  158. <View style={styles.infoView}>
  159. <TextView style={styles.infoText}>{getOperatingHours()}</TextView>
  160. </View>
  161. </View>
  162. <View style={{width: 4}}></View>
  163. <View style={ui.flex1}>
  164. <TextView style={styles.infoTitle}>{$t("charging.parkingFees")}</TextView>
  165. <View style={styles.infoView}>
  166. <TextView style={styles.infoText}>{getParkingFee()}</TextView>
  167. </View>
  168. </View>
  169. <View style={{width: 4}}></View>
  170. <View style={ui.flex1}>
  171. <TextView style={styles.infoTitle}>{$t("charging.additionalInfo")}</TextView>
  172. <View style={styles.infoView}>
  173. <TextView style={styles.infoText}>{stationInfo?.additionalNotes}</TextView>
  174. </View>
  175. </View>
  176. </View>
  177. <EndView half/>
  178. <View style={ui.flexc}>
  179. { stationInfo.upcoming
  180. ? <View style={[ui.center, $margin(0, 8)]}>
  181. <MaterialIcons
  182. name="upcoming"
  183. size={42}
  184. color={colorAccent}
  185. style={styles.upcomingIcon} />
  186. <TextView style={styles.upcomingText}>{$t("home.upcoming")}</TextView>
  187. </View>
  188. : <>
  189. <Pressable
  190. style={styles.directIconView}
  191. onPress={() => {
  192. utils.directMaps(stationInfo.latitude, stationInfo.longitude, stationInfo.address);
  193. }}>
  194. <MaterialCommunityIcons
  195. name="directions"
  196. size={20}
  197. color={textPrimary}/>
  198. <TextView style={styles.directText}>Directions</TextView>
  199. </Pressable>
  200. { app.modules.bookmarks &&
  201. <Pressable
  202. style={[styles.directIconView, stationInfo.favorite ? styles.bookmarked : {}]}
  203. onPress={onFavorite}>
  204. <MaterialIcons
  205. name="star"
  206. size={20}
  207. color={stationInfo.favorite ? textLight : textPrimary}/>
  208. <TextView style={[styles.directText, stationInfo.favorite ? styles.bookmarked : {}]}>
  209. {stationInfo.favorite ? "Saved" : "Save"}
  210. </TextView>
  211. </Pressable>
  212. }
  213. {/* <Pressable
  214. style={styles.directIconView}
  215. onPress={() => {
  216. startPage(PageList.scanqr, {actionDetail: true});
  217. }}>
  218. <MaterialCommunityIcons
  219. name="qrcode-scan"
  220. size={12}
  221. color={textPrimary}
  222. style={$padding(3)}/>
  223. <TextView style={styles.directText}>Scan</TextView>
  224. </Pressable> */}
  225. <Pressable
  226. style={styles.directIconView}
  227. onPress={() => toChargePage()}>
  228. <MaterialCommunityIcons
  229. name="information-variant"
  230. size={20}
  231. color={textPrimary}/>
  232. <TextView style={styles.directText}>More Info</TextView>
  233. </Pressable>
  234. </> }
  235. </View>
  236. {/* stationInfo?.labels?.length > 0 &&
  237. <View style={styles.siteLabelsView}>
  238. <Image
  239. style={styles.labelIcon}
  240. source={require('../../../images/maps/ic_marker_additional.png')}/>
  241. { stationInfo.labels.map((item, index) =>
  242. <SiteLabelView key={index} {...item}/>
  243. )}
  244. </View>
  245. */}
  246. </View>
  247. }
  248. </BottomModal>
  249. )
  250. }
  251. const styles = StyleSheet.create({
  252. bottomModal: {
  253. backgroundColor: pageBackground
  254. },
  255. stationBarView: {
  256. padding: 16
  257. },
  258. stationBarPresed: {
  259. backgroundColor: "#F6F6F6",
  260. ...ElevationObject(5)
  261. },
  262. stationInfo: {
  263. flex: 1,
  264. height: 45,
  265. paddingLeft: 4,
  266. paddingRight: 8,
  267. justifyContent: 'space-around'
  268. },
  269. stationTitle: {
  270. flex: 1,
  271. color: textPrimary,
  272. fontSize: 24,
  273. fontWeight: 'bold',
  274. paddingBottom: 4
  275. },
  276. stationAddress: {
  277. color: textSecondary,
  278. fontSize: 14,
  279. paddingTop: 6,
  280. paddingBottom: 8
  281. },
  282. siteTypes: {
  283. color: textLight,
  284. height: 20,
  285. fontSize: 12,
  286. marginRight: 6,
  287. borderRadius: 30,
  288. ...$padding(0, 10),
  289. backgroundColor: textPrimary
  290. },
  291. stationAvailable: {
  292. color: textPrimary,
  293. height: 20,
  294. fontSize: 12,
  295. marginRight: 6,
  296. borderRadius: 30,
  297. borderWidth: 1,
  298. borderColor: colorAccent,
  299. ...$padding(0, 8, 0, 4)
  300. },
  301. directView: {
  302. zIndex: 1,
  303. height: 45,
  304. marginLeft: 8,
  305. marginRight: 4,
  306. alignItems: 'center',
  307. justifyContent: 'space-between'
  308. },
  309. distanceText: {
  310. color: textPrimary,
  311. fontSize: 12,
  312. },
  313. directIconView: {
  314. zIndex: 1,
  315. height: 32,
  316. marginRight: 10,
  317. borderWidth: 1,
  318. borderRadius: 30,
  319. borderColor: textPrimary,
  320. alignItems: 'center',
  321. flexDirection: 'row',
  322. justifyContent: 'center',
  323. ...$padding(2, 10, 2, 6)
  324. },
  325. bookmarked: {
  326. color: textLight,
  327. borderColor: colorAccent,
  328. backgroundColor: colorAccent
  329. },
  330. directText: {
  331. color: textPrimary,
  332. fontSize: 14,
  333. paddingLeft: 4
  334. },
  335. connectView: {
  336. flex: 1,
  337. paddingTop: 12,
  338. paddingBottom: 12,
  339. alignItems: 'center',
  340. flexDirection: 'row'
  341. },
  342. divideLine: {
  343. height: 1,
  344. backgroundColor: '#AEAEAE'
  345. },
  346. infoDetailsView: {
  347. paddingTop: 8,
  348. flexDirection: 'row'
  349. },
  350. infoTitle: {
  351. color: textPrimary,
  352. fontSize: 14,
  353. //fontWeight: 'bold',
  354. ...$padding(8, 0, 8)
  355. },
  356. infoView: {
  357. paddingBottom: 8
  358. },
  359. infoText: {
  360. color: textCancel,
  361. fontSize: 12
  362. },
  363. closeIcon: {
  364. width: 30,
  365. height: 30,
  366. marginTop: -16,
  367. marginRight: -8,
  368. alignItems: 'center',
  369. justifyContent: 'center'
  370. },
  371. siteLabelsView: {
  372. marginBottom: 5,
  373. flexWrap: 'wrap',
  374. alignItems: 'center',
  375. flexDirection: 'row'
  376. },
  377. labelIcon: {
  378. width: 16,
  379. height: 16,
  380. marginRight: 6
  381. },
  382. upcomingIcon: {
  383. marginLeft: 8,
  384. opacity: .3
  385. },
  386. upcomingText: {
  387. color: colorAccent,
  388. fontSize: 10,
  389. opacity: .3,
  390. marginLeft: 8,
  391. marginTop: -3
  392. }
  393. })