migrate to blitzjs

This commit is contained in:
m5r
2021-07-31 22:33:18 +08:00
parent 4aa646ab43
commit fc4278ca7b
218 changed files with 19100 additions and 27038 deletions

View File

@ -0,0 +1,22 @@
import { ReactNode } from "react"
import { Head } from "blitz"
type LayoutProps = {
title?: string
children: ReactNode
}
const BaseLayout = ({ title, children }: LayoutProps) => {
return (
<>
<Head>
<title>{title || "virtual-phone"}</title>
<link rel="icon" href="/favicon.ico" />
</Head>
{children}
</>
)
}
export default BaseLayout

View File

@ -0,0 +1,81 @@
import type { ReactNode } from "react"
import Link from "next/link"
import { useRouter } from "next/router"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import {
faPhoneAlt as fasPhone,
faTh as fasTh,
faComments as fasComments,
faCog as fasCog,
} from "@fortawesome/pro-solid-svg-icons"
import {
faPhoneAlt as farPhone,
faTh as farTh,
faComments as farComments,
faCog as farCog,
} from "@fortawesome/pro-regular-svg-icons"
export default function Footer() {
return (
<footer className="grid grid-cols-4" style={{ flex: "0 0 50px" }}>
<NavLink
label="Calls"
path="/calls"
icons={{
active: <FontAwesomeIcon size="lg" className="w-6 h-6" icon={fasPhone} />,
inactive: <FontAwesomeIcon size="lg" className="w-6 h-6" icon={farPhone} />,
}}
/>
<NavLink
label="Keypad"
path="/keypad"
icons={{
active: <FontAwesomeIcon size="lg" className="w-6 h-6" icon={fasTh} />,
inactive: <FontAwesomeIcon size="lg" className="w-6 h-6" icon={farTh} />,
}}
/>
<NavLink
label="Messages"
path="/messages"
icons={{
active: <FontAwesomeIcon size="lg" className="w-6 h-6" icon={fasComments} />,
inactive: <FontAwesomeIcon size="lg" className="w-6 h-6" icon={farComments} />,
}}
/>
<NavLink
label="Settings"
path="/settings"
icons={{
active: <FontAwesomeIcon size="lg" className="w-6 h-6" icon={fasCog} />,
inactive: <FontAwesomeIcon size="lg" className="w-6 h-6" icon={farCog} />,
}}
/>
</footer>
)
}
type NavLinkProps = {
path: string
label: string
icons: {
active: ReactNode
inactive: ReactNode
}
}
function NavLink({ path, label, icons }: NavLinkProps) {
const router = useRouter()
const isActiveRoute = router.pathname.startsWith(path)
const icon = isActiveRoute ? icons.active : icons.inactive
return (
<div className="flex flex-col items-center justify-around h-full">
<Link href={path}>
<a className="flex flex-col items-center">
{icon}
<span className="text-xs">{label}</span>
</a>
</Link>
</div>
)
}

View File

@ -0,0 +1,101 @@
import type { ErrorInfo, FunctionComponent } from "react"
import { Component } from "react"
import Head from "next/head"
import type { WithRouterProps } from "next/dist/client/with-router"
import { withRouter } from "next/router"
import appLogger from "../../../../integrations/logger"
import Footer from "./footer"
type Props = {
title: string
pageTitle?: string
hideFooter?: true
}
const logger = appLogger.child({ module: "Layout" })
const Layout: FunctionComponent<Props> = ({
children,
title,
pageTitle = title,
hideFooter = false,
}) => {
return (
<>
{pageTitle ? (
<Head>
<title>{pageTitle}</title>
</Head>
) : null}
<div className="h-full w-full overflow-hidden fixed bg-gray-50">
<div className="flex flex-col w-full h-full">
<div className="flex flex-col flex-1 w-full overflow-y-auto">
<main className="flex-1 my-0 h-full">
<ErrorBoundary>{children}</ErrorBoundary>
</main>
</div>
{!hideFooter ? <Footer /> : null}
</div>
</div>
</>
)
}
type ErrorBoundaryState =
| {
isError: false
}
| {
isError: true
errorMessage: string
}
const ErrorBoundary = withRouter(
class ErrorBoundary extends Component<WithRouterProps, ErrorBoundaryState> {
public readonly state = {
isError: false,
} as const
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return {
isError: true,
errorMessage: error.message,
}
}
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
logger.error(error, errorInfo.componentStack)
}
public render() {
if (this.state.isError) {
return (
<>
<h2 className="mt-6 text-center text-3xl leading-9 font-extrabold text-gray-900">
Oops, something went wrong.
</h2>
<p className="mt-2 text-center text-lg leading-5 text-gray-600">
Would you like to{" "}
<button
className="inline-flex space-x-2 items-center text-left"
onClick={this.props.router.reload}
>
<span className="transition-colors duration-150 border-b border-primary-200 hover:border-primary-500">
reload the page
</span>
</button>{" "}
?
</p>
</>
)
}
return this.props.children
}
}
)
export default Layout