From e75715c2e0e2d4fe5d9ee1964dfc5827acba79f9 Mon Sep 17 00:00:00 2001 From: Julien Delaigues <0xju@pm.me> Date: Thu, 14 Mar 2024 11:10:58 +0800 Subject: [PATCH 1/6] chore: add posthog integration --- package.json | 1 + src/screens/app/index.tsx | 44 ++++++++++++++++++++++++++++++++------- yarn.lock | 25 ++++++++++++++++++++++ 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index b8d64a4d..67813f05 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "next-translate": "^2.6.2", "next-translate-plugin": "^2.6.2", "nodemailer": "^6.9.11", + "posthog-js": "^1.114.2", "ramda": "^0.29.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/src/screens/app/index.tsx b/src/screens/app/index.tsx index 61d501ca..fbb63ea0 100644 --- a/src/screens/app/index.tsx +++ b/src/screens/app/index.tsx @@ -3,6 +3,9 @@ import { CacheProvider } from "@emotion/react"; import { init } from "@socialgouv/matomo-next"; import type { AppProps } from "next/app"; import Head from "next/head"; +import { useRouter } from "next/router"; +import posthog from "posthog-js"; +import { PostHogProvider } from "posthog-js/react"; import { useEffect } from "react"; import createEmotionCache from "../../utils/createEmotionCache"; @@ -19,11 +22,25 @@ interface MyAppProps extends AppProps { const MATOMO_URL = process.env.NEXT_PUBLIC_MATOMO_URL; const MATOMO_SITE_ID = process.env.NEXT_PUBLIC_MATOMO_SITE_ID; +// Check that PostHog is client-side (used to handle Next.js SSR) +if (typeof window !== "undefined") { + posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY as string, { + api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, + + // Enable debug mode in development + loaded: (posthog) => { + if (process.env.NODE_ENV === "development") posthog.debug(); + }, + }); +} + export default function MyApp({ Component, emotionCache = clientSideEmotionCache, pageProps, }: MyAppProps) { + const router = useRouter(); + useEffect(() => { if (!MATOMO_URL) return; @@ -33,13 +50,26 @@ export default function MyApp({ }); }, []); + useEffect(() => { + // Track page views + const handleRouteChange = () => posthog?.capture("$pageview"); + + router.events.on("routeChangeComplete", handleRouteChange); + + return () => { + router.events.off("routeChangeComplete", handleRouteChange); + }; + }, []); + return ( - - - - - - - + + + + + + + + + ); } diff --git a/yarn.lock b/yarn.lock index 8a0a4db9..a7641d16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7363,6 +7363,13 @@ __metadata: languageName: node linkType: hard +"fflate@npm:^0.4.8": + version: 0.4.8 + resolution: "fflate@npm:0.4.8" + checksum: 29d1eddaaa5deab61b1c6b0d21282adacadbc4d2c01e94d8b1ee784398151673b9c563e53f97a801bc410a1ae55e8de5378114a743430e643e7a0644ba8e5a42 + languageName: node + linkType: hard + "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -7535,6 +7542,7 @@ __metadata: next-translate-plugin: "npm:^2.6.2" nodemailer: "npm:^6.9.11" postcss: "npm:^8.4.35" + posthog-js: "npm:^1.114.2" prettier: "npm:^3.2.5" ramda: "npm:^0.29.1" react: "npm:^18.2.0" @@ -11113,6 +11121,23 @@ __metadata: languageName: node linkType: hard +"posthog-js@npm:^1.114.2": + version: 1.114.2 + resolution: "posthog-js@npm:1.114.2" + dependencies: + fflate: "npm:^0.4.8" + preact: "npm:^10.19.3" + checksum: 75246ac5ec9c347729fdaeef9c64e4dbdedf416f30c9b26f6bb78b0879e92b933e67ebf600741a62da0d5c69e977dabd505c8a684580b2b0609d5752a58771a3 + languageName: node + linkType: hard + +"preact@npm:^10.19.3": + version: 10.19.6 + resolution: "preact@npm:10.19.6" + checksum: 305c63bc59f9a081185fea8ee9a43c96f69af58e50692228d0e566eacd69bac009f2fb9d4ebfa2bcfcfd9762c5318a7f1ccd1d5223ab8764e3f7e14386bce626 + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" From 97d1b25f01256834e6f405c981b6f03c15c16995 Mon Sep 17 00:00:00 2001 From: Julien Delaigues <0xju@pm.me> Date: Thu, 14 Mar 2024 11:19:30 +0800 Subject: [PATCH 2/6] chore: use reverse proxy --- next.config.js | 13 +++++++++++-- src/screens/app/index.tsx | 9 ++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/next.config.js b/next.config.js index 6f56624e..8948f3ff 100644 --- a/next.config.js +++ b/next.config.js @@ -38,11 +38,20 @@ const baseConfig = nextTranslate({ source: `${prefix}/native-staking`, })), ], - rewrites: async () => - ["/rss", "/rss/"].map((path) => ({ + rewrites: async () => [ + ...["/rss", "/rss/"].map((path) => ({ destination: "/rss.xml", source: path, })), + { + destination: "https://eu-assets.i.posthog.com/static/:path*", + source: "/ingest/static/:path*", + }, + { + destination: "https://eu.i.posthog.com/:path*", + source: "/ingest/:path*", + }, + ], typescript: { ignoreBuildErrors: process.env.QUICK_BUILD === "true", }, diff --git a/src/screens/app/index.tsx b/src/screens/app/index.tsx index fbb63ea0..fa04ee71 100644 --- a/src/screens/app/index.tsx +++ b/src/screens/app/index.tsx @@ -25,12 +25,14 @@ const MATOMO_SITE_ID = process.env.NEXT_PUBLIC_MATOMO_SITE_ID; // Check that PostHog is client-side (used to handle Next.js SSR) if (typeof window !== "undefined") { posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY as string, { - api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, + api_host: `${window.location.origin}/ingest`, // Enable debug mode in development - loaded: (posthog) => { - if (process.env.NODE_ENV === "development") posthog.debug(); + loaded: (_posthog) => { + if (process.env.NODE_ENV === "development") _posthog.debug(); }, + + ui_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, }); } @@ -59,6 +61,7 @@ export default function MyApp({ return () => { router.events.off("routeChangeComplete", handleRouteChange); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( From ccdda5b6010ddddd587ef94e5545fa2b62d6ade7 Mon Sep 17 00:00:00 2001 From: Julien Delaigues <0xju@pm.me> Date: Thu, 14 Mar 2024 17:45:42 +0800 Subject: [PATCH 3/6] feat: add custom events --- .../staking_section/claim_rewards_modal.tsx | 17 ++++++++++++++++- .../staking_section/connect_wallet_modal.tsx | 8 ++++++++ .../staking_section/staking_modal.tsx | 6 ++++++ .../staking_section/unstaking_modal.tsx | 7 +++++++ .../staking/lib/staking_sdk/context/index.tsx | 11 +++++++++-- .../lib/staking_sdk/wallet_operations/cosmos.ts | 2 +- src/utils/posthog.ts | 6 ++++++ 7 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 src/utils/posthog.ts diff --git a/src/screens/staking/components/staking_section/claim_rewards_modal.tsx b/src/screens/staking/components/staking_section/claim_rewards_modal.tsx index 7a935f45..77255c80 100644 --- a/src/screens/staking/components/staking_section/claim_rewards_modal.tsx +++ b/src/screens/staking/components/staking_section/claim_rewards_modal.tsx @@ -13,7 +13,10 @@ import { setSelectedAccount, syncAccountData, } from "@src/screens/staking/lib/staking_sdk/context/actions"; -import { getSelectedAccount } from "@src/screens/staking/lib/staking_sdk/context/selectors"; +import { + getClaimableRewardsForNetwork, + getSelectedAccount, +} from "@src/screens/staking/lib/staking_sdk/context/selectors"; import type { Coin } from "@src/screens/staking/lib/staking_sdk/core/base"; import { formatCoin } from "@src/screens/staking/lib/staking_sdk/formatters"; import { accountHasRewards } from "@src/screens/staking/lib/staking_sdk/utils/accounts"; @@ -22,6 +25,7 @@ import { getClaimRewardsFee, } from "@src/screens/staking/lib/staking_sdk/wallet_operations"; import { ClaimRewardsError } from "@src/screens/staking/lib/staking_sdk/wallet_operations/base"; +import { PostHogCustomEvent } from "@src/utils/posthog"; import * as styles from "./claim_rewards_modal.module.scss"; import Label from "./label"; @@ -109,6 +113,17 @@ const ClaimRewardsModal = () => { setSelectedAccount(stakingRef.current, null, null); + const claimableRewardsForNetwork = + getClaimableRewardsForNetwork( + stakingRef.current.state, + selectedAccount.networkId, + ); + + stakingRef.current.postHog?.capture( + PostHogCustomEvent.ClaimedRewards, + claimableRewardsForNetwork, + ); + toastSuccess({ subtitle: `${t("rewardsModal.success.sub")} 🎉`, title: t("rewardsModal.success.title"), diff --git a/src/screens/staking/components/staking_section/connect_wallet_modal.tsx b/src/screens/staking/components/staking_section/connect_wallet_modal.tsx index 7b20fa8c..36579d54 100644 --- a/src/screens/staking/components/staking_section/connect_wallet_modal.tsx +++ b/src/screens/staking/components/staking_section/connect_wallet_modal.tsx @@ -12,6 +12,7 @@ import { getWalletName, walletsIcons, } from "@src/screens/staking/lib/wallet_info"; +import { PostHogCustomEvent } from "@src/utils/posthog"; import * as styles from "./connect_wallet_modal.module.scss"; import ModalBase from "./modal_base"; @@ -65,6 +66,13 @@ const ConnectWalletModal = () => { }) .then((connected) => { if (connected) { + stakingRef.current.postHog?.capture( + PostHogCustomEvent.WalletConnected, + { + type: walletId, + }, + ); + toastSuccess({ subtitle: t("connectWallet.success.subtitle"), title: t("connectWallet.success.title"), diff --git a/src/screens/staking/components/staking_section/staking_modal.tsx b/src/screens/staking/components/staking_section/staking_modal.tsx index 13268753..4aef207a 100644 --- a/src/screens/staking/components/staking_section/staking_modal.tsx +++ b/src/screens/staking/components/staking_section/staking_modal.tsx @@ -29,6 +29,7 @@ import { stakeAmount, } from "@src/screens/staking/lib/staking_sdk/wallet_operations"; import { StakeError } from "@src/screens/staking/lib/staking_sdk/wallet_operations/base"; +import { PostHogCustomEvent } from "@src/utils/posthog"; import Label from "./label"; import ModalBase, { ModalError } from "./modal_base"; @@ -147,6 +148,11 @@ const StakingModal = () => { setSelectedAccount(stakingRef.current, null, null); + stakingRef.current.postHog?.capture(PostHogCustomEvent.StakedTokens, { + amount, + denom: mainNetworkDenom[selectedAccount.networkId], + }); + toastSuccess({ subtitle: `${t("stakingModal.success.sub")} 🎉`, title: t("stakingModal.success.title"), diff --git a/src/screens/staking/components/staking_section/unstaking_modal.tsx b/src/screens/staking/components/staking_section/unstaking_modal.tsx index da062024..6b6fd3b9 100644 --- a/src/screens/staking/components/staking_section/unstaking_modal.tsx +++ b/src/screens/staking/components/staking_section/unstaking_modal.tsx @@ -21,6 +21,7 @@ import { } from "@src/screens/staking/lib/staking_sdk/context/actions"; import { getSelectedAccount } from "@src/screens/staking/lib/staking_sdk/context/selectors"; import type { StakingNetworkInfo } from "@src/screens/staking/lib/staking_sdk/core"; +import { mainNetworkDenom } from "@src/screens/staking/lib/staking_sdk/core/base"; import { formatCoin } from "@src/screens/staking/lib/staking_sdk/formatters"; import { getAccountNormalisedDelegation } from "@src/screens/staking/lib/staking_sdk/utils/accounts"; import { @@ -33,6 +34,7 @@ import { unstake, } from "@src/screens/staking/lib/staking_sdk/wallet_operations"; import { UnstakeError } from "@src/screens/staking/lib/staking_sdk/wallet_operations/base"; +import { PostHogCustomEvent } from "@src/utils/posthog"; import Label from "./label"; import ModalBase, { ModalError } from "./modal_base"; @@ -148,6 +150,11 @@ const UnstakingModal = () => { setSelectedAccount(stakingRef.current, null, null); + stakingRef.current.postHog?.capture( + PostHogCustomEvent.UnstakedTokens, + { amount, denom: mainNetworkDenom[selectedAccount.networkId] }, + ); + toastSuccess({ subtitle: t("unstakingModal.success.subtitle"), title: t("unstakingModal.success.title", { diff --git a/src/screens/staking/lib/staking_sdk/context/index.tsx b/src/screens/staking/lib/staking_sdk/context/index.tsx index b3abe542..d4162374 100644 --- a/src/screens/staking/lib/staking_sdk/context/index.tsx +++ b/src/screens/staking/lib/staking_sdk/context/index.tsx @@ -1,3 +1,5 @@ +import type { PostHog } from "posthog-js"; +import { usePostHog } from "posthog-js/react"; import type { PropsWithChildren } from "react"; import { createContext, @@ -16,6 +18,7 @@ type SetState = ( ) => void; export type TStakingContext = { + postHog?: PostHog; setState: SetState; state: StakingState; }; @@ -37,6 +40,8 @@ const baseContext: TStakingContext = { export const StakingContext = createContext(baseContext); export const StakingProvider = ({ children }: PropsWithChildren) => { + const postHog = usePostHog(); + const [state, setState] = useState( (typeof window !== "undefined" && window.stakingContext?.state) || baseContext.state, @@ -54,10 +59,11 @@ export const StakingProvider = ({ children }: PropsWithChildren) => { }; return { + postHog, setState: wrappedSetState, state, }; - }, [state, setState]); + }, [postHog, state]); useEffect(() => { window.stakingContext = contextValue; @@ -73,12 +79,13 @@ export const StakingProvider = ({ children }: PropsWithChildren) => { }; export const useStakingRef = () => { - const { setState, state } = useContext(StakingContext); + const { postHog, setState, state } = useContext(StakingContext); const stakingRef = useRef({} as TStakingContext); stakingRef.current.state = state; stakingRef.current.setState = setState; + stakingRef.current.postHog = postHog; return stakingRef; }; diff --git a/src/screens/staking/lib/staking_sdk/wallet_operations/cosmos.ts b/src/screens/staking/lib/staking_sdk/wallet_operations/cosmos.ts index 3cd4e9bc..162c8ccc 100644 --- a/src/screens/staking/lib/staking_sdk/wallet_operations/cosmos.ts +++ b/src/screens/staking/lib/staking_sdk/wallet_operations/cosmos.ts @@ -1,5 +1,4 @@ import type { EncodeObject } from "@cosmjs/proto-signing"; -import { SigningStargateClient } from "@cosmjs/stargate"; import type { MsgDelegateEncodeObject, MsgUndelegateEncodeObject, @@ -7,6 +6,7 @@ import type { StdFee, Event as TxEvent, } from "@cosmjs/stargate"; +import { SigningStargateClient } from "@cosmjs/stargate"; import type { AccountData } from "@keplr-wallet/types"; import { MsgWithdrawDelegatorReward } from "cosmjs-types/cosmos/distribution/v1beta1/tx"; import { diff --git a/src/utils/posthog.ts b/src/utils/posthog.ts new file mode 100644 index 00000000..a6005b5b --- /dev/null +++ b/src/utils/posthog.ts @@ -0,0 +1,6 @@ +export const enum PostHogCustomEvent { + ClaimedRewards = "ClaimedRewards", + StakedTokens = "StakedTokens", + UnstakedTokens = "UnstakedTokens", + WalletConnected = "WalletConnected", +} From e4f0fff86fcc7aef22dd73fde0d204f9f0d18600 Mon Sep 17 00:00:00 2001 From: Julien Delaigues <0xju@pm.me> Date: Thu, 21 Mar 2024 11:57:07 +0800 Subject: [PATCH 4/6] feat: only track events on the staking page --- src/screens/app/index.tsx | 2 ++ src/screens/staking/index.tsx | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/screens/app/index.tsx b/src/screens/app/index.tsx index fa04ee71..4482a155 100644 --- a/src/screens/app/index.tsx +++ b/src/screens/app/index.tsx @@ -32,6 +32,8 @@ if (typeof window !== "undefined") { if (process.env.NODE_ENV === "development") _posthog.debug(); }, + // Used to capture events only for the staking page + opt_out_capturing_by_default: true, ui_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, }); } diff --git a/src/screens/staking/index.tsx b/src/screens/staking/index.tsx index 47a530ea..439f8f7d 100644 --- a/src/screens/staking/index.tsx +++ b/src/screens/staking/index.tsx @@ -1,5 +1,6 @@ import useTranslation from "next-translate/useTranslation"; -import { useRef } from "react"; +import posthog from "posthog-js"; +import { useEffect, useRef } from "react"; import LayoutVal from "@src/components/layout_val"; import Tooltip from "@src/components/tooltip"; @@ -24,6 +25,12 @@ const Staking = () => { const hasConnectedWallets = getHasConnectedWallets(stakingRef.current.state); + useEffect(() => { + posthog.opt_in_capturing(); + + return () => posthog.opt_out_capturing(); + }, []); + const extraInfo = ( <>
From 330866a5042ed74b065a1d68d678c360deb20d0e Mon Sep 17 00:00:00 2001 From: Julien Delaigues <0xju@pm.me> Date: Tue, 2 Apr 2024 10:36:10 +0800 Subject: [PATCH 5/6] feat: track wallet's address when staking, unstaking, claming reward --- .../components/staking_section/claim_rewards_modal.tsx | 5 ++++- .../staking/components/staking_section/staking_modal.tsx | 1 + .../staking/components/staking_section/unstaking_modal.tsx | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/screens/staking/components/staking_section/claim_rewards_modal.tsx b/src/screens/staking/components/staking_section/claim_rewards_modal.tsx index 77255c80..792ab69d 100644 --- a/src/screens/staking/components/staking_section/claim_rewards_modal.tsx +++ b/src/screens/staking/components/staking_section/claim_rewards_modal.tsx @@ -121,7 +121,10 @@ const ClaimRewardsModal = () => { stakingRef.current.postHog?.capture( PostHogCustomEvent.ClaimedRewards, - claimableRewardsForNetwork, + { + ...claimableRewardsForNetwork, + walletAddress: selectedAccount.address, + }, ); toastSuccess({ diff --git a/src/screens/staking/components/staking_section/staking_modal.tsx b/src/screens/staking/components/staking_section/staking_modal.tsx index 4aef207a..5afe6741 100644 --- a/src/screens/staking/components/staking_section/staking_modal.tsx +++ b/src/screens/staking/components/staking_section/staking_modal.tsx @@ -151,6 +151,7 @@ const StakingModal = () => { stakingRef.current.postHog?.capture(PostHogCustomEvent.StakedTokens, { amount, denom: mainNetworkDenom[selectedAccount.networkId], + walletAddress: selectedAccount.address, }); toastSuccess({ diff --git a/src/screens/staking/components/staking_section/unstaking_modal.tsx b/src/screens/staking/components/staking_section/unstaking_modal.tsx index 6b6fd3b9..bda5ad37 100644 --- a/src/screens/staking/components/staking_section/unstaking_modal.tsx +++ b/src/screens/staking/components/staking_section/unstaking_modal.tsx @@ -152,7 +152,11 @@ const UnstakingModal = () => { stakingRef.current.postHog?.capture( PostHogCustomEvent.UnstakedTokens, - { amount, denom: mainNetworkDenom[selectedAccount.networkId] }, + { + amount, + denom: mainNetworkDenom[selectedAccount.networkId], + walletAddress: selectedAccount.address, + }, ); toastSuccess({ From 6330ba670005b627a715f8d4d4e2d5c5cb98cc6e Mon Sep 17 00:00:00 2001 From: Julien Delaigues <0xju@pm.me> Date: Tue, 2 Apr 2024 17:55:10 +0800 Subject: [PATCH 6/6] chore: update terms of services and private policy --- public/locales/en/policy.json | 2 +- public/locales/en/terms_and_conditions.json | 2 +- public/locales/zh-CN/policy.json | 2 +- .../locales/zh-CN/terms_and_conditions.json | 2 +- public/locales/zh-HK/policy.json | 2 +- .../locales/zh-HK/terms_and_conditions.json | 2 +- src/screens/policy/index.tsx | 70 +++++++++++++++++++ src/screens/terms_and_conditions/index.tsx | 12 ++++ 8 files changed, 88 insertions(+), 6 deletions(-) diff --git a/public/locales/en/policy.json b/public/locales/en/policy.json index 0ee608b5..e9dd9e73 100644 --- a/public/locales/en/policy.json +++ b/public/locales/en/policy.json @@ -3,5 +3,5 @@ "description1": "<0>This policy describes the privacy practices of Forbole Technology Limited (“<1>Forbole”, “we” or “us”) with respect to the Forbole website located at <2>https://forbole.com and related content, applications, features, and functionality (collectively, the “<1>Platform”) and the various services that we offer to you on or through the Platform (the “<1>Services”). Users of our Services are referred to as “<1>users” or “you”.", "description2": "Please read this policy and the Forbole Terms of Use carefully before engaging with the Platform or using the Services.", "title": "Forbole Privacy Policy", - "updatedDate": "Last updated: 19 July 2023" + "updatedDate": "Last updated: 14 March 2024" } diff --git a/public/locales/en/terms_and_conditions.json b/public/locales/en/terms_and_conditions.json index 96335ed4..11324389 100644 --- a/public/locales/en/terms_and_conditions.json +++ b/public/locales/en/terms_and_conditions.json @@ -1,5 +1,5 @@ { "desc": " ", "title": "Forbole Terms of Use", - "updatedDate": "Last updated: 19 July 2023" + "updatedDate": "Last updated: 14 March 2024" } diff --git a/public/locales/zh-CN/policy.json b/public/locales/zh-CN/policy.json index 9fbd807f..42d3a6b8 100644 --- a/public/locales/zh-CN/policy.json +++ b/public/locales/zh-CN/policy.json @@ -3,5 +3,5 @@ "description1": "<0>This policy describes the privacy practices of Forbole Technology Limited (“<1>Forbole”, “we” or “us”) with respect to the Forbole website located at <2>https://forbole.com and related content, applications, features, and functionality (collectively, the “<1>Platform”) and the various services that we offer to you on or through the Platform (the “<1>Services”). Users of our Services are referred to as “<1>users” or “you”.", "description2": "在参与平台或使用服务之前,请仔细阅读本政策和 Forbole 使用条款。", "title": "Forbole 私隐政策", - "updatedDate": "最后更新日期:2023 年 7 月 19 日" + "updatedDate": "最后更新日期:2024 年 3 月 14 日" } diff --git a/public/locales/zh-CN/terms_and_conditions.json b/public/locales/zh-CN/terms_and_conditions.json index d8c01e74..3c7d7338 100644 --- a/public/locales/zh-CN/terms_and_conditions.json +++ b/public/locales/zh-CN/terms_and_conditions.json @@ -1,5 +1,5 @@ { "desc": "条款及细则,请以英文版本为准。", "title": "Forbole 条款及细则", - "updatedDate": "最后更新日期:2023 年 7 月 19 日" + "updatedDate": "最后更新日期:2024 年 3 月 14 日" } diff --git a/public/locales/zh-HK/policy.json b/public/locales/zh-HK/policy.json index 8fccc332..dff299ff 100644 --- a/public/locales/zh-HK/policy.json +++ b/public/locales/zh-HK/policy.json @@ -3,5 +3,5 @@ "description1": "<0>This policy describes the privacy practices of Forbole Technology Limited (“<1>Forbole”, “we” or “us”) with respect to the Forbole website located at <2>https://forbole.com and related content, applications, features, and functionality (collectively, the “<1>Platform”) and the various services that we offer to you on or through the Platform (the “<1>Services”). Users of our Services are referred to as “<1>users” or “you”.", "description2": "在參與平台或使用服務之前,請仔細閱讀本政策和 Forbole 使用條款。", "title": "Forbole 私隱政策", - "updatedDate": "最後更新日期:2023 年 7 月 19 日" + "updatedDate": "最後更新日期:2024 年 3 月 14 日" } diff --git a/public/locales/zh-HK/terms_and_conditions.json b/public/locales/zh-HK/terms_and_conditions.json index cef53deb..290ad429 100644 --- a/public/locales/zh-HK/terms_and_conditions.json +++ b/public/locales/zh-HK/terms_and_conditions.json @@ -1,5 +1,5 @@ { "desc": "條款及細則,請以英文版本為準。", "title": "Forbole 條款及細則", - "updatedDate": "最後更新日期:2023 年 7 月 19 日" + "updatedDate": "最後更新日期:2024 年 3 月 14 日" } diff --git a/src/screens/policy/index.tsx b/src/screens/policy/index.tsx index 4d3ba15a..7516c61e 100644 --- a/src/screens/policy/index.tsx +++ b/src/screens/policy/index.tsx @@ -528,6 +528,76 @@ const Policy = () => { or similar technologies.

