Leon 1 năm trước cách đây
mục cha
commit
39f7c50ff7

+ 17 - 0
src/context/locales/en.js

@@ -107,6 +107,23 @@ export default {
         },
         edit_nickname: {
             title: 'Edit Nickname'
+        },
+        reminders:{
+            title:'Reminders',
+            fast_sleep:'Fast & Sleep',
+            base:'Reminders',
+            base_schedule_time:'At schedule time',
+            always:'Always',
+            base_footer:'A timely reminder so you never miss your schedule time for fasting and/or sleep.',
+            extra:'Extra Reminders',
+            missed_action:'Missed previous action',
+            extra_footer:'In case you missed your previous action, receive another reminder to log it together with the current one. This gives you extra protection against any streak loss.',
+            sun:'The Sun (Pro)',
+            sun_header:'Reminders for Your Daily Local Solar Times',
+            sun_footer:'Note for polar region, during Polar Day (Midnight Sun) when the Sun is up all day or Polar Night when the Sun is down all day, the only reminder available is the daily Solar Noon.',
+            sunrise:'Sunrise',
+            sunset:'Sunset',
+            solarnoon:'Solar noon',
         }
     },
     feature: {

+ 17 - 1
src/context/locales/zh.js

@@ -107,7 +107,23 @@ export default {
         edit_nickname: {
             title: '编辑昵称'
         },
-
+        reminders:{
+            title:'提醒',
+            fast_sleep:'断食与睡眠',
+            base:'基础',
+            base_schedule_time:'打卡提醒',
+            always:'已开启',
+            base_footer:'到了开始断食或就寝时间,收到打卡提醒一次。',
+            extra:'外加',
+            missed_action:'补记提醒',
+            extra_footer:'当错过开始时间仍未打卡,到了结束时间可收到补记提醒、避免连续纪录中断。',
+            sun:'昼夜与阴阳 (Pro 会员专享)',
+            sun_header:'基于太阳运动轨迹,安排每日饮食作息时间表。',
+            sun_footer:'支持全球任意位置。如您位于极地地区,由于极昼期间太阳位于地平线以上、极夜期间太阳地平线以下,您只会在“正午”太阳位于相对最高点时收到提醒。',
+            sunrise:'日出',
+            sunset:'日落',
+            solarnoon:'正午',
+        }
 
 
 

+ 22 - 9
src/features/common/TimePicker.tsx

@@ -2,9 +2,11 @@ import PickerViews from "@/components/input/PickerViews";
 import { PickerView, PickerViewColumn, View } from "@tarojs/components";
 
 import { useEffect, useState } from "react";
+import { useSelector } from "react-redux";
 
 export default function Component(props: { time: string, confirm: Function, cancel: Function, title?: string, color?: string }) {
     var [hour, minute] = props.time.split(':').map(x => parseInt(x))
+    const user = useSelector((state: any) => state.user);
     const m = Math.round(minute / 5) * 5;
     const v = [hour, m / 5];
 
@@ -22,24 +24,35 @@ export default function Component(props: { time: string, confirm: Function, canc
 
 
     for (let i = 0; i <= 23; i++) {
-        var h = i<10?'0'+i:i
+        var h = i < 10 ? '0' + i : i
         hours.push(h as any);
     }
 
     const minutes: string[] = [];
-    for (let i = 0; i <= 11; i++) {
-        var ms = i*5
-        var m1 = ms<10?'0'+ms:ms+''
-        minutes.push(m1 as any);
+    if (user.test_user) {
+        for (let i = 0; i <= 59; i++) {
+            var ms = i
+            var m1 = ms < 10 ? '0' + ms : ms + ''
+            minutes.push(m1 as any);
+        }
     }
+    else {
+        for (let i = 0; i <= 11; i++) {
+            var ms = i * 5
+            var m1 = ms < 10 ? '0' + ms : ms + ''
+            minutes.push(m1 as any);
+        }
+    }
+
+
 
     function onPickerChange(e) {
-        var h = parseInt( hours[e[0]])
+        var h = parseInt(hours[e[0]])
         var m = parseInt(minutes[e[1]])
-        var strHour =h < 10 ? '0' + h : h
-        var strMinute = m< 10 ? '0' + m : m
+        var strHour = h < 10 ? '0' + h : h
+        var strMinute = m < 10 ? '0' + m : m
         props.confirm(strHour + ':' + strMinute)
     }
 
-    return <PickerViews  themeColor={props.color} title={props.title} value={dt} showBtns={true} onChange={onPickerChange} items={[hours, minutes]} onCancel={() => { props.cancel() }} />
+    return <PickerViews themeColor={props.color} title={props.title} value={dt} showBtns={true} onChange={onPickerChange} items={[hours, minutes]} onCancel={() => { props.cancel() }} />
 }

+ 0 - 1
src/features/daynight/DayNightDetailPopup.tsx

@@ -114,7 +114,6 @@ export default function DayNightDetailPopup(props: {
     }
 
     function dayDuration() {
-        debugger
         if (isCompleted()) {
             return TimeFormatter.calculateTimeDifference(props.authInfo.day_completed.sunrise_ts, props.authInfo.day_completed.sunset_ts, true);
         }

+ 8 - 0
src/features/daynight/DayNightSwiperPopup.tsx

@@ -25,6 +25,7 @@ export default function DayNightSwiperPopup(props: { authInfo: any }) {
     const [nightDate, setNightDate] = useState<any>('')
     const [isNight, setIsNight] = useState(false)
 
+
     useEffect(() => {
         setAuthInfo(props.authInfo)
     }, [props.authInfo])
@@ -385,6 +386,13 @@ export default function DayNightSwiperPopup(props: { authInfo: any }) {
         setShowDetailPopup(true)
     }
 
+    global.showDayNightSwiperPop2 = (isNight, strNight, strDay) => {
+        setNightDate(strNight)
+        setDayDate(strDay)
+        setIsNight(isNight)
+        setShowDetailPopup(true)
+    }
+
     global.showDayNightSwiperModal = () => {
         setShowDetailModal(true)
     }

+ 32 - 9
src/pages/notification/setting.scss

@@ -45,7 +45,7 @@
     margin-top: 20px;
 }
 
-.setting_cell{
+.setting_cell {
     display: flex;
     flex-direction: row;
     align-items: center;
@@ -58,7 +58,7 @@
     padding-right: 40px;
 }
 
-.setting_cell_group{
+.setting_cell_group {
     display: flex;
     flex-direction: column;
     margin-left: 46px;
@@ -68,7 +68,7 @@
     overflow: hidden;
 }
 
-.setting_cell_group_item{
+.setting_cell_group_item {
     display: flex;
     flex-direction: row;
     align-items: center;
@@ -78,18 +78,18 @@
     padding-right: 40px;
 }
 
-.setting_cell_title{
+.setting_cell_title {
     color: #fff;
     font-size: 28px;
 }
 
-.setting_cell_value1{
+.setting_cell_value1 {
     color: #fff;
     opacity: 0.8;
     font-size: 28px;
 }
 
-.setting_tip{
+.setting_tip {
     background-color: rgba(255, 123, 0, 0.2);
     height: 56px;
     display: flex;
@@ -98,7 +98,30 @@
     padding-left: 46px;
 }
 
-.setting_tip_text{
+.setting_tip_bg {
+    position: fixed;
+    left: 0;
+    right: 0;
+    bottom: 103px;
+    padding-bottom: constant(safe-area-inset-bottom);
+    /* 兼容 iOS < 11.2 */
+    padding-bottom: env(safe-area-inset-bottom);
+    background-color: #000;
+}
+
+.setting_tip2 {
+
+    background-color: rgba(255, 123, 0, 0.2);
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    padding-left: 46px;
+    padding-right: 46px;
+    padding-top: 10px;
+    padding-bottom: 10px;
+}
+
+.setting_tip_text {
     color: #FF7B00;
     font-size: 28px;
     letter-spacing: 0;
@@ -106,8 +129,8 @@
 
 
 
-.new_item_cell_line{
-    height: 1px;
+.new_item_cell_line {
+    height: 2px;
     background-color: #fff;
     opacity: 0.2;
     margin-left: 40px;

+ 220 - 34
src/pages/notification/setting.tsx

@@ -12,7 +12,7 @@ import { getLocalPush } from "@/features/trackTimeDuration/actions/TrackTimeActi
 import { useDispatch, useSelector } from "react-redux";
 import ProductList from "../store/product_list";
 import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
-import { getPerm, userAccess } from "@/services/user";
+import { getPerm, latestLocation, userAccess } from "@/services/user";
 import '@/features/trackTimeDuration/components/CheckAccess.scss';
 import Modal from "@/components/layout/Modal.weapp";
 import Layout from "@/components/layout/layout";
@@ -23,6 +23,8 @@ import Tabbar from "@/components/navigation/TabBar";
 import FSwitch from "@/components/input/FSwitch";
 import { wxPubFollow } from "@/services/permission";
 import { setWXFollow } from "@/store/permission";
+import { TimeFormatter } from "@/utils/time_format";
+import DayNightSwiperPopup from "@/features/daynight/DayNightSwiperPopup";
 
 let useNavigation;
 let AppState;
@@ -57,28 +59,45 @@ export default function Page() {
     const [systemSun, setSystemSun] = useState(true)
     const [isAuthorized, setIsAuthorized] = useState(false)
     const [showMemberAlert, setShowMemberAlert] = useState(false)
+    const [errorCode, setErrorCode] = useState(-1)
     const user = useSelector((state: any) => state.user);
     const accessObj = useSelector((state: any) => state.access);
     const common = useSelector((state: any) => state.common);
+    const [authInfo, setAuthInfo] = useState<any>(null)
+    const [hasAddress, setHasAddress] = useState(false)
     const permission = useSelector((state: any) => state.permission);
+    const [index,setIndex] = useState(0)
+
+
+    const [switching0, setSwitching0] = useState(false)
+    const [switching1, setSwitching1] = useState(false)
+    const [switching2, setSwitching2] = useState(false)
+    const [switching3, setSwitching3] = useState(false)
 
     let navigation;
     if (useNavigation) {
         navigation = useNavigation()
     }
 
-    // useEffect(() => {
-
-    // }, [])
+    useEffect(() => {
+        setInterval(()=>{
+            setIndex(index=>index+1)
+        },1000)
+    }, [])
 
     useEffect(() => {
         if (!user.isLogin) {
             return;
         }
-        checkSetting()
-        getSettings()
-        getMemberStatus()
+        // checkSetting()
+        // getSettings()
+        // getMemberStatus()
         if (process.env.TARO_ENV == 'rn') {
+            checkSetting()
+            getSettings()
+            getMemberStatus()
+            getLatestLocation()
+
             navigation.setOptions({
                 headerTitle: '',
             });
@@ -92,6 +111,7 @@ export default function Page() {
             navigation.addListener('focus', () => {
                 rnNotification()
                 getMemberStatus()
+                getLatestLocation()
             });
 
             // 当页面即将消失时执行
@@ -117,6 +137,7 @@ export default function Page() {
             rnNotification()
             checkSetting()
             getMemberStatus()
+            getLatestLocation()
         }
 
     };
@@ -188,8 +209,16 @@ export default function Page() {
 
     useDidShow(() => {
         console.log('notfication setting user did show')
+        getSettings()
+        getMemberStatus()
+        checkSetting()
+        getLatestLocation()
     })
 
+    global.swiperDayNightRefresh = ()=>{
+        getLatestLocation()
+    }
+
     function getSettings() {
         getNotifySettings().then(res => {
             var dt = (res as any).notification
@@ -200,6 +229,42 @@ export default function Page() {
             setIsSolarNoon(dt.follow_sun.solar_noon.in_app == 'ON')
 
             setLoaded(true)
+
+            if ((res as any).push_errors && (res as any).push_errors.length > 0) {
+                setErrorCode((res as any).push_errors[0].code)
+            }
+            else {
+                setErrorCode(-1)
+            }
+
+        })
+    }
+
+    function getLatestLocation() {
+        if (!user.isLogin) {
+            return
+        }
+        var today = new Date()
+        var yesterday = new Date(today.getTime() - 24 * 3600 * 1000)
+        var tomorrow = new Date(today.getTime() + 24 * 3600 * 1000 * 50)
+        var strYesterday = `${yesterday.getFullYear()}-${TimeFormatter.padZero(yesterday.getMonth() + 1)}-${TimeFormatter.padZero(yesterday.getDate())}`
+        var strTomorrow = `${tomorrow.getFullYear()}-${TimeFormatter.padZero(tomorrow.getMonth() + 1)}-${TimeFormatter.padZero(tomorrow.getDate())}`
+        latestLocation({
+            date_start: strYesterday, date_end: strTomorrow
+        }).then(data => {
+            if (data && (data as any).daylights) {
+                (data as any).daylights.map(item => {
+                    if (!item.sunrise_ts) {
+                        item.sunrise_ts = new Date(item.date + 'T' + item.sunrise + ':00').getTime()
+                        item.sunset_ts = new Date(item.date + 'T' + item.sunset + ':00').getTime()
+                    }
+                })
+            }
+            setHasAddress((data as any).has_address)
+
+            setAuthInfo(data)
+        }).catch(e => {
+            setLoaded(true)
         })
     }
 
@@ -297,7 +362,7 @@ export default function Page() {
 
 
     function confirm() {
-        jumpPage('', 'ProductList', navigation)
+        jumpPage('/pages/store/product_list', 'ProductList', navigation)
         setShowMemberAlert(false)
     }
 
@@ -334,12 +399,33 @@ export default function Page() {
                         cancel: () => {
                         },
                         confirm: () => {
-                            checkNotification()
+                            if (process.env.TARO_ENV == 'weapp') {
+                                followWxPub()
+                            }
+                            else {
+                                checkNotification()
+                            }
+
                         }
                     })
                 }
             })
         }
+        else {
+            showAlert({
+                title: '关注公众号',
+                content: 'content',
+                cancelText: t('feature.track_time_duration.reminders.later'),
+                confirmText: t('feature.track_time_duration.reminders.open'),
+                showCancel: true,
+                cancel: () => {
+                },
+                confirm: () => {
+                    followWxPub()
+
+                }
+            })
+        }
     }
 
     function pro(isLogin: boolean) {
@@ -351,44 +437,109 @@ export default function Page() {
         </ScrollView>
     }
 
+    function sunSwitchStatus(type: string) {
+        if (type == 'sunrise' && switching1) {
+            return true
+        }
+        if (type == 'sunset' && switching2) {
+            return true
+        }
+
+        if (type == 'solarnoon' && switching3) {
+            return true
+        }
+        if (type =='extra' && switching0){
+            return true
+        }
+
+        if (!user.isLogin) {
+            return false;
+        }
+        if (!isAuthorized) {
+            return false;
+        }
+        if (type == 'extra'){
+            return isExtra;
+        }
+        if (!hasAddress) {
+            return false;
+        }
+
+        if (type == 'sunrise')
+            return isSunrise
+        if (type == 'sunset')
+            return isSunset
+        if (type == 'solarnoon')
+            return isSolarNoon
+        return true
+
+    }
+
+    function openSwitch(index){
+        if (index==0){
+            setSwitching0(true)
+            setTimeout(()=>{
+                setSwitching0(false)
+            },500)
+        }
+        if (index==1){
+            setSwitching1(true)
+            setTimeout(()=>{
+                setSwitching1(false)
+            },500)
+        }
+        if (index==2){
+            setSwitching2(true)
+            setTimeout(()=>{
+                setSwitching2(false)
+            },500)
+        }
+        if (index==3){
+            setSwitching3(true)
+            setTimeout(()=>{
+                setSwitching3(false)
+            },500)
+        }
+    }
+
     function proDetail(isLogin: boolean) {
         return <View className="setting_container">
             <View className="setting_section">
-                <Text className="setting_section_title">Fast & Sleep</Text>
+                <Text className="setting_section_title">{t('page.reminders.fast_sleep')}</Text>
             </View>
-            <Text className="setting_header">Reminders</Text>
+            <Text className="setting_header">{t('page.reminders.base')}</Text>
             <View className="setting_cell">
-                <Text className="setting_cell_title" style={{ flex: 1 }}>At schedule time</Text>
+                <Text className="setting_cell_title" style={{ flex: 1 }}>{t('page.reminders.base_schedule_time')}</Text>
                 {
-                    isLogin ? <Text className="setting_cell_value1">{systemFast ? 'Always' : 'Off'}</Text> :
+                    isLogin ? <Text className="setting_cell_value1">{systemFast ? t('page.reminders.always') : 'Off'}</Text> :
                         <Text className="setting_cell_value1">Off</Text>
                 }
 
             </View>
-            <Text className="setting_footer">A timely reminder so you never miss your schedule time for fasting and/or sleep.</Text>
-            <Text className="setting_header">Extra Reminders (Pro)</Text>
+            <Text className="setting_footer">{t('page.reminders.base_footer')}</Text>
+            <Text className="setting_header">{t('page.reminders.extra')}</Text>
             <View className="setting_cell">
-                <Text className="setting_cell_title" style={{ flex: 1 }}>Missed previous action</Text>
+                <Text className="setting_cell_title" style={{ flex: 1 }}>{t('page.reminders.missed_action')}</Text>
                 <FSwitch color={ColorType.fast}
-                    checked={isLogin ? (isAuthorized ? isExtra : false) : false}
+                    checked={sunSwitchStatus('extra')}
                     onChange={(value) => {
+                        openSwitch(0)
                         if (!isLogin) {
                             jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
                             return
                         }
-                        debugger
 
                         if (!isAuthorized) {
                             notificationOpen()
                             return
                         }
-                        if (value) {
-                            if (accessObj && accessObj.access && accessObj.access.member.status == 'NON_MEMBER') {
-                                setShowMemberAlert(true)
-                                return
-                            }
+                        // if (value) {
+                        //     if (accessObj && accessObj.access && accessObj.access.member.status == 'NON_MEMBER') {
+                        //         setShowMemberAlert(true)
+                        //         return
+                        //     }
 
-                        }
+                        // }
                         postNotifySettings({
                             notification: {
                                 fast_sleep: {
@@ -404,18 +555,19 @@ export default function Page() {
                     }}
                 />
             </View>
-            <Text className="setting_footer">In case you missed your previous action, receive another reminder to log it together with the current one. This gives you extra protection against any streak loss.</Text>
+            <Text className="setting_footer">{t('page.reminders.extra_footer')}</Text>
             <View className="setting_section">
-                <Text className="setting_section_title">The Sun (Pro)</Text>
+                <Text className="setting_section_title">{t('page.reminders.sun')}</Text>
             </View>
-            <Text className="setting_header">Reminders for Your Daily Local Solar Times</Text>
+            <Text className="setting_header">{t('page.reminders.sun_header')}</Text>
             <View className="setting_cell_group">
                 <View className="setting_cell_group_item">
-                    <Text className="setting_cell_title" style={{ flex: 1 }}>Sunrise</Text>
+                    <Text className="setting_cell_title" style={{ flex: 1 }}>{t('page.reminders.sunrise')}</Text>
                     <FSwitch
                         color={ColorType.fast}
-                        checked={isLogin ? (isAuthorized ? isSunrise : false) : false}
+                        checked={sunSwitchStatus('sunrise')}
                         onChange={(value) => {
+                            openSwitch(1)
                             if (!isLogin) {
                                 jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
                                 return
@@ -424,6 +576,11 @@ export default function Page() {
                                 notificationOpen()
                                 return
                             }
+                            if (!hasAddress) {
+                                global.showDayNightSwiperPop2(false, new Date(), new Date())
+                                
+                                return
+                            }
                             if (value) {
                                 if (accessObj && accessObj.access && accessObj.access.member.status == 'NON_MEMBER') {
                                     setShowMemberAlert(true)
@@ -449,19 +606,25 @@ export default function Page() {
                 </View>
                 <View className="new_item_cell_line" />
                 <View className="setting_cell_group_item">
-                    <Text className="setting_cell_title" style={{ flex: 1 }}>Sunset</Text>
+                    <Text className="setting_cell_title" style={{ flex: 1 }}>{t('page.reminders.sunset')}</Text>
                     <FSwitch
                         color={ColorType.fast}
-                        checked={isLogin ? (isAuthorized ? isSunset : false) : false}
+                        checked={sunSwitchStatus('sunset')}
                         onChange={(value) => {
+                            openSwitch(2)
                             if (!isLogin) {
                                 jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
                                 return
                             }
                             if (!isAuthorized) {
+                                
                                 notificationOpen()
                                 return
                             }
+                            if (!hasAddress) {
+                                global.showDayNightSwiperPop2(true, new Date(), new Date())
+                                return
+                            }
                             if (value) {
                                 if (accessObj && accessObj.access && accessObj.access.member.status == 'NON_MEMBER') {
                                     // setTimeout(() => {
@@ -491,17 +654,23 @@ export default function Page() {
                 </View>
                 <View className="new_item_cell_line" />
                 <View className="setting_cell_group_item">
-                    <Text className="setting_cell_title" style={{ flex: 1 }}>Solar noon</Text>
+                    <Text className="setting_cell_title" style={{ flex: 1 }}>{t('page.reminders.solarnoon')}</Text>
                     <FSwitch
                         color={ColorType.fast}
-                        checked={isLogin ? (isAuthorized ? isSolarNoon : false) : false}
+                        checked={sunSwitchStatus('solarnoon')}
                         onChange={(value) => {
+                            openSwitch(3)
                             if (!isLogin) {
                                 jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
                                 return
                             }
                             if (!isAuthorized) {
                                 notificationOpen()
+                                setIsAuthorized(false)
+                                return
+                            }
+                            if (!hasAddress) {
+                                global.showDayNightSwiperPop2(false, new Date(), new Date())
                                 return
                             }
                             if (value) {
@@ -533,7 +702,11 @@ export default function Page() {
                     />
                 </View>
             </View>
-            <Text className="setting_footer">Note for polar region, during Polar Day (Midnight Sun) when the Sun is up all day or Polar Night when the Sun is down all day, the only reminder available is the daily Solar Noon.</Text>
+            <Text className="setting_footer">{t('page.reminders.sun_footer')}</Text>
+            <Text style={{opacity:0}}>{index}</Text>
+            {
+                process.env.TARO_ENV == 'weapp' && <View style={{ height: 120 }} />
+            }
         </View>
     }
 
@@ -588,6 +761,7 @@ export default function Page() {
                         <Text className="setting_tip_text">Jump to App's Notifications settings{'>>'}</Text>
                     </View>
                 }
+
                 {
                     showMemberAlert && process.env.TARO_ENV == 'weapp' && alertPop()
                 }
@@ -600,6 +774,18 @@ export default function Page() {
                 }
             </View>
         </Layout>
+
+        {
+            process.env.TARO_ENV == 'weapp' && user.isLogin && errorCode == 43101 && <View className="setting_tip_bg"><View className="setting_tip2" onClick={goSetting}>
+                <Text className="setting_tip_text">{'请前往公众号主页,点右上角「设置-通知消息管理」\n确认“接收通知”已开启。'}</Text>
+            </View></View>
+        }
+        {
+            process.env.TARO_ENV == 'weapp' && user.isLogin && errorCode == 43019 && <View className="setting_tip_bg"><View className="setting_tip2" onClick={goSetting}>
+                <Text className="setting_tip_text">{'您暂无该功能体验权限。'}</Text>
+            </View></View>
+        }
+        <DayNightSwiperPopup authInfo={authInfo} />
         <Tabbar index={2} />
     </View>
 }

+ 1 - 1
src/services/http/api.js

@@ -1,4 +1,4 @@
-const online = process.env.TARO_ENV == 'weapp' ? true : false;
+const online = process.env.TARO_ENV == 'weapp' ? false : false;
 
 import { WX_VERSION as _WX_VERSION, APP_VERSION as _APP_VERSION } from "../../../config/env";