diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index 222063a918..fea6aff841 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -3168,5 +3168,44 @@ }, "dropdownNoItems": { "message": "No items" + }, + "earnings": { + "message": "Earnings" + }, + "earningsInfoTooltip": { + "message": "Earnings are only an estimation of your daily and monthly activity, including ad views and interactions with referral links. At the end of each month, your RP (reward points) will be converted into TKEY and distributed to your Tezos address. The more RP you accumulate, the greater your rewards will be." + }, + "ads": { + "message": "Ads" + }, + "today": { + "message": "Today" + }, + "activeFeatures": { + "message": "Active features" + }, + "advertisingFeatureDescription": { + "message": "Get RP by viewing ads" + }, + "advertisingFeatureTooltip": { + "message": "The advertising feature is used to display ads within Temple Wallet and on websites. To earn TKEY and enable ads, we request your permission to share your wallet address and IP, this information is used solely to serve you relevant ads and distribute rewards." + }, + "referralLinksFeatureDescription": { + "message": "Get RP while use favorite websites" + }, + "referralLinksFeatureTooltip": { + "message": "The referral links feature allows users to engage with affiliate offers from our partners. These offers will appear as links while you browse your favorite websites. To enable this feature, we request your permission to share your wallet address and IP address, this information is used solely to serve you relevant offers and distribute rewards." + }, + "achievements": { + "message": "Achievements" + }, + "lifetimeEarnings": { + "message": "Lifetime earnings" + }, + "noEarningsFound": { + "message": "No earnings found" + }, + "somethingWentWrong": { + "message": "Something went wrong" } } diff --git a/src/app/PageRouter.tsx b/src/app/PageRouter.tsx index 3097171b5d..69b6661f5c 100644 --- a/src/app/PageRouter.tsx +++ b/src/app/PageRouter.tsx @@ -30,6 +30,7 @@ import { Notifications, NotificationsItem } from 'lib/notifications/components'; import { useTempleClient } from 'lib/temple/front'; import * as Woozie from 'lib/woozie'; +import { RewardsPage } from './pages/Rewards'; import { StakingPage } from './pages/Staking'; import { WithDataLoading } from './WithDataLoading'; @@ -98,6 +99,7 @@ const ROUTE_MAP = Woozie.createMap([ ['/attention', onlyReady(onlyInFullPage(() => ))], ['/notifications', onlyReady(() => )], ['/notifications/:id', onlyReady(({ id }) => )], + ['/rewards', onlyReady(() => )], ['*', () => ] ]); diff --git a/src/app/atoms/DonationBanner/DonationBanner.tsx b/src/app/atoms/DonationBanner/DonationBanner.tsx deleted file mode 100644 index a3310101fb..0000000000 --- a/src/app/atoms/DonationBanner/DonationBanner.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React, { FC } from 'react'; - -import { Anchor } from 'app/atoms/Anchor'; -import { ReactComponent as Ukraine } from 'app/icons/ukraine.svg'; -import { T } from 'lib/i18n'; - -import { DonationBannerSelectors } from './selectors'; - -const DONATE_MAD_FISH_URL = 'https://donate.mad.fish'; - -export const DonationBanner: FC = () => ( - -
-
- - - -
-
- -
-
-
-); diff --git a/src/app/atoms/DonationBanner/selectors.ts b/src/app/atoms/DonationBanner/selectors.ts deleted file mode 100644 index cc6fca5c88..0000000000 --- a/src/app/atoms/DonationBanner/selectors.ts +++ /dev/null @@ -1,3 +0,0 @@ -export enum DonationBannerSelectors { - ukraineDonationBanner = 'DonationBanner/Ukraine Donation Banner' -} diff --git a/src/app/hooks/use-partners-promotion-settings.tsx b/src/app/hooks/use-partners-promotion-settings.tsx new file mode 100644 index 0000000000..7ad32e9b02 --- /dev/null +++ b/src/app/hooks/use-partners-promotion-settings.tsx @@ -0,0 +1,47 @@ +import { ChangeEvent } from 'react'; + +import { useDispatch } from 'react-redux'; + +import { togglePartnersPromotionAction } from 'app/store/partners-promotion/actions'; +import { useShouldShowPartnersPromoSelector } from 'app/store/partners-promotion/selectors'; +import { t } from 'lib/i18n'; +import { useConfirm } from 'lib/ui/dialog'; + +export const usePartnersPromotionSettings = () => { + const dispatch = useDispatch(); + const confirm = useConfirm(); + + const isEnabled = useShouldShowPartnersPromoSelector(); + + const handleHidePromotion = async () => { + const confirmed = await confirm({ + title: t('closePartnersPromotion'), + children: t('closePartnersPromoConfirm'), + comfirmButtonText: t('disable') + }); + + if (confirmed) { + dispatch(togglePartnersPromotionAction(false)); + } + }; + + const handleShowPromotion = async () => { + const confirmed = await confirm({ + title: t('enablePartnersPromotionConfirm'), + children: t('enablePartnersPromotionDescriptionConfirm'), + comfirmButtonText: t('enable') + }); + + if (confirmed) { + dispatch(togglePartnersPromotionAction(true)); + } + }; + + const setEnabled = (toChecked: boolean, event?: ChangeEvent) => { + event?.preventDefault(); + + return toChecked ? handleShowPromotion() : handleHidePromotion(); + }; + + return { isEnabled, setEnabled }; +}; diff --git a/src/app/hooks/use-referral-links-settings.tsx b/src/app/hooks/use-referral-links-settings.tsx new file mode 100644 index 0000000000..309982e46c --- /dev/null +++ b/src/app/hooks/use-referral-links-settings.tsx @@ -0,0 +1,67 @@ +import React, { ChangeEvent, useCallback } from 'react'; + +import { useDispatch } from 'react-redux'; + +import { setAcceptedTermsVersionAction, setReferralLinksEnabledAction } from 'app/store/settings/actions'; +import { useAcceptedTermsVersionSelector, useReferralLinksEnabledSelector } from 'app/store/settings/selectors'; +import { + PRIVACY_POLICY_URL, + RECENT_TERMS_VERSION, + TERMS_OF_USE_URL, + TERMS_WITH_REFERRALS_VERSION +} from 'lib/constants'; +import { t, T } from 'lib/i18n'; +import { useConfirm } from 'lib/ui/dialog'; + +export const useReferralLinksSettings = () => { + const dispatch = useDispatch(); + const enabled = useReferralLinksEnabledSelector(); + const acceptedTermsVersion = useAcceptedTermsVersionSelector(); + const confirm = useConfirm(); + + const setEnabled = useCallback( + async (toChecked: boolean, event?: ChangeEvent) => { + event?.preventDefault(); + + if (toChecked && acceptedTermsVersion < TERMS_WITH_REFERRALS_VERSION) { + const confirmed = await confirm({ + title: , + description: ( + + + , + + + + ]} + /> + ), + comfirmButtonText: t('agreeAndContinue') + }); + + if (!confirmed) { + return; + } + } + + dispatch(setAcceptedTermsVersionAction(RECENT_TERMS_VERSION)); + dispatch(setReferralLinksEnabledAction(toChecked)); + }, + [acceptedTermsVersion, confirm, dispatch] + ); + + return { isEnabled: enabled, setEnabled }; +}; diff --git a/src/app/icons/triangle-down.svg b/src/app/icons/triangle-down.svg new file mode 100644 index 0000000000..cff0a93f49 --- /dev/null +++ b/src/app/icons/triangle-down.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/app/layouts/PageLayout.selectors.ts b/src/app/layouts/PageLayout.selectors.ts index 17e613c8e2..60e409f646 100644 --- a/src/app/layouts/PageLayout.selectors.ts +++ b/src/app/layouts/PageLayout.selectors.ts @@ -1,4 +1,5 @@ export enum PageLayoutSelectors { backButton = 'Page Layout/Back Button', - skipButton = 'Page Layout/Skip Button' + skipButton = 'Page Layout/Skip Button', + rewardsButton = 'Page Layout/Rewards Button' } diff --git a/src/app/layouts/PageLayout.tsx b/src/app/layouts/PageLayout.tsx index 0ecf2594a9..c3e81736d5 100644 --- a/src/app/layouts/PageLayout.tsx +++ b/src/app/layouts/PageLayout.tsx @@ -14,7 +14,6 @@ import clsx from 'clsx'; import DocBg from 'app/a11y/DocBg'; import { Button } from 'app/atoms/Button'; -import { DonationBanner } from 'app/atoms/DonationBanner/DonationBanner'; import Spinner from 'app/atoms/Spinner/Spinner'; import { useAppEnv } from 'app/env'; import ErrorBoundary from 'app/ErrorBoundary'; @@ -35,6 +34,7 @@ import Header from './PageLayout/Header'; import { NewsletterOverlay } from './PageLayout/NewsletterOverlay/NewsletterOverlay'; import { OnRampOverlay } from './PageLayout/OnRampOverlay/OnRampOverlay'; import { ReactivateAdsOverlay } from './PageLayout/ReactivateAdsOverlay'; +import { RewardsButton } from './PageLayout/RewardsButton'; import { ShortcutAccountSwitchOverlay } from './PageLayout/ShortcutAccountSwitchOverlay'; import { PageLayoutSelectors } from './PageLayout.selectors'; @@ -116,7 +116,6 @@ type ToolbarProps = { hasBackAction?: boolean; step?: number; setStep?: (step: number) => void; - adShow?: boolean; skip?: boolean; attention?: boolean; }; @@ -126,15 +125,7 @@ export let ToolbarElement: HTMLDivElement | null = null; /** Defined for reference in code to highlight relation between multiple sticky elements & their sizes */ export const TOOLBAR_IS_STICKY = true; -const Toolbar: FC = ({ - pageTitle, - hasBackAction = true, - step, - setStep, - adShow = false, - skip, - attention -}) => { +const Toolbar: FC = ({ pageTitle, hasBackAction = true, step, setStep, skip, attention }) => { const { historyPosition, pathname } = useLocation(); const { fullPage } = useAppEnv(); const { setOnboardingCompleted } = useOnboardingProgress(); @@ -203,10 +194,8 @@ const Toolbar: FC = ({ return (
-
- {!isBackButtonAvailable && adShow && } - - {isBackButtonAvailable && ( + {isBackButtonAvailable ? ( +
- )} -
+
+ ) : ( + + )} {pageTitle && (

{pageTitle}

diff --git a/src/app/layouts/PageLayout/RewardsButton/firefox-star-animation.tsx b/src/app/layouts/PageLayout/RewardsButton/firefox-star-animation.tsx new file mode 100644 index 0000000000..40a6e403cc --- /dev/null +++ b/src/app/layouts/PageLayout/RewardsButton/firefox-star-animation.tsx @@ -0,0 +1,39 @@ +import React, { memo, useEffect, useRef } from 'react'; + +const starAnimationVideo = require('./star_animation.webm'); +const starAnimationPoster = require('./star_animation_poster.gif'); + +interface Props { + loop: boolean; +} + +export const FirefoxStarAnimation = memo(({ loop }) => { + const videoRef = useRef(null); + const prevLoopRef = useRef(loop); + + useEffect(() => { + if (loop && !prevLoopRef.current) { + videoRef.current!.play(); + } else if (!loop && prevLoopRef.current) { + videoRef.current!.currentTime = 0; + videoRef.current!.pause(); + } + prevLoopRef.current = loop; + }, [loop]); + + return ( +