/* tslint:disable:no-any */ import { List, Picker, Toast, Portal } from "@ant-design/react-native"; import Constants from "expo-constants"; import * as WebBrowser from "expo-web-browser"; import React, { useEffect, useState } from "react"; import { Alert, Platform, ScrollView, Switch, View, AsyncStorage, } from "react-native"; import { connect } from "react-redux"; import { analytics } from "@/common/analytics"; import { ListHeader } from "@/common/list-header"; import { registerForPushNotificationAsync } from "@/common/register-push-token"; import { actionUpdateReduxState } from "@/common/root-reducer"; import { AppState } from "@/common/store"; import { useTheme } from "@/common/theme"; import { i18n, LocalizationContext } from "@/translations"; import { actionLogout } from "@/screens/mine-screen/account-reducer"; import { useUserProfile } from "@/screens/mine-screen/hooks/use-user-profile"; import { useUpdateReportSubscribeToRemote } from "@/screens/mine-screen/hooks/use-update-report-subscribe"; import { useFeatureFlags } from "@/common/feature-flags/use-feature-flags"; import { AccountHeader } from "@/screens/mine-screen/account-header"; import { InviteSection } from "@/screens/referral-screen/components/invite-section"; import { useIsFocused } from "@react-navigation/native"; import { ReportStatus } from "../../../__generated__/globalTypes"; const { Item } = List; const { Brief } = Item; type Props = { authToken: string; locale: string; logout: (authToken: string) => void; updateReduxState: (state: { base: { locale?: string; currentTheme?: string }; }) => void; currentTheme: "dark" | "light"; userId: string; navigation: any; }; export const About = connect( (state: AppState) => ({ authToken: state.base.authToken, locale: state.base.locale, currentTheme: state.base.currentTheme, userId: state.base.userId, }), (dispatch) => ({ logout(authToken: string): void { dispatch(actionLogout(authToken)); }, updateReduxState(payload: { base: { locale: string } }): void { dispatch(actionUpdateReduxState(payload)); }, }) )( ({ authToken, locale, logout, updateReduxState, currentTheme, userId, navigation, }: Props) => { const theme = useTheme().colorTheme; const { setLocale } = React.useContext(LocalizationContext); const pickerSource = [ { value: ReportStatus.WEEKLY, label: i18n.t("weekly") }, { value: ReportStatus.MONTHLY, label: i18n.t("monthly") }, { value: ReportStatus.OFF, label: i18n.t("off") }, ]; useEffect(() => { async function init() { await registerForPushNotificationAsync(); } init(); }, []); const [reportAnimateCount, setReportAnimateCount] = useState(0); const [subscriptionFlash, setSubscriptionFlash] = useState(false); const isFocused = useIsFocused(); React.useEffect(() => { async function init() { try { const value = await AsyncStorage.getItem("@SubscriptionFlash:key"); if (value !== null) { setSubscriptionFlash(value === "true"); } else { setSubscriptionFlash(false); } await AsyncStorage.setItem("@SubscriptionFlash:key", "false"); } catch (error) { console.error(`failed to get subscription flash value: ${error}`); } } init(); }, [isFocused]); useEffect(() => { if (subscriptionFlash) { const interval = setInterval(() => { if (reportAnimateCount < 5) { setReportAnimateCount(reportAnimateCount + 1); } }, 300); return () => clearInterval(interval); } setReportAnimateCount(0); return undefined; }, [subscriptionFlash, reportAnimateCount]); const { emailReportStatus } = useUserProfile(userId); const [reportStatus, setReportStatue] = useState<string>( emailReportStatus ? emailReportStatus.toString() : "" ); useEffect(() => { setReportStatue(emailReportStatus ? emailReportStatus.toString() : ""); }, [emailReportStatus]); const { error, mutate } = useUpdateReportSubscribeToRemote(); const getReportStatusLabel = (status: string) => { switch (status) { case ReportStatus.OFF: return i18n.t("off"); case ReportStatus.WEEKLY: return i18n.t("weekly"); case ReportStatus.MONTHLY: return i18n.t("monthly"); default: return i18n.t("off"); } }; const getReportStatusEnum = (status: string) => { switch (status) { case ReportStatus.OFF: return ReportStatus.OFF; case ReportStatus.WEEKLY: return ReportStatus.WEEKLY; case ReportStatus.MONTHLY: return ReportStatus.MONTHLY; default: return ReportStatus.OFF; } }; const renderAppSection = () => { const backgroundColor = { backgroundColor: theme.white, color: theme.text01, }; const { spendingReportSubscription } = useFeatureFlags(userId); return ( // @ts-ignore <List style={backgroundColor} renderHeader={<ListHeader>{i18n.t("about")}</ListHeader>} > <Item disabled extra={Platform.OS === "ios" ? "Apple Store" : "Google Play"} arrow="horizontal" style={backgroundColor} onPress={async () => { const storeUrl = Platform.OS === "ios" ? "https://apps.apple.com/us/app/id1527950512" : "https://play.google.com/store/apps/details?id=io.beancount.android"; if (storeUrl) { await WebBrowser.openBrowserAsync(storeUrl); await analytics.track("tap_review_app", { storeUrl }); } }} > {i18n.t("reviewApp")} </Item> {spendingReportSubscription && ( <Picker data={pickerSource} cols={1} extra={getReportStatusLabel(reportStatus)} onChange={async (value) => { const newValue = value ? String(value[0]) : ""; if (newValue === reportStatus) { return; } setReportStatue(newValue); const loadingKey = Toast.loading(i18n.t("updating")); await mutate({ variables: { userId, status: getReportStatusEnum(newValue) }, }); Portal.remove(loadingKey); if (!error) { Toast.success(i18n.t("updateSuccess")); } else { console.error("failed to update report status", error); Toast.fail(i18n.t("updateFailed")); } }} > <Item style={[ backgroundColor, { backgroundColor: reportAnimateCount % 2 === 1 ? theme.warning : theme.white, }, ]} arrow="horizontal" > {i18n.t("subscribe")} </Item> </Picker> )} <Item disabled style={backgroundColor} extra={ <Switch value={String(locale).startsWith("en")} onValueChange={async (value) => { const changeTo = value ? "en" : "zh"; updateReduxState({ base: { locale: changeTo }, }); i18n.locale = changeTo; setLocale(changeTo); await analytics.track("tap_switch_language", { changeTo }); }} /> } > {i18n.t("currentLanguage")} <Brief> {String(locale).startsWith("en") ? i18n.t("english") : i18n.t("chinese")} </Brief> </Item> <Item style={backgroundColor} disabled extra={ <Switch value={currentTheme === "dark"} onValueChange={async (value) => { const mode = value ? "dark" : "light"; updateReduxState({ base: { currentTheme: mode }, }); await analytics.track("tap_switch_theme", { mode }); }} /> } > {i18n.t("theme")} <Brief>{currentTheme === "dark" ? "Dark" : "Light"}</Brief> </Item> <Item style={backgroundColor} disabled extra={Constants.nativeAppVersion} > {i18n.t("currentVersion")} </Item> {authToken ? ( <Item style={backgroundColor} disabled onPress={() => { Alert.alert( "", i18n.t("logoutAlertMsg"), [ { text: i18n.t("logoutAlertCancel"), style: "cancel" }, { text: i18n.t("logoutAlertConfirm"), onPress: () => { logout(authToken); }, }, ], { cancelable: false } ); }} > {i18n.t("logout")} </Item> ) : ( <View /> )} </List> ); }; return ( <ScrollView style={{ backgroundColor: theme.white }}> <AccountHeader /> <InviteSection navigation={navigation} /> {renderAppSection()} </ScrollView> ); } );