NGU-Web/src/components/PageState.tsx

91 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ═══════════════════════════════════════════════════════════════
PAGE STATE
The three ways a detail page can fail to be a detail page. All
four of them need the same thing, and it should be the same thing
— a visitor who hits a dead retreat link and a dead chapter link
shouldn't get two different pages.
Rendered inside PageShell so the chrome doesn't flicker in and
out between loading and loaded.
A 404 gets no retry button: the slug doesn't exist and trying
again won't change that. Anything else does, because a dropped
connection is the usual cause and one tap fixes it.
═══════════════════════════════════════════════════════════════ */
import { Link } from 'react-router-dom'
import PageShell from './PageShell.tsx'
const TEAL = '#138ba0'
const BODY = '#4a6b72'
export default function PageState({
loading,
error,
notFound,
onRetry,
noun,
backTo,
backLabel,
}: {
loading: boolean
error: string | null
notFound: boolean
onRetry: () => void
/** Lowercase, as it appears mid-sentence: "retreat", "chapter". */
noun: string
backTo: string
backLabel: string
}) {
let title: string
let content: React.ReactNode
if (notFound) {
title = 'Not found'
content = (
<div className="max-w-6xl mx-auto px-6">
<p style={{ color: BODY }}>
There’s no {noun} at this address. It may have been renamed, or taken
down.
</p>
<Link
to={backTo}
className="mt-4 inline-block rounded-full border px-4 py-1.5 text-sm font-medium transition-colors hover:bg-[#eef9fb]"
style={{ borderColor: TEAL, color: TEAL }}
>
{backLabel}
</Link>
</div>
)
} else if (error) {
title = 'Something went wrong'
content = (
<div className="max-w-6xl mx-auto px-6">
<p style={{ color: '#b3261e' }}>Couldn’t load this {noun}. {error}</p>
<button
type="button"
onClick={onRetry}
className="mt-3 rounded-full border px-4 py-1.5 text-sm font-medium transition-colors hover:bg-[#eef9fb]"
style={{ borderColor: TEAL, color: TEAL }}
>
Try again
</button>
</div>
)
} else {
title = 'Loading…'
content = (
<p className="max-w-6xl mx-auto px-6" style={{ color: BODY }} role="status">
Loading this {noun}…
</p>
)
}
return (
<PageShell
title={title}
sections={[{ id: 'status', title: '', accent: TEAL, background: '#ffffff', content }]}
/>
)
}