tack-up-now/app/routes/_index.tsx

133 lines
3.7 KiB
TypeScript

import {
json,
type LoaderFunctionArgs,
type MetaFunction,
} from "@remix-run/node"
import { useLoaderData } from "@remix-run/react"
import React, { Suspense, useEffect, useState } from "react"
import coerceSemver from "semver/functions/coerce"
import versionAtLeast from "semver/functions/gte"
import UAParser from "ua-parser-js"
import { usePush } from "remix-pwa-monorepo/packages/push/client/hook"
export const meta: MetaFunction = () => {
return [
{ title: "Tack Up Now!" },
{ name: "description", content: "Get equinelive notifications" },
]
}
export const loader = async ({ request }: LoaderFunctionArgs) => {
const userAgent = request.headers.get("user-agent")
const parsedUserAgent = new UAParser(userAgent ?? "")
const os = parsedUserAgent.getOS()
const isNonSafari = parsedUserAgent.getBrowser().name !== "Mobile Safari"
const browser = parsedUserAgent.getBrowser().name
const isSupported =
os.name !== "iOS" ||
versionAtLeast(coerceSemver(os.version) ?? "0.0.0", "16.4.0")
console.log("Wut", isNonSafari)
return json({ isSupported, isNonSafari, browser })
}
export default function Index() {
const { isSupported, isNonSafari, browser } = useLoaderData<typeof loader>()
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
<Suspense>
<LandingMessage isSupported={isSupported} isNonSafari={isNonSafari} />
{browser}
</Suspense>
</div>
)
}
function LandingMessage({
isSupported,
isNonSafari,
}: {
isSupported: boolean
isNonSafari: boolean
}) {
const isClient = typeof window !== "undefined"
const notificationsEnabled =
isClient &&
"Notification" in window &&
window.Notification.permission === "granted"
const isRunningPWA =
isClient &&
(("standalone" in navigator && (navigator.standalone as boolean)) ||
matchMedia("(dislay-mode: standalone)").matches)
const [rendered, setRendered] = useState(false)
const [isInstalled, setIsInstalled] = useState(notificationsEnabled)
useEffect(() => {
setRendered(true)
}, [])
return !isClient || !rendered ? (
<div>Loading</div>
) : isInstalled ? (
<div>Your Notifications</div>
) : isNonSafari ? (
<div>Safari</div>
) : isRunningPWA && !notificationsEnabled ? (
<EnableButton onSubscribe={() => setIsInstalled(true)} />
) : isSupported ? (
<div>Install Tack Up Now!</div>
) : (
<div>{"Sorry, your device doesn't support Tack Up Now! :("}</div>
)
}
function EnableButton({ onSubscribe }: { onSubscribe: () => void }) {
const { subscribeToPush, requestPermission, canSendPush } = usePush()
function subscribe() {
requestPermission()
}
useEffect(() => {
if (!canSendPush) return
subscribeToPush(
urlB64ToUint8Array(applicationServerPublicKey) as any,
(subscription) => {
fetch("/api/subscribe", {
method: "POST",
body: JSON.stringify(subscription),
})
onSubscribe()
},
(error) => {
const errorDiv = document.createElement("div")
errorDiv.innerText = "Error thingy" + JSON.stringify(error)
document.appendChild(errorDiv)
}
)
}, [canSendPush])
return <button onClick={subscribe}>Enable notifications</button>
}
const applicationServerPublicKey =
"BDTbzdtzJxwV0sscdsXla-GKvlcxqQr7edEfkX8-papwvvV1UVc3IMyRacl1BbgTi31nWPji2wKCZkjf1l5iX7Y"
function urlB64ToUint8Array(base64String: string) {
const padding = "=".repeat((4 - (base64String.length % 4)) % 4)
const base64 = (base64String + padding).replace(/\-/g, "+").replace(/_/g, "/")
const rawData = window.atob(base64)
const outputArray = new Uint8Array(rawData.length)
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i)
}
return outputArray
}