Instantly share code, notes, and snippets.
Created
November 8, 2023 08:04
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save savayer/3748169b9d43f6b384a5db6978cc1d64 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Cookies from 'js-cookie'; | |
import React, { useEffect, useState } from 'react'; | |
import { Close } from './icons'; | |
import { classNames, getOs } from './utils'; | |
/** | |
* Lookup key for the Cookie value to hide the app banner for a period of time. | |
**/ | |
const APP_BANNER_IS_HIDDEN = 'app_banner_is_hidden'; | |
/** | |
* Function that sets the app banner as hidden and also sets the app banner's hidden | |
* TTL cookie. | |
* @callback HideAppBannerFunction | |
* @returns {undefined} | |
* | |
* @typedef UseAppUrlOptions | |
* @property {string} playStoreUrl Google Play Store URL. | |
* @property {string} appStoreUrl IOS App Store URL. | |
* | |
* @typedef BaseAppBannerProps | |
* @property {string} title Title of the app banner. | |
* @property {string} description Description of the app banner. | |
* @property {string} linkText The text for the app banner's view/install app link element. | |
* @property {React.ReactElement} logo The application's logo. | |
* | |
* @typedef {BaseAppBannerProps & UseAppUrlOptions} AppBannerProps | |
**/ | |
/** | |
* Hook for managing the app banner's hiding logic. | |
* | |
* @param {number | Date} [hiddenTtl=90] The amount of time that the app banner should be hidden | |
* for before prompting the user again once the user decides to hide it. Could be either a date or a | |
* number value for the number of days. Default is 90 days (approx. 3 months). | |
* | |
* @returns {[boolean, HideAppBannerFunction]} A tuple: first item is the app banner's hidden | |
* state, the second item is a function to set the app banner as hidden. | |
**/ | |
function useHideAppBanner(hiddenTtl = 90) { | |
const [isHidden, setIsHidden] = useState(true); | |
useEffect(() => { | |
if (Cookies.get(APP_BANNER_IS_HIDDEN) === undefined) { | |
setIsHidden(false); | |
} | |
}, []); | |
const hide = () => { | |
setIsHidden(true); | |
Cookies.set(APP_BANNER_IS_HIDDEN, true, { expires: hiddenTtl }); | |
}; | |
return [isHidden, hide]; | |
} | |
/** | |
* Hook for retrieving the mobile app URL based on the user agent. | |
* | |
* @param options {UseAppUrlOptions} | |
* | |
* @returns {string | null} The application URL if the user agent is either on an Android or IOS | |
* operating system, `null` otherwise. | |
**/ | |
function useAppUrl({ playStoreUrl, appStoreUrl }) { | |
const [appUrl, setAppUrl] = useState(null); | |
useEffect(() => { | |
const os = getOs(window.navigator); | |
switch (os) { | |
case 'android': | |
setAppUrl(playStoreUrl); | |
break; | |
case 'ios': | |
setAppUrl(appStoreUrl); | |
break; | |
} | |
}, [playStoreUrl, appStoreUrl]); | |
return appUrl; | |
} | |
/** | |
* @param {AppBannerProps} props | |
**/ | |
export function AppBanner({ | |
title, | |
description, | |
logo, | |
playStoreUrl, | |
appStoreUrl, | |
linkText, | |
}) { | |
const [isAppBannerHidden, hideAppBanner] = useHideAppBanner(); | |
const appUrl = useAppUrl({ playStoreUrl, appStoreUrl }); | |
return ( | |
<div | |
className={classNames( | |
'flex items-center justify-between bg-gray-100 p-4', | |
isAppBannerHidden && '!hidden', | |
)} | |
> | |
<div className="flex items-center"> | |
<Close | |
className="h-3 shrink-0 cursor-pointer fill-gray-600" | |
onClick={hideAppBanner} | |
/> | |
<div className="mx-3 h-14 w-14 shrink-0 rounded-lg border border-gray-200 bg-white p-2"> | |
{logo} | |
</div> | |
<div className="flex-1"> | |
<h1 className="w-full text-sm font-medium text-gray-600">{title}</h1> | |
<p className="w-full text-xs text-gray-400">{description}</p> | |
</div> | |
</div> | |
<a | |
href={appUrl} | |
target="_blank" | |
rel="noreferrer noopenner" | |
className="ml-4 cursor-pointer font-semibold text-blue-500" | |
> | |
{linkText} | |
</a> | |
</div> | |
); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment