import { View, Text, Image } from "@tarojs/components"; import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react"; import { getLatestJournal, records } from "@/services/health"; import './History.scss' import Calendar from "./calendar"; import { useDispatch, useSelector } from "react-redux"; import HistoryItem from "./HistoryItem"; import { rpxToPx } from "@/utils/tools"; import { jumpPage } from "../trackTimeDuration/hooks/Common"; import Taro, { useReady } from "@tarojs/taro"; import { getScenario, getThemeColor } from "./hooks/health_hooks"; import { TimeFormatter } from "@/utils/time_format"; import dayjs from "dayjs"; import { MainColorType } from "@/context/themes/color"; import { IconArrow, IconCellArrow, IconClose } from "@/components/basic/Icons"; import NoRecord from "@/_health/components/no_record"; import ListFooter from "@/_health/components/list_footer"; import { useTranslation } from "react-i18next"; import { setActiveTip, setEatTip, setFirstActiveId, setFirstEatId } from "@/store/health"; import RightArrowRow from "@/_health/components/right_arrow_row"; import NewButton, { NewButtonType } from "@/_health/base/new_button"; import TimelineDate from "@/_health/components/timeline_date"; let lastMode = '' let myScrollTop = 0 export default forwardRef((props: { type?: string, fast_type?: string, updateDate?: any, refreshSuccess?: any }, ref) => { const [itemLayouts, setItemLayouts] = useState([]) const [itemHeights, setItemHeights] = useState([]) const [list, setList] = useState([]) const [page, setPage] = useState(1) const [total, setTotal] = useState(0) const [loaded, setLoaded] = useState(false) const health = useSelector((state: any) => state.health); const user = useSelector((state: any) => state.user); const [loading, setLoading] = useState(false) const [showEatArchive, setShowEatArchive] = useState(true) const [showActiveArchive, setShowActiveArchive] = useState(true) const [fastList, setFastList] = useState([]) const [eatList, setEatList] = useState([]) const [activeList, setActiveList] = useState([]) const [sleepList, setSleepList] = useState([]) const [fastTotal, setFastTotal] = useState(-1) const [eatTotal, setEatTotal] = useState(-1) const [activeTotal, setActiveTotal] = useState(-1) const [sleepTotal, setSleepTotal] = useState(-1) const [hideEatArchiveTip, setHideEatArchiveTip] = useState(false) const [hideActiveArchiveTip, setHideActiveArchiveTip] = useState(false) const [hideFastTip, setHideFastTip] = useState(false) const [hideSleepTip, setHideSleepTip] = useState(false) const [pageTop, setPageTop] = useState(0) const query = Taro.createSelectorQuery() const dispatch = useDispatch() const { t } = useTranslation() useImperativeHandle(ref, () => ({ onScroll: onScroll, refresh: refresh, more: more })) useEffect(() => { if (list.length > 0) { setTimeout(() => { measureItemLayouts() }, 300) } }, [list]) useEffect(() => { if (!user.isLogin) { setList([]) } }, [user.isLogin]) useEffect(()=>{ return ()=>{ myScrollTop = 0 } },[]) global.refreshHistory = () => { refresh() refreshItem('FAST') refreshItem('SLEEP') refreshItem('EAT') refreshItem('ACTIVE') } useEffect(() => { if (props.type) { loadData(1) } }, [props.type]) useEffect(() => { if (lastMode != health.mode) { lastMode = health.mode // loadData(1) setPage(1) switch (health.mode) { case 'DAY': case 'NIGHT': setList([]) return case 'FAST': if (fastList.length > 0) { setList(fastList) setTotal(fastTotal) return; } break case 'EAT': if (eatList.length > 0) { setList(eatList) setTotal(eatTotal) return; } break case 'SLEEP': if (sleepList.length > 0) { setList(sleepList) setTotal(sleepTotal) return; } break case 'ACTIVE': if (activeList.length > 0) { setList(activeList) setTotal(activeTotal) return; } break } loadData(1) } }, [health.mode]) function measureItemLayouts() { list.forEach((item, index) => { query.select(`#history-${index}`).boundingClientRect() }); query.exec((res) => { var layouts: any = [] var heights: any = [] res.forEach((rect, index) => { if (rect) { layouts[index] = rect.top + myScrollTop heights[index] = rect.height } }); setItemLayouts(layouts) setItemHeights(heights) }) } function onScroll(e) { // var top = e.detail.scrollTop // myScrollTop = top var top = e.detail.scrollTop - e.detail.deltaY myScrollTop = e.detail.scrollTop setPageTop(top) if (itemLayouts.length > 0) { var i = -1 var date = '' list.forEach((item, index) => { if (top >= itemLayouts[index] - 50) { i = index if (TimeFormatter.isTimestampInThisWeek(item.window_range.start_timestamp)) { date = t('health.this_week') } else if (dayjs(item.window_range.start_timestamp).format('YYYY') == dayjs().format('YYYY')) { date = global.language == 'en' ? dayjs(item.window_range.start_timestamp).format('MMMM') : dayjs(item.window_range.start_timestamp).format('MMMM') } else { date = global.language == 'en' ? dayjs(item.window_range.start_timestamp).format('YYYY') : dayjs(item.window_range.start_timestamp).format('YYYY年') } } }) if (props.updateDate) { props.updateDate({ show: i != -1, date: date }) } } else { if (props.updateDate) { props.updateDate({ show: false, date: '' }) } } } function refresh() { loadData(1) setPage(1) } function more() { if (loading) return; if (total == list.length) return; var index = page; index++; setPage(index) loadData(index) } function refreshItem(type) { setPage(1) var params: any = { window: type, limit: 10, page: 1 } records(params).then(res => { var array = (res as any).data array.map(item => { var temps: any = [] var lastType = '' var lastTextArray: any = [] var lastImageArray: any = [] item.events.map(event => { event.moments && event.moments.map(moment => { switch (moment.type) { case 'TEXT': { lastTextArray.push({ title: moment.title, description: moment.description, event_id: event.id }) if (lastType == 'PIC') { temps.push({ type: 'PIC', data: JSON.parse(JSON.stringify(lastImageArray)) }) lastImageArray = [] } lastType = 'TEXT' } break; case 'PIC': { lastImageArray.push(moment.media[0].url) if (lastType == 'TEXT') { temps.push({ type: 'TEXT', data: JSON.parse(JSON.stringify(lastTextArray)) }) lastTextArray = [] } lastType = 'PIC' } break; case 'PIC_TEXT': if (lastType == 'PIC') { temps.push({ type: 'PIC', data: JSON.parse(JSON.stringify(lastImageArray)) }) lastImageArray = [] } if (lastType == 'TEXT') { temps.push({ type: 'TEXT', data: JSON.parse(JSON.stringify(lastTextArray)) }) lastTextArray = [] } temps.push({ type: 'PIC_TEXT', data: [ { title: moment.title, description: moment.description, url: moment.media[0].url, urls:moment.media, event_id: event.id } ] }) lastType = 'PIC_TEXT' break; } }) }) if (lastType == 'PIC') { temps.push({ type: 'PIC', data: JSON.parse(JSON.stringify(lastImageArray)) }) lastImageArray = [] } if (lastType == 'TEXT') { temps.push({ type: 'TEXT', data: JSON.parse(JSON.stringify(lastTextArray)) }) lastTextArray = [] } item.dataArray = temps; }) switch (type) { case 'FAST': setFastList(array) setFastTotal((res as any).total) break case 'SLEEP': setSleepList(array) setSleepTotal((res as any).total) break case 'EAT': setEatList(array) setEatTotal((res as any).total) break case 'ACTIVE': setActiveList(array) setActiveTotal((res as any).total) break } }) } function loadData(index: number) { // console.log('load data, page',index) if (index == 1) { Taro.setStorage({ key: 'lastRefresh', data: new Date().getTime() + '' }) } var params: any = { window: props.type ? props.type : health.mode, limit: 10, page: index } if (props.fast_type) { params.fast_type = props.fast_type } setPage(index) setLoading(true) records(params).then(res => { var array = (res as any).data array.map(item => { var temps: any = [] var lastType = '' var lastTextArray: any = [] var lastImageArray: any = [] item.events.map(event => { event.moments && event.moments.map(moment => { switch (moment.type) { case 'TEXT': { lastTextArray.push({ title: moment.title, description: moment.description, event_id: event.id }) if (lastType == 'PIC') { temps.push({ type: 'PIC', data: JSON.parse(JSON.stringify(lastImageArray)) }) lastImageArray = [] } lastType = 'TEXT' } break; case 'PIC': { lastImageArray.push(moment.media[0].url) if (lastType == 'TEXT') { temps.push({ type: 'TEXT', data: JSON.parse(JSON.stringify(lastTextArray)) }) lastTextArray = [] } lastType = 'PIC' } break; case 'PIC_TEXT': if (lastType == 'PIC') { temps.push({ type: 'PIC', data: JSON.parse(JSON.stringify(lastImageArray)) }) lastImageArray = [] } if (lastType == 'TEXT') { temps.push({ type: 'TEXT', data: JSON.parse(JSON.stringify(lastTextArray)) }) lastTextArray = [] } temps.push({ type: 'PIC_TEXT', data: [ { title: moment.title, description: moment.description, url: moment.media[0].url, urls:moment.media, event_id: event.id } ] }) lastType = 'PIC_TEXT' break; } }) }) if (lastType == 'PIC') { temps.push({ type: 'PIC', data: JSON.parse(JSON.stringify(lastImageArray)) }) lastImageArray = [] } if (lastType == 'TEXT') { temps.push({ type: 'TEXT', data: JSON.parse(JSON.stringify(lastTextArray)) }) lastTextArray = [] } item.dataArray = temps; }) setLoading(false) setLoaded(true) if (index == 1) { // console.log(props.type,health.mode) if (!props.type && array.length >= 0) { if (health.mode == 'EAT') { setEatList(array) setList(array) setEatTotal((res as any).total) } else if (health.mode == 'ACTIVE') { setActiveList(array) setList(array) setActiveTotal((res as any).total) } else if (health.mode == 'FAST') { setFastList(array) setList(array) setFastTotal((res as any).total) } else if (health.mode == 'SLEEP') { setSleepList(array) setList(array) setSleepTotal((res as any).total) } } setTotal((res as any).total) if (props.refreshSuccess) { props.refreshSuccess() } } else { setList([...list, ...array]) } }).catch(e => { setLoading(false) }) } function historyMonth(index) { var showDate = false; var dateStr = '' if (index == 0) { var currentDate = global.language == 'en' ? dayjs(list[index].window_range.start_timestamp).format('YYYY') : dayjs(list[index].window_range.start_timestamp).format('YYYY年') var now = global.language == 'en' ? dayjs().format('YYYY') : dayjs().format('YYYY年') if (currentDate != now) { showDate = true dateStr = currentDate } } else { var currentDate = global.language == 'en' ? dayjs(list[index].window_range.start_timestamp).format('YYYY') : dayjs(list[index].window_range.start_timestamp).format('YYYY年') var now = global.language == 'en' ? dayjs(list[index - 1].window_range.start_timestamp).format('YYYY') : dayjs(list[index - 1].window_range.start_timestamp).format('YYYY年') if (currentDate != now) { showDate = true dateStr = currentDate } } if (showDate) { return {dateStr} } return } function hideLine(index) { var currentDate = dayjs(list[index].window_range.start_timestamp).format('YYYY年M月D日') if (list.length > index + 1) { var nextDate = dayjs(list[index + 1].window_range.start_timestamp).format('YYYY年M月D日') if (currentDate == nextDate) return true } return false } if (!loaded || health.mode == 'DAY' || health.mode == 'NIGHT') return if (!user.isLogin) return function showTipF() { var showTip = false if (getScenario(health.windows, health.mode).status == 'OG') { if (health.mode == 'EAT') { showTip = !global.hideEatArchiveTip } else if (health.mode == 'ACTIVE') { showTip = !global.hideActiveArchiveTip } } return showTip } function newJournalTip() { if (!props.type) { var show = false if (health.mode == 'EAT' && health.eat_journal_tip) { show = true } else if (health.mode == 'ACTIVE' && health.active_journal_tip) { show = true } if (show) { return { // jumpPage('/_health/pages/archive') var data = list[0] jumpPage(`/_health/pages/timeline_detail?window_id=${data.window_id}&type=recent&isfastsleep=0×tamp=${data.publish.timestamp}`) // getLatestJournal(false, { // id: health.mode == 'EAT' ? global.eatTipId : global.activeTipId, // user_confirmed: true // }).then(res => { // }) setTimeout(() => { if (health.mode == 'EAT') { dispatch(setEatTip(false)) } else { dispatch(setActiveTip(false)) } }, 1000) }}> {t('health.new_journal_created')} {/* { health.eatArchived.images.map((item, index) => { return }) } */} // return { // if (health.mode == 'EAT'){ // dispatch(setEatTip(false)) // } // else { // dispatch(setActiveTip(false)) // } // }} // style={{ // width:rpxToPx(750), // height:rpxToPx(156), // display:'flex', // alignItems:'center', // justifyContent:'center', // backgroundColor:'#fff', // color:getThemeColor(health.mode), // }}> // New Journal Created {'>'} // } } return } function markDoneTip() { if (health.mode == 'DAY' && health.mode != 'NIGHT') return var scenario = getScenario(health.windows, health.mode) if (scenario.status != 'OG') return if (health.mode == 'EAT' && hideEatArchiveTip) return if (health.mode == 'ACTIVE' && hideActiveArchiveTip) return if (health.mode == 'FAST' && hideFastTip) return if (health.mode == 'SLEEP' && hideSleepTip) return function tipContent() { var strTime = '' var today = new Date().getDate() var date = new Date(scenario.archive_timestamp).getDate() var time = dayjs(scenario.archive_timestamp).format('HH:mm') if (today == date) { strTime = t('health.today_at', { time: time }) if (global.language == 'en') { if (time == '23:59') { strTime = 'at midnight' } else { strTime = `today at ${time}` } } } else { strTime = t('health.tomorrow_at', { time: time }) if (global.language == 'en') { strTime = `tomorrow at ${time}` } } switch (health.mode) { case 'FAST': if (global.language == 'en') { return Today's Moments will appear in Recents when you log end fast. } return 今天的时刻 将在您 记录结束断食 之际,出现在最近记录中。 case 'SLEEP': if (global.language == 'en') { return Today's Moments will appear in Recents when you log wake up. } return 今天的时刻 将在您 记录起床 之际,出现在最近记录中。 case 'EAT': case 'ACTIVE': if (global.language == 'en') { return Today's Moments will appear in Recents {strTime} or when you mark done. } return 今天的时刻 将在今夜或在您 标记完成 之际,出现在最近记录中。 } return 1 } return { tipContent() } { switch (health.mode) { case 'FAST': setHideFastTip(true) break; case 'EAT': setHideEatArchiveTip(true) break; case 'SLEEP': setHideSleepTip(true) break case 'ACTIVE': setHideActiveArchiveTip(true) break } }}> } return { (list.length >= 0 || health.mode == 'EAT' || health.mode == 'ACTIVE') && {t('health.recents')} { (health.mode == 'EAT' || health.mode == 'ACTIVE') && { var showBadge = (health.mode == 'EAT' && health.eat_journal_tip) || (health.mode == 'ACTIVE' && health.active_journal_tip) jumpPage('/pages/account/Journal?type=' + health.mode + `&show_tip=${showTipF() && false ? '1' : '0'}&show_badge=${showBadge ? 1 : 0}`) }} /> } } { markDoneTip() } { list.length == 0 && } { list.length > 0 && { list.map((item, index) => { if (itemLayouts.length >= index + 1 && pageTop > 0) { if (Math.abs(itemLayouts[index] - pageTop) > 3000) { return {/* {index} */} } if (Math.abs(itemLayouts[index] - pageTop) > 1500) { return 0 ? list[index - 1].window_range.start_timestamp : null} /> } } return { historyMonth(index) } 0 ? list[index - 1] : null} index={index} mode={props.type ?? health.mode} fast_type={props.fast_type} type={props.type} hideLine={hideLine(index)} onClick={() => { }} /> }) } } {/* */} 0) && (total == list.length)} loading={loading} /> })