+
+ + (iv) anonymized identifiers. We + also may use Posthog and Sentry to help us better understand + the usage and error data in order to improve our user + experience. Please refer to each service provider’s Terms of + Use and Privacy Policy for more information: + +
+ (i) Posthog's Terms of Use:{" "} + + https://posthog.com/terms + +
+
+ (ii) Posthog’s Privacy Policy:{" "} + + https://posthog.com/privacy + +
+
+ (iii) Sentry’s Terms of Use:{" "} + + https://sentry.io/terms/ + +
+
+ (iv) Sentry’s Privacy Policy:{" "} + + https://sentry.io/privacy/ + +
+

diff --git a/src/screens/terms_and_conditions/index.tsx b/src/screens/terms_and_conditions/index.tsx index 36e12dff..efb63440 100644 --- a/src/screens/terms_and_conditions/index.tsx +++ b/src/screens/terms_and_conditions/index.tsx @@ -267,6 +267,18 @@ const TermsAndConditions = () => { will subsist now or in the future in any part of the world.

+

+ 2.8We've integrated{" "} + Posthog, a third-party + analytics and behavioral tracking tool, into our platform to + gain insights into user interactions and behaviors. This + enables us to continually enhance and optimize our services, + ensuring an improved user experience for you. By accepting our + Terms of Service, you're also agreeing to the{" "} + Terms of Service + of Posthog. +

+

3. Disclaimers