diff --git a/package-lock.json b/package-lock.json index 8c9a2d1..9ba242a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,7 @@ "axios": "^1.6.7", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", + "cookies-next": "^4.1.1", "date-fns": "^3.3.1", "ethers": "5.7", "framer-motion": "^11.0.8", @@ -49,7 +50,7 @@ "react-circular-progressbar": "^2.1.0", "react-dom": "^18.2.0", "react-hook-form": "^7.51.0", - "react-ios-pwa-prompt": "^1.8.4", + "react-icons": "^5.0.1", "react-modal-sheet": "^2.2.0", "react-pull-to-refresh": "^2.0.1", "react-qr-code": "^2.0.12", @@ -12423,6 +12424,11 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -16209,11 +16215,34 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-es": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.0.0.tgz", "integrity": "sha512-mWYvfOLrfEc996hlKcdABeIiPHUPC6DM2QYZdGGOvhOTbA3tjm2eBwqlJpoFdjC89NI4Qt6h0Pu06Mp+1Pj5OQ==" }, + "node_modules/cookies-next": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/cookies-next/-/cookies-next-4.1.1.tgz", + "integrity": "sha512-20QaN0iQSz87Os0BhNg9M71eM++gylT3N5szTlhq2rK6QvXn1FYGPB4eAgU4qFTunbQKhD35zfQ95ZWgzUy3Cg==", + "dependencies": { + "@types/cookie": "^0.6.0", + "@types/node": "^16.10.2", + "cookie": "^0.6.0" + } + }, + "node_modules/cookies-next/node_modules/@types/node": { + "version": "16.18.91", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.91.tgz", + "integrity": "sha512-h8Q4klc8xzc9kJKr7UYNtJde5TU2qEePVyH3WyzJaUC+3ptyc5kPQbWOIUcn8ZsG5+KSkq+P0py0kC0VqxgAXw==" + }, "node_modules/copy-to-clipboard": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", @@ -26168,13 +26197,12 @@ } } }, - "node_modules/react-ios-pwa-prompt": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/react-ios-pwa-prompt/-/react-ios-pwa-prompt-1.8.4.tgz", - "integrity": "sha512-y2dMzPZWWcdCClb1JItMJkyEfapnJe/Nz2bC8HIMaXTRA4hQfL1nwxsjiENwKESYKQdm6wrrS4b8qD2Mx/bwtw==", + "node_modules/react-icons": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz", + "integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==", "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "react": "*" } }, "node_modules/react-is": { diff --git a/package.json b/package.json index 636830a..f239e40 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "axios": "^1.6.7", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", + "cookies-next": "^4.1.1", "date-fns": "^3.3.1", "ethers": "5.7", "framer-motion": "^11.0.8", @@ -59,7 +60,7 @@ "react-circular-progressbar": "^2.1.0", "react-dom": "^18.2.0", "react-hook-form": "^7.51.0", - "react-ios-pwa-prompt": "^1.8.4", + "react-icons": "^5.0.1", "react-modal-sheet": "^2.2.0", "react-pull-to-refresh": "^2.0.1", "react-qr-code": "^2.0.12", diff --git a/src/app/assets/img/icons/firefox-install.png b/src/app/assets/img/icons/firefox-install.png new file mode 100644 index 0000000..13b3a5f Binary files /dev/null and b/src/app/assets/img/icons/firefox-install.png differ diff --git a/src/app/components/AddToHomeScreen/AddToHomeScreen.tsx b/src/app/components/AddToHomeScreen/AddToHomeScreen.tsx new file mode 100644 index 0000000..9d76a36 --- /dev/null +++ b/src/app/components/AddToHomeScreen/AddToHomeScreen.tsx @@ -0,0 +1,96 @@ +import React, { useState, useEffect } from 'react'; +import { setCookie, getCookie } from 'cookies-next'; +import dynamic from 'next/dynamic'; + +const ModuleLoading = () =>

Loading...

