Skip to content

Commit 323c59d

Browse files
committed
add /error page
1 parent 3b6816d commit 323c59d

File tree

4 files changed

+237
-0
lines changed

4 files changed

+237
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"use client"
2+
3+
import { useSearchParams } from "next/navigation"
4+
5+
import { ServerErrorPage } from "@/components/server-error"
6+
import { isValidStatusCode, statusMessages } from "@/lib/status-codes"
7+
8+
export default function ErrorPageClient() {
9+
const searchParams = useSearchParams()
10+
11+
const statusCode = Number(searchParams.get("status_code"))
12+
13+
if (isValidStatusCode(statusCode)) {
14+
return <ServerErrorPage statusCode={statusCode.toString()} message={statusMessages[statusCode]} />
15+
}
16+
17+
if (!Number.isNaN(statusCode)) {
18+
return <ServerErrorPage statusCode={statusCode.toString()} message="Something strange..." />
19+
}
20+
21+
return <ServerErrorPage message="Something strange..." />
22+
}

client/src/app/error/page.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { Metadata } from "next"
2+
import * as React from "react"
3+
4+
import ErrorPageClient from "@/app/error/error-page-client"
5+
6+
export const metadata: Metadata = {
7+
title: "Error",
8+
}
9+
10+
export default function ErrorPage() {
11+
return (
12+
<React.Suspense fallback={null}>
13+
<ErrorPageClient />
14+
</React.Suspense>
15+
)
16+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type React from "react"
2+
3+
const styles: Record<string, React.CSSProperties> = {
4+
error: {
5+
textAlign: "center",
6+
display: "flex",
7+
flexDirection: "column",
8+
alignItems: "center",
9+
justifyContent: "center",
10+
},
11+
desc: {
12+
display: "flex",
13+
height: "96px",
14+
flexDirection: "row",
15+
alignItems: "center",
16+
},
17+
h1: {
18+
display: "inline-block",
19+
margin: "0 20px 0 0",
20+
paddingRight: 23,
21+
fontSize: 48,
22+
fontWeight: 500,
23+
verticalAlign: "top",
24+
borderRight: "1px solid hsl(var(--foreground) / 0.5)",
25+
},
26+
h2: {
27+
fontSize: 28,
28+
fontWeight: 400,
29+
lineHeight: "28px",
30+
},
31+
wrap: {
32+
display: "inline-block",
33+
},
34+
}
35+
36+
export type HttpErrorProps = {
37+
statusCode?: string
38+
message: string
39+
} & React.HTMLAttributes<HTMLDivElement>
40+
41+
export function ServerErrorPage({ style, ...props }: HttpErrorProps) {
42+
style ??= {}
43+
style.minHeight = "100vh"
44+
return <ServerError style={style} {...props} />
45+
}
46+
47+
export function ServerError({ statusCode, message, style, ...props }: HttpErrorProps) {
48+
return (
49+
<main style={{ ...styles.error, ...style }} {...props}>
50+
<div style={styles.desc}>
51+
{statusCode ? <h1 style={styles.h1}>{statusCode}</h1> : null}
52+
<div style={styles.wrap}>
53+
<h2 style={styles.h2}>{message}.</h2>
54+
</div>
55+
</div>
56+
</main>
57+
)
58+
}

client/src/lib/status-codes.ts

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
export const statusMessages = {
2+
100: "Continue",
3+
101: "Switching Protocols",
4+
102: "Processing",
5+
103: "Early Hints",
6+
200: "OK",
7+
201: "Created",
8+
202: "Accepted",
9+
203: "Non-Authoritative Information",
10+
204: "No Content",
11+
205: "Reset Content",
12+
206: "Partial Content",
13+
207: "Multi-Status",
14+
208: "Already Reported",
15+
226: "IM Used",
16+
300: "Multiple Choices",
17+
301: "Moved Permanently",
18+
302: "Found",
19+
303: "See Other",
20+
304: "Not Modified",
21+
305: "Use Proxy",
22+
307: "Temporary Redirect",
23+
308: "Permanent Redirect",
24+
400: "Bad Request",
25+
401: "Unauthorized",
26+
402: "Payment Required",
27+
403: "Forbidden",
28+
404: "Not Found",
29+
405: "Method Not Allowed",
30+
406: "Not Acceptable",
31+
407: "Proxy Authentication Required",
32+
408: "Request Timeout",
33+
409: "Conflict",
34+
410: "Gone",
35+
411: "Length Required",
36+
412: "Precondition Failed",
37+
413: "Payload Too Large",
38+
414: "URI Too Long",
39+
415: "Unsupported Media Type",
40+
416: "Range Not Satisfiable",
41+
417: "Expectation Failed",
42+
418: "I'm a Teapot",
43+
421: "Misdirected Request",
44+
422: "Unprocessable Entity",
45+
423: "Locked",
46+
424: "Failed Dependency",
47+
425: "Too Early",
48+
426: "Upgrade Required",
49+
428: "Precondition Required",
50+
429: "Too Many Requests",
51+
431: "Request Header Fields Too Large",
52+
451: "Unavailable For Legal Reasons",
53+
500: "Internal Server Error",
54+
501: "Not Implemented",
55+
502: "Bad Gateway",
56+
503: "Service Unavailable",
57+
504: "Gateway Timeout",
58+
505: "HTTP Version Not Supported",
59+
506: "Variant Also Negotiates",
60+
507: "Insufficient Storage",
61+
508: "Loop Detected",
62+
509: "Bandwidth Limit Exceeded",
63+
510: "Not Extended",
64+
511: "Network Authentication Required",
65+
}
66+
67+
export enum HttpStatus {
68+
Continue = 100,
69+
SwitchingProtocols = 101,
70+
Processing = 102,
71+
EarlyHints = 103,
72+
73+
OK = 200,
74+
Created = 201,
75+
Accepted = 202,
76+
NonAuthoritativeInformation = 203,
77+
NoContent = 204,
78+
ResetContent = 205,
79+
PartialContent = 206,
80+
MultiStatus = 207,
81+
AlreadyReported = 208,
82+
IMUsed = 226,
83+
84+
MultipleChoices = 300,
85+
MovedPermanently = 301,
86+
Found = 302,
87+
SeeOther = 303,
88+
NotModified = 304,
89+
UseProxy = 305,
90+
TemporaryRedirect = 307,
91+
PermanentRedirect = 308,
92+
93+
BadRequest = 400,
94+
Unauthorized = 401,
95+
PaymentRequired = 402,
96+
Forbidden = 403,
97+
NotFound = 404,
98+
MethodNotAllowed = 405,
99+
NotAcceptable = 406,
100+
ProxyAuthenticationRequired = 407,
101+
RequestTimeout = 408,
102+
Conflict = 409,
103+
Gone = 410,
104+
LengthRequired = 411,
105+
PreconditionFailed = 412,
106+
PayloadTooLarge = 413,
107+
URITooLong = 414,
108+
UnsupportedMediaType = 415,
109+
RangeNotSatisfiable = 416,
110+
ExpectationFailed = 417,
111+
IAmATeapot = 418,
112+
MisdirectedRequest = 421,
113+
UnprocessableEntity = 422,
114+
Locked = 423,
115+
FailedDependency = 424,
116+
TooEarly = 425,
117+
UpgradeRequired = 426,
118+
PreconditionRequired = 428,
119+
TooManyRequests = 429,
120+
RequestHeaderFieldsTooLarge = 431,
121+
UnavailableForLegalReasons = 451,
122+
123+
InternalServerError = 500,
124+
NotImplemented = 501,
125+
BadGateway = 502,
126+
ServiceUnavailable = 503,
127+
GatewayTimeout = 504,
128+
HttpVersionNotSupported = 505,
129+
VariantAlsoNegotiates = 506,
130+
InsufficientStorage = 507,
131+
LoopDetected = 508,
132+
BandwidthLimitExceeded = 509,
133+
NotExtended = 510,
134+
NetworkAuthenticationRequired = 511,
135+
}
136+
137+
export type StatusCode = keyof typeof statusMessages
138+
139+
export function isValidStatusCode(statusCode: unknown): statusCode is StatusCode {
140+
return typeof statusCode === "number" && Object.hasOwn(statusMessages, statusCode)
141+
}

0 commit comments

Comments
 (0)