-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(pcomparator): add pwa manifest (#79)
* chore(pcomparator): add pwa manifest * test transparent status bar * set background color * add dark theme manifest * add react-use-pwa to customize install prompt * add custom pwa prompt for ios * add missing translations
- Loading branch information
1 parent
fcb2f2b
commit bd30e90
Showing
19 changed files
with
361 additions
and
18 deletions.
There are no files selected for viewing
Binary file added
BIN
+7.37 KB
pcomparator/.yarn/cache/@dotmind-react-use-pwa-npm-1.0.4-303d6d74b3-e040cd4ed3.zip
Binary file not shown.
Binary file not shown.
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
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
Large diffs are not rendered by default.
Oops, something went wrong.
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
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
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
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
"use client"; | ||
|
||
import { Trans } from "@lingui/macro"; | ||
import { | ||
Button, | ||
Card, | ||
CardBody, | ||
Checkbox, | ||
Modal, | ||
ModalBody, | ||
ModalContent, | ||
ModalFooter, | ||
ModalHeader, | ||
useDisclosure | ||
} from "@nextui-org/react"; | ||
import { ExternalLink, Info } from "lucide-react"; | ||
import dynamic from "next/dynamic"; | ||
import { useEffect } from "react"; | ||
import useIosInstallPrompt from "~/core/pwa/useIos"; | ||
import useWebInstallPrompt from "~/core/pwa/useWebInstall"; | ||
|
||
const InstallPrompt = () => { | ||
const [iosInstallPrompt, handleIOSInstallDeclined] = useIosInstallPrompt(); | ||
const [webInstallPrompt, handleWebInstallDeclined, handleWebInstallAccepted] = useWebInstallPrompt(); | ||
const { isOpen, onClose, onOpen, onOpenChange } = useDisclosure(); | ||
|
||
useEffect(() => { | ||
if (!iosInstallPrompt && !webInstallPrompt) return; | ||
setTimeout(onOpen, 3000); | ||
}, [webInstallPrompt, iosInstallPrompt]); | ||
|
||
if (!iosInstallPrompt && !webInstallPrompt) return null; | ||
|
||
return ( | ||
<Modal isOpen={isOpen} onOpenChange={onOpenChange}> | ||
<ModalContent> | ||
{iosInstallPrompt ? ( | ||
<> | ||
<ModalHeader> | ||
<Trans>Install Our App for a Better Experience!</Trans> | ||
</ModalHeader> | ||
<ModalBody> | ||
<p> | ||
<Trans>Get faster access, work offline, and enjoy a smoother experience.</Trans> | ||
</p> | ||
<Card className="mb-4"> | ||
<CardBody className="flex !flex-row gap-6 bg-yellow-200/[0.2] dark:bg-yellow-200/[0.06]"> | ||
<Info color="#e3c84b" size="22px" /> | ||
<div className="flex-1"> | ||
<span className="text-small"> | ||
<b>App can not be automatically installed on Ios</b> | ||
</span> | ||
<span className="text-small flex items-center gap-x-1"> | ||
Tap | ||
<ExternalLink /> | ||
then "Add to Home Screen" | ||
</span> | ||
</div> | ||
</CardBody> | ||
</Card> | ||
<ul> | ||
<li> | ||
<Checkbox isSelected readOnly> | ||
Instant access with one tap | ||
</Checkbox> | ||
</li> | ||
<li> | ||
<Checkbox isSelected readOnly> | ||
No need for app store downloads | ||
</Checkbox> | ||
</li> | ||
<li> | ||
<Checkbox isSelected readOnly> | ||
Works offline and loads faster | ||
</Checkbox> | ||
</li> | ||
<li> | ||
<Checkbox isSelected readOnly> | ||
Stay updated with notifications | ||
</Checkbox> | ||
</li> | ||
</ul> | ||
</ModalBody> | ||
<ModalFooter> | ||
<Button | ||
onPress={() => { | ||
handleIOSInstallDeclined(); | ||
onClose(); | ||
}} | ||
> | ||
<Trans>Maybe later</Trans> | ||
</Button> | ||
<Button | ||
onPress={() => { | ||
handleIOSInstallDeclined(); | ||
onClose(); | ||
}} | ||
color="primary" | ||
> | ||
<span>Have installed it</span> | ||
</Button> | ||
</ModalFooter> | ||
</> | ||
) : webInstallPrompt ? ( | ||
<> | ||
<ModalHeader> | ||
<Trans>Install Our App for a Better Experience!</Trans> | ||
</ModalHeader> | ||
<ModalBody> | ||
<p> | ||
<Trans>Get faster access, work offline, and enjoy a smoother experience.</Trans> | ||
</p> | ||
<ul> | ||
<li> | ||
<Checkbox isSelected readOnly> | ||
Instant access with one tap | ||
</Checkbox> | ||
</li> | ||
<li> | ||
<Checkbox isSelected readOnly> | ||
No need for app store downloads | ||
</Checkbox> | ||
</li> | ||
<li> | ||
<Checkbox isSelected readOnly> | ||
Works offline and loads faster | ||
</Checkbox> | ||
</li> | ||
<li> | ||
<Checkbox isSelected readOnly> | ||
Stay updated with notifications | ||
</Checkbox> | ||
</li> | ||
</ul> | ||
</ModalBody> | ||
<ModalFooter> | ||
<Button | ||
onPress={() => { | ||
handleWebInstallDeclined(); | ||
onClose(); | ||
}} | ||
> | ||
<Trans>Maybe later</Trans> | ||
</Button> | ||
<Button | ||
onPress={() => { | ||
handleWebInstallAccepted(); | ||
onClose(); | ||
}} | ||
color="primary" | ||
> | ||
<span>Install our app 👋</span> | ||
</Button> | ||
</ModalFooter> | ||
</> | ||
) : null} | ||
</ModalContent> | ||
</Modal> | ||
); | ||
}; | ||
|
||
export const InstallPWA = dynamic(() => Promise.resolve(InstallPrompt), { | ||
ssr: false | ||
}); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import useShouldShowPrompt from "~/core/pwa/useShouldShow"; | ||
|
||
const iosInstallPromptedAt = "iosInstallPromptedAt"; | ||
|
||
const isIOS = (): boolean => { | ||
// @ts-ignore | ||
if (navigator.standalone) { | ||
//user has already installed the app | ||
return false; | ||
} | ||
const ua = window.navigator.userAgent; | ||
const isIPad = !!ua.match(/iPad/i); | ||
const isIPhone = !!ua.match(/iPhone/i); | ||
return isIPad || isIPhone; | ||
}; | ||
|
||
const useIosInstallPrompt = (): [boolean, () => void] => { | ||
const [userShouldBePromptedToInstall, handleUserSeeingInstallPrompt] = | ||
useShouldShowPrompt(iosInstallPromptedAt); | ||
|
||
return [isIOS() && userShouldBePromptedToInstall, handleUserSeeingInstallPrompt]; | ||
}; | ||
export default useIosInstallPrompt; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import moment from "moment"; | ||
import { useState } from "react"; | ||
|
||
const getInstallPromptLastSeenAt = (promptName: string): string => localStorage.getItem(promptName)!; | ||
|
||
const setInstallPromptSeenToday = (promptName: string): void => { | ||
const today = moment().toISOString(); | ||
localStorage.setItem(promptName, today); | ||
}; | ||
|
||
function getUserShouldBePromptedToInstall( | ||
promptName: string, | ||
daysToWaitBeforePromptingAgain: number | ||
): boolean { | ||
const lastPrompt = moment(getInstallPromptLastSeenAt(promptName)); | ||
const daysSinceLastPrompt = moment().diff(lastPrompt, "days"); | ||
return Number.isNaN(daysSinceLastPrompt) || daysSinceLastPrompt > daysToWaitBeforePromptingAgain; | ||
} | ||
|
||
const useShouldShowPrompt = ( | ||
promptName: string, | ||
daysToWaitBeforePromptingAgain = 30 | ||
): [boolean, () => void] => { | ||
const [userShouldBePromptedToInstall, setUserShouldBePromptedToInstall] = useState( | ||
getUserShouldBePromptedToInstall(promptName, daysToWaitBeforePromptingAgain) | ||
); | ||
|
||
const handleUserSeeingInstallPrompt = () => { | ||
setUserShouldBePromptedToInstall(false); | ||
setInstallPromptSeenToday(promptName); | ||
}; | ||
|
||
return [userShouldBePromptedToInstall, handleUserSeeingInstallPrompt]; | ||
}; | ||
export default useShouldShowPrompt; |
Oops, something went wrong.