; +const AddToIosSafari = dynamic(() => import('./AddToIosSafari'), { loading: () => }); +const AddToMobileChrome = dynamic(() => import('./AddToMobileChrome'), { loading: () => }); +const AddToMobileFirefox = dynamic(() => import('./AddToMobileFirefox'), { loading: () => }); +const AddToMobileFirefoxIos = dynamic(() => import('./AddToMobileFirefoxIos'), { loading: () => }); +const AddToMobileChromeIos = dynamic(() => import('./AddToMobileChromeIos'), { loading: () => }); +const AddToSamsung = dynamic(() => import('./AddToSamsung'), { loading: () => }); +const AddToOtherBrowser = dynamic(() => import('./AddToOtherBrowser'), { loading: () => }); + +import useUserAgent from '@/app/hooks/useUserAgent'; + +type AddToHomeScreenPromptType = 'safari' | 'chrome' | 'firefox' | 'other' | 'firefoxIos' | 'chromeIos' | 'samsung' | ''; +const COOKIE_NAME = 'addToHomeScreenPrompt'; + +export default function AddToHomeScreen() { + const [displayPrompt, setDisplayPrompt] = useState(''); + const { userAgent, isMobile, isStandalone, isIOS } = useUserAgent(); + + const closePrompt = () => { + setDisplayPrompt(''); + }; + + const doNotShowAgain = () => { + // Create date 1 year from now + const date = new Date(); + date.setFullYear(date.getFullYear() + 1); + setCookie(COOKIE_NAME, 'dontShow', { expires: date }); // Set cookie for a year + setDisplayPrompt(''); + }; + + useEffect(() => { + const addToHomeScreenPromptCookie = getCookie(COOKIE_NAME); + + if (addToHomeScreenPromptCookie !== 'dontShow') { + // Only show prompt if user is on mobile and app is not installed + if (isMobile && !isStandalone) { + if (userAgent === 'Safari') { + setDisplayPrompt('safari'); + } else if (userAgent === 'Chrome') { + setDisplayPrompt('chrome'); + } else if (userAgent === 'Firefox') { + setDisplayPrompt('firefox'); + } else if (userAgent === 'FirefoxiOS') { + setDisplayPrompt('firefoxIos'); + } else if (userAgent === 'ChromeiOS') { + setDisplayPrompt('chromeIos'); + } else if (userAgent === 'SamsungBrowser') { + setDisplayPrompt('samsung'); + } else { + setDisplayPrompt('other'); + } + } + } else { + } + }, [userAgent, isMobile, isStandalone, isIOS]); + + const Prompt = () => ( + <> + { + { + 'safari': , + 'chrome': , + 'firefox': , + 'firefoxIos': , + 'chromeIos': , + 'samsung': , + 'other': , + '': <> + }[displayPrompt] + } + + ) + + return ( + <> + { + displayPrompt !== '' + ? + <> +
+ +
+ + : + <> + } + + ); +} \ No newline at end of file diff --git a/src/app/components/AddToHomeScreen/AddToIosSafari.tsx b/src/app/components/AddToHomeScreen/AddToIosSafari.tsx new file mode 100644 index 0000000..5219d50 --- /dev/null +++ b/src/app/components/AddToHomeScreen/AddToIosSafari.tsx @@ -0,0 +1,43 @@ +import React from 'react' + +import { TbShare2 } from 'react-icons/tb' +import { AiOutlinePlusSquare } from 'react-icons/ai' +import { FaTimes } from 'react-icons/fa' +import { ImArrowDown } from 'react-icons/im' + +interface Props { + closePrompt: () => void; + doNotShowAgain: () => void; +} + +export default function AddToIosSafari(props: Props) { + const { closePrompt, doNotShowAgain } = props; + + return ( +
+
+ +

For the best experience, we recommend installing the Valley Trader app to your home screen!

+
+

Click the

+ +

icon

+
+
+

Scroll down and then click:

+
+

Add to Home Screen

+ +
+
+ + +
+ +
+ ) +} diff --git a/src/app/components/AddToHomeScreen/AddToMobileChrome.tsx b/src/app/components/AddToHomeScreen/AddToMobileChrome.tsx new file mode 100644 index 0000000..d098d43 --- /dev/null +++ b/src/app/components/AddToHomeScreen/AddToMobileChrome.tsx @@ -0,0 +1,40 @@ +import React from 'react' + +import { FaTimes } from 'react-icons/fa' +import { HiDotsVertical } from 'react-icons/hi' +import { MdAddToHomeScreen } from 'react-icons/md' +import { ImArrowUp } from 'react-icons/im' + +interface Props { + closePrompt: () => void; + doNotShowAgain: () => void; +} + +export default function AddToMobileChrome(props: Props) { + const { closePrompt, doNotShowAgain } = props; + + return ( +
+ +
+ +

For the best experience, we recommend installing the Valley Trader app to your home screen!

+
+

Click the

+ +

icon

+
+
+

Scroll down and then click:

+
+ +

Add to Home Screen

+
+
+ +
+
+ ) +} diff --git a/src/app/components/AddToHomeScreen/AddToMobileChromeIos.tsx b/src/app/components/AddToHomeScreen/AddToMobileChromeIos.tsx new file mode 100644 index 0000000..05c0fa5 --- /dev/null +++ b/src/app/components/AddToHomeScreen/AddToMobileChromeIos.tsx @@ -0,0 +1,41 @@ +import React from 'react' + +import { AiOutlinePlusSquare } from 'react-icons/ai' +import { FaTimes } from 'react-icons/fa' +import { ImArrowUp } from 'react-icons/im' +import { TbShare2 } from 'react-icons/tb' + +interface Props { + closePrompt: () => void; + doNotShowAgain: () => void; +} + +export default function AddToMobileChromeIos(props: Props) { + const { closePrompt, doNotShowAgain } = props; + + return ( +
+
+ + +

For the best experience, we recommend installing the Valley Trader app to your home screen!

+
+

Click the

+ +

icon

+
+
+

Scroll down and then click:

+
+

Add to Home Screen

+ +
+
+ +
+ +
+ ) +} \ No newline at end of file diff --git a/src/app/components/AddToHomeScreen/AddToMobileFirefox.tsx b/src/app/components/AddToHomeScreen/AddToMobileFirefox.tsx new file mode 100644 index 0000000..b012f8d --- /dev/null +++ b/src/app/components/AddToHomeScreen/AddToMobileFirefox.tsx @@ -0,0 +1,44 @@ +import React from 'react' +import Image from 'next/image' + +import { FaTimes } from 'react-icons/fa' +import { HiDotsVertical } from 'react-icons/hi' +import { ImArrowDownRight } from 'react-icons/im' +import ffIcon from '@/app/assets/img/icons/firefox-install.png' + +interface Props { + closePrompt: () => void; + doNotShowAgain: () => void; +} + +export default function AddToMobileFirefox(props: Props) { + const { closePrompt, doNotShowAgain } = props; + + return ( +
+
+ +

For the best experience, we recommend installing the Valley Trader app to your home screen!

+
+

Click the

+ +

icon

+
+
+

Scroll down and then click:

+
+
+ Firefox install icon +

Install

+
+
+
+ + +
+ +
+ ) +} diff --git a/src/app/components/AddToHomeScreen/AddToMobileFirefoxIos.tsx b/src/app/components/AddToHomeScreen/AddToMobileFirefoxIos.tsx new file mode 100644 index 0000000..b9ddce9 --- /dev/null +++ b/src/app/components/AddToHomeScreen/AddToMobileFirefoxIos.tsx @@ -0,0 +1,48 @@ +import React from 'react' + +import { AiOutlinePlusSquare } from 'react-icons/ai' +import { FaTimes, FaBars } from 'react-icons/fa' +import { ImArrowDown } from 'react-icons/im' +import { FiShare } from 'react-icons/fi' + +interface Props { + closePrompt: () => void; + doNotShowAgain: () => void; +} + +export default function AddToMobileFirefoxIos(props: Props) { + const { closePrompt, doNotShowAgain } = props; + + return ( +
+
+ +

For the best experience, we recommend installing the Valley Trader app to your home screen!

+
+

Click the

+ +

icon

+
+
+

Scroll down and then click:

+
+

Share

+ +
+
+
+

Then click:

+
+

Add to Home Screen

+ +
+
+ + +
+ +
+ ) +} diff --git a/src/app/components/AddToHomeScreen/AddToOtherBrowser.tsx b/src/app/components/AddToHomeScreen/AddToOtherBrowser.tsx new file mode 100644 index 0000000..9a13639 --- /dev/null +++ b/src/app/components/AddToHomeScreen/AddToOtherBrowser.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import Link from 'next/link' + +import { FaTimes } from 'react-icons/fa' + +interface Props { + closePrompt: () => void; + doNotShowAgain: () => void; +} + +export default function AddToOtherBrowser(props: Props) { + const { closePrompt, doNotShowAgain } = props; + const searchUrl = `https://www.google.com/search?q=add+to+home+screen+for+common-mobile-browsers`; + + return ( +
+
+ +

For the best experience, we recommend installing the Valley Trader app to your home screen!

+
+

Unfortunately, we were unable to determine which browser you are using. Please search for how to install a web app for your browser.

+ Try This Search +
+ +
+ +
+ ) +} \ No newline at end of file diff --git a/src/app/components/AddToHomeScreen/AddToSamsung.tsx b/src/app/components/AddToHomeScreen/AddToSamsung.tsx new file mode 100644 index 0000000..d58a628 --- /dev/null +++ b/src/app/components/AddToHomeScreen/AddToSamsung.tsx @@ -0,0 +1,48 @@ +import React from 'react' + +import { AiOutlinePlusSquare } from 'react-icons/ai' +import { FaTimes, FaBars } from 'react-icons/fa' +import { ImArrowDown } from 'react-icons/im' +import { FiShare } from 'react-icons/fi' +import { TfiPlus } from 'react-icons/tfi' + +interface Props { + closePrompt: () => void; + doNotShowAgain: () => void; +} + +export default function AddToSamsung(props: Props) { + const { closePrompt, doNotShowAgain } = props; + + return ( +
+
+ +

For the best experience, we recommend installing the Valley Trader app to your home screen!

+
+

Click the

+ +

icon

+
+
+

Scroll down and then click:

+
+ +

Add page to

+
+
+
+

Then select:

+
+

Home screen

+
+
+ + +
+ +
+ ) +} diff --git a/src/app/hooks/useUserAgent.tsx b/src/app/hooks/useUserAgent.tsx new file mode 100644 index 0000000..5ddbf00 --- /dev/null +++ b/src/app/hooks/useUserAgent.tsx @@ -0,0 +1,57 @@ +import React, { useEffect, useState } from 'react'; + +export default function useUserAgent() { + /** + * we set our initial state as null because we don't know what the user agent is yet + * that way we can check if the user agent has been set or not + */ + const [isMobile, setIsMobile] = useState(null); + const [userAgent, setUserAgent] = useState(null); + const [isIOS, setIsIOS] = useState(null); + const [isStandalone, setIsStandalone] = useState(null); + const [userAgentString, setUserAgentString] = useState(null); + + useEffect(() => { + if (window) { + const userAgentString = window.navigator.userAgent; + setUserAgentString(userAgentString); + let userAgent; + + /** + * Parse user agent string to determine browser + * The order of the if statements is important because some browsers + * have multiple matches in their user agent string + */ + if (userAgentString.indexOf('SamsungBrowser') > -1) { + userAgent = 'SamsungBrowser'; + } else if (userAgentString.indexOf('Firefox') > -1) { + userAgent = 'Firefox'; + } else if (userAgentString.indexOf('FxiOS') > -1) { + userAgent = 'FirefoxiOS'; + } else if (userAgentString.indexOf('CriOS') > -1) { + userAgent = 'ChromeiOS'; + } else if (userAgentString.indexOf('Chrome') > -1) { + userAgent = 'Chrome'; + } else if (userAgentString.indexOf('Safari') > -1) { + userAgent = 'Safari'; + } else { + userAgent = 'unknown'; + } + setUserAgent(userAgent); + + // Check if user agent is mobile + const isIOS = userAgentString.match(/iPhone|iPad|iPod/i); + const isAndroid = userAgentString.match(/Android/i); + setIsIOS(isIOS ? true : false); + const isMobile = isIOS || isAndroid; + setIsMobile(!!isMobile); + + // Check if app is installed (if it's installed we wont show the prompt) + if (window.matchMedia('(display-mode: standalone)').matches) { + setIsStandalone(true); + } + } + }, []); + + return { isMobile, userAgent, isIOS, isStandalone, userAgentString }; +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 65bf4d9..9e40f88 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -31,7 +31,6 @@ import { AnimatePresence, LayoutGroup } from 'framer-motion'; import { sepolia } from 'viem/chains'; import BottomNavbar from './components/BottomNav/BottomNav'; // pwa -import PWAPrompt from 'react-ios-pwa-prompt'; export default function RootLayout({ @@ -140,12 +139,7 @@ export default function RootLayout({ - +
{auth}
{drawer}
diff --git a/src/app/page.tsx b/src/app/page.tsx index db5af04..d2f60e4 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,50 +1,46 @@ 'use client'; +import React, { useState, useEffect } from 'react'; +import AddToHomeScreen from '@/app/components/AddToHomeScreen/AddToHomeScreen'; +import { motion } from 'framer-motion'; +import dynamic from 'next/dynamic'; -import Head from 'next/head'; - -// React -import * as React from 'react'; -import { useState, useEffect } from 'react'; - -// Web3auth -import { Web3AuthNoModal } from '@web3auth/no-modal'; -import { CHAIN_NAMESPACES, IProvider, WALLET_ADAPTERS } from '@web3auth/base'; -import { EthereumPrivateKeyProvider } from '@web3auth/ethereum-provider'; -import { OpenloginAdapter } from '@web3auth/openlogin-adapter'; - -import { useDispatch } from 'react-redux'; - -// Components -import Balance from '@/app/components/Balance/Balance'; -import useCreateKernal from '@/app/utils/useCreateKernal'; -import Link from 'next/link'; -// -import { setKernalClient } from '@/GlobalRedux/Features/kernalClient/kernalClientSlice'; - -import { parseEther } from 'viem'; -import { useRouter } from 'next/navigation'; +import useUserAgent from '@/app/hooks/useUserAgent'; export default function HomePage() { - const router = useRouter(); + const [welcomeMessage, setWelcomeMessage] = + useState('Checking device...'); + const { isMobile, userAgentString, userAgent } = useUserAgent(); useEffect(() => { - router.push('/home'); -}, []); + const welcomeMessage = isMobile + ? 'You are on a mobile device.' + : 'You are on a desktop device. Please use a mobile device to view this app.'; + setWelcomeMessage(welcomeMessage); + }, [isMobile]); - - return ( -
- - {/*
- - Home - -
*/} +
+ + Welcome to Payments + + + {welcomeMessage} + + {userAgentString && ( +

{userAgentString}

+ )} + +
); }