Clock.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. import { View, Text } from "@tarojs/components";
  2. import './Clock.scss'
  3. import ClockNew from "./ClockNew";
  4. import { useEffect, useState } from "react";
  5. import Taro, { useShareAppMessage } from "@tarojs/taro";
  6. import { useDispatch, useSelector } from "react-redux";
  7. import { getInfoSuccess } from "@/store/user";
  8. import { useTranslation } from "react-i18next";
  9. import { MainColorType } from "@/context/themes/color";
  10. import { IconMap, IconStreak } from "@/components/basic/Icons";
  11. import { getScenario, getThemeColor } from "@/features/health/hooks/health_hooks";
  12. import Streak from "@/features/health/Streak";
  13. import Calendar from "@/features/health/calendar";
  14. import HeaderCircadian from "@/features/health/HeaderCircadian";
  15. import { rpxToPx } from "@/utils/tools";
  16. import AddLabel from "@/_health/components/add_label";
  17. import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
  18. import showAlert from "@/components/basic/Alert";
  19. import { setTitle } from "@/store/health";
  20. import { globalSetting } from "@/services/common";
  21. let useNavigation;
  22. if (process.env.TARO_ENV == 'rn') {
  23. useNavigation = require("@react-navigation/native").useNavigation
  24. }
  25. let scrollTop = 0
  26. export default function Clock() {
  27. const dispatch = useDispatch();
  28. const [loaded, setLoaded] = useState(false)
  29. const { t } = useTranslation()
  30. const health = useSelector((state: any) => state.health);
  31. const user = useSelector((state: any) => state.user);
  32. const [showCalendar, setShowCalendar] = useState(false)
  33. const [showStreak, setShowStreak] = useState(true)
  34. const systemInfo: any = Taro.getWindowInfo ? Taro.getWindowInfo() : Taro.getSystemInfoSync();
  35. const navigationBarHeight = systemInfo.statusBarHeight + 44;
  36. const [showModal, setShowModal] = useState(false)
  37. const [labels, setLabels] = useState<any>([])
  38. let navigation;
  39. if (useNavigation) {
  40. navigation = useNavigation()
  41. }
  42. if (process.env.TARO_ENV == 'weapp') {
  43. useShareAppMessage((e) => {
  44. return {
  45. title: t('feature.track_time_duration.common.share_title'),
  46. path: 'pages/clock/Clock'
  47. }
  48. })
  49. }
  50. global.showIndexAddActive = (array) => {
  51. setLabels(array)
  52. setShowModal(true)
  53. }
  54. useEffect(() => {
  55. if (navigation) {
  56. navigation.setOptions({
  57. headerTitle: '',
  58. });
  59. }
  60. dispatch(setTitle(''))
  61. global.memberAlert = false;
  62. if (process.env.TARO_ENV == 'weapp') {
  63. loadWXCache()
  64. }
  65. else {
  66. loadRNCache()
  67. }
  68. getSetting()
  69. }, [])
  70. function getSetting() {
  71. globalSetting({
  72. keys: 'mp_status'
  73. }).then(res => {
  74. if ((res as any).data && (res as any).data.length > 0 && (res as any).data[0].value.status == 'PENDING') {
  75. global.allowShare = false
  76. }
  77. else {
  78. global.allowShare = true
  79. }
  80. })
  81. }
  82. function loadWXCache() {
  83. var gps = Taro.getStorageSync('gps')
  84. if (gps) {
  85. global.locationDetail = JSON.parse(gps)
  86. }
  87. global.memberAlert = Taro.getStorageSync('memberAlert') || false
  88. var userData = Taro.getStorageSync('userData')
  89. if (userData) {
  90. console.log('load user cache')
  91. dispatch(getInfoSuccess(JSON.parse(userData)));
  92. }
  93. setLoaded(true)
  94. }
  95. async function loadRNCache() {
  96. var showDayRing = await getStorage('showDayRing') || false;
  97. var showNightRing = await getStorage('showNightRing') || false;
  98. global.memberAlert = await getStorage('memberAlert') || false
  99. var gps = await getStorage('gps')
  100. if (gps) {
  101. global.locationDetail = JSON.parse(gps)
  102. }
  103. var userData = await getStorage('userData')
  104. console.log(userData)
  105. if (userData) {
  106. dispatch(getInfoSuccess(JSON.parse(userData)));
  107. }
  108. setLoaded(true)
  109. }
  110. async function getStorage(key: string) {
  111. try {
  112. const res = await Taro.getStorage({ key });
  113. return res.data;
  114. } catch {
  115. return '';
  116. }
  117. }
  118. function getStreakCount() {
  119. const scenario = getScenario(health.windows, health.mode)
  120. return scenario.current_streak && scenario.current_streak.days
  121. }
  122. function getStreakDesc() {
  123. switch (health.mode) {
  124. case 'FAST':
  125. return t('health.faststreak')
  126. case 'EAT':
  127. return t('health.eatstreak')
  128. case 'SLEEP':
  129. return t('health.sleepstreak')
  130. case 'ACTIVE':
  131. return t('health.activestreak')
  132. }
  133. return ''
  134. }
  135. function haveStreaks() {
  136. if (user.isLogin && health.windows && health.mode.length > 0) {
  137. const scenario = getScenario(health.windows, health.mode)
  138. if (scenario.current_streak) {
  139. return true
  140. }
  141. }
  142. return false
  143. }
  144. function steakIcon() {
  145. if (!haveStreaks()) return <View />
  146. if (showCalendar) {
  147. return <View className="navi-streak"
  148. onClick={() => {
  149. setShowCalendar(false)
  150. }}
  151. style={{ height: 44, marginTop: systemInfo.statusBarHeight, }}>
  152. <View style={{
  153. zIndex: 1,
  154. height: rpxToPx(64),
  155. display: 'flex',
  156. flexDirection: 'row',
  157. alignItems: 'center',
  158. backgroundColor: getThemeColor(health.mode),
  159. borderRadius: rpxToPx(64),
  160. paddingRight: rpxToPx(24)
  161. }} onClick={() => {
  162. setShowCalendar(false)
  163. }}>
  164. <View style={{ width: rpxToPx(16) }} />
  165. <IconStreak color='#fff' width={20} full="#fff" />
  166. <View style={{ width: rpxToPx(4) }} />
  167. <Text className="h30 bold" style={{ color: '#fff' }}>{getStreakDesc()}</Text>
  168. </View>
  169. </View>
  170. }
  171. else {
  172. return <View className="navi-streak"
  173. onClick={() => {
  174. setShowCalendar(true)
  175. }}
  176. style={{ height: 44, marginTop: systemInfo.statusBarHeight, }}>
  177. <View style={{ width: rpxToPx(16) }} />
  178. <IconStreak color='#000' width={20} full="transparent" />
  179. <View style={{ width: rpxToPx(4) }} />
  180. <Text className="h34 bold" style={{ color: '#000' }}>{getStreakCount()}</Text>
  181. </View>
  182. }
  183. }
  184. function getCity() {
  185. var city = ''
  186. var scenario = getScenario(health.windows, health.mode)
  187. if (scenario.extra.address) {
  188. if (scenario.extra.address.city.length > 0) {
  189. city = scenario.extra.address.city
  190. }
  191. else if (scenario.extra.address.province.length > 0) {
  192. city = scenario.extra.address.province
  193. }
  194. else if (scenario.extra.address.country.length > 0) {
  195. city = scenario.extra.address.country
  196. }
  197. else {
  198. city = `${Math.abs(parseInt(scenario.extra.lat))}°${parseInt(scenario.extra.lat) < 0 ? 'S' : 'N'} ${Math.abs(parseInt(scenario.extra.lng))}°${parseInt(scenario.extra.lng) < 0 ? 'W' : 'E'}`
  199. // city = t('feature.track_time_duration.third_ring.unknown')
  200. }
  201. }
  202. else {
  203. city = `${Math.abs(parseInt(scenario.extra.lat))}°${parseInt(scenario.extra.lat) < 0 ? 'S' : 'N'} ${Math.abs(parseInt(scenario.extra.lng))}°${parseInt(scenario.extra.lng) < 0 ? 'W' : 'E'}`//t('feature.track_time_duration.third_ring.unknown')
  204. }
  205. return city
  206. }
  207. function locationIcon() {
  208. if (!health.windows || !user.isLogin) return null
  209. var scenario = getScenario(health.windows, health.mode)
  210. if ((health.mode == 'DAY' || health.mode == 'NIGHT') && scenario.extra.choose_location) {
  211. return <View className="navi-streak"
  212. onClick={() => {
  213. global.chooseLocation()
  214. }}
  215. style={{ height: 44, marginTop: systemInfo.statusBarHeight, }}>
  216. <View style={{ width: rpxToPx(16) }} />
  217. <IconMap color='#000' width={20} />
  218. <View style={{ width: rpxToPx(4) }} />
  219. <Text className="h34 bold" style={{ color: '#000' }}>{getCity()}</Text>
  220. </View>
  221. }
  222. return null
  223. }
  224. function onScroll(e) {
  225. scrollTop = e.detail.scrollTop
  226. setShowStreak(scrollTop < 20)
  227. }
  228. if (!loaded)
  229. return <View />
  230. return <View style={{ flex: 1, position: 'relative' }}>
  231. <View style={{ height: navigationBarHeight, backgroundColor: MainColorType.g05 }} />
  232. <View className="navi-bar" style={{ height: navigationBarHeight, zIndex: 1000, backgroundColor: showCalendar ? '#fff' : MainColorType.g05 }}>
  233. <View className="navi-streak" style={{
  234. height: 44,
  235. marginTop: systemInfo.statusBarHeight,
  236. alignItems: 'center',
  237. justifyContent: 'center',
  238. paddingLeft: 0,
  239. fontWeight: 'bold',
  240. fontSize: 17
  241. }} >{health.title}</View>
  242. {
  243. showStreak && steakIcon()
  244. }
  245. {
  246. locationIcon()
  247. }
  248. <View style={{
  249. position: 'absolute',
  250. left: 60,
  251. right: 60,
  252. bottom: 0,
  253. height: 44,
  254. display: 'flex',
  255. alignItems: 'center',
  256. justifyContent: 'center'
  257. }}>
  258. <HeaderCircadian />
  259. </View>
  260. </View>
  261. <ClockNew onScroll={onScroll}>
  262. {
  263. showCalendar && <Streak testInfo={null}
  264. // top={scrollTop}
  265. top={navigationBarHeight}
  266. dismiss={() => {
  267. setShowCalendar(false)
  268. }}
  269. confirm={() => { }}>
  270. <View style={{ display: 'flex', flexDirection: 'column' }}>
  271. {/* <View style={{ height: navigationBarHeight }} /> */}
  272. <Calendar year={2024} month={new Date().getMonth() + 1} mode={health.mode} />
  273. </View>
  274. </Streak>
  275. }
  276. </ClockNew>
  277. {
  278. showModal && <AddLabel labels={labels}
  279. window='ACTIVE'
  280. disMiss={() => setShowModal(false)}
  281. op_page='SCHEDULE_ACTIVE_SLEEP'
  282. // onlyCheck={true}
  283. // schedules={[]}
  284. confirm={(res) => {
  285. if ((res as any).result) {
  286. global.refreshWindow()
  287. setShowModal(false)
  288. // dispatch(setSchedules((res as any).schedules))
  289. // dispatch(setFooter((res as any).footer))
  290. // setList((res as any).schedules)
  291. // setErrors([])
  292. }
  293. else {
  294. showAlert({
  295. title: t('health.schedule_conflict'),
  296. content: t('health.conflict_desc'),
  297. showCancel: false,
  298. confirmText: t('health.check_conflict'),
  299. confirm: () => {
  300. setTimeout(() => {
  301. setShowModal(false)
  302. }, 1000)
  303. if ((res as any).show_conflict_dialog) {
  304. jumpPage('/_health/pages/schedules?mode=' + '&error=' + JSON.stringify(res))
  305. }
  306. else {
  307. jumpPage('/_health/pages/schedules?mode=' + health.mode + '&error=' + JSON.stringify(res))
  308. }
  309. // jumpPage(`./schedules?mode=&schedules=${JSON.stringify((res as any).schedules)}&errors=${JSON.stringify((res as any).error_messages)}`)
  310. }
  311. })
  312. // setList((res as any).schedules)
  313. // dispatch(setFooter((res as any).footer))
  314. // setErrors((res as any).error_messages ? (res as any).error_messages : [])
  315. }
  316. }}
  317. color={MainColorType.active} />
  318. }
  319. </View>
  320. }