Skip to content

Commit f3d76b7

Browse files
committed
エラーページにEventIDつきフォームリンクを追加、全エラーページをコンポーネントにまとめる
1 parent 8d2d357 commit f3d76b7

8 files changed

Lines changed: 152 additions & 124 deletions

File tree

app/(docs)/@chat/error.tsx

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
"use client"; // Error boundaries must be Client Components
22

3-
import clsx from "clsx";
43
import { ChatAreaContainer } from "./chat/[chatId]/chatArea";
5-
import { useEffect, useState } from "react";
6-
import { captureException } from "@sentry/nextjs";
4+
import { ErrorMessage } from "@/errorMessage";
75

86
export default function Error({
97
error,
@@ -12,30 +10,9 @@ export default function Error({
1210
error: Error & { digest?: string };
1311
reset: () => void;
1412
}) {
15-
const [eventId, setEventId] = useState<string>();
16-
useEffect(() => {
17-
setEventId(captureException(error));
18-
}, [error]);
19-
2013
return (
2114
<ChatAreaContainer chatId={"error"}>
22-
<p>ページの読み込み中にエラーが発生しました。</p>
23-
<pre
24-
className={clsx(
25-
"border-2 border-current/20 mt-4 rounded-box p-4! bg-base-300! text-base-content!",
26-
"max-w-full whitespace-pre-wrap"
27-
)}
28-
>
29-
{error.message}
30-
</pre>
31-
{error.digest && (
32-
<p className="mt-2 text-sm text-base-content/50">
33-
Digest: {error.digest}
34-
</p>
35-
)}
36-
{eventId && (
37-
<p className="mt-2 text-sm text-base-content/50">eventID: {eventId}</p>
38-
)}
15+
<ErrorMessage error={error} />
3916
</ChatAreaContainer>
4017
);
4118
}

app/about/license/ThirdPartyLicenses.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"use client";
22

3-
import { StyledSyntaxHighlighter } from "@/markdown/styledSyntaxHighlighter";
4-
import { langConstants } from "@my-code/runtime/languages";
3+
import { FallbackPre } from "@/markdown/styledSyntaxHighlighter";
54
import { useState } from "react";
65

76
export interface LicenseEntry {
@@ -80,12 +79,7 @@ export function ThirdPartyLicenses({ licenses }: { licenses: LicenseEntry[] }) {
8079
</p>
8180
)}
8281
{pkg.licenseText && (
83-
<StyledSyntaxHighlighter
84-
className="text-sm"
85-
language={langConstants(undefined)}
86-
>
87-
{pkg.licenseText}
88-
</StyledSyntaxHighlighter>
82+
<FallbackPre className="text-sm">{pkg.licenseText}</FallbackPre>
8983
)}
9084
</div>
9185
</div>

app/error.tsx

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
"use client"; // Error boundaries must be Client Components
22

3-
import { captureException } from "@sentry/nextjs";
4-
import clsx from "clsx";
5-
import Link from "next/link";
6-
import { useEffect, useState } from "react";
3+
import { ErrorMessage } from "./errorMessage";
74

85
export default function ErrorPage({
96
error,
@@ -12,46 +9,7 @@ export default function ErrorPage({
129
error: unknown;
1310
reset: () => void;
1411
}) {
15-
const [eventId, setEventId] = useState<string>();
16-
useEffect(() => {
17-
setEventId(captureException(error));
18-
}, [error]);
19-
2012
return (
21-
<div className="p-4 flex-1 w-max max-w-full mx-auto flex flex-col items-center justify-center">
22-
<h1 className="text-2xl font-bold mb-4">エラー</h1>
23-
<p>ページの読み込み中にエラーが発生しました。</p>
24-
<pre
25-
className={clsx(
26-
"border-2 border-current/20 mt-4 rounded-box p-4! bg-base-300! text-base-content!",
27-
"max-w-full whitespace-pre-wrap"
28-
)}
29-
>
30-
{error instanceof Error ? error.message : String(error)}
31-
</pre>
32-
{"digest" in (error as { digest: string }) && (
33-
<p className="mt-2 text-sm text-base-content/50">
34-
Digest: {(error as { digest: string }).digest}
35-
</p>
36-
)}
37-
{eventId && (
38-
<p className="mt-2 text-sm text-base-content/50">eventID: {eventId}</p>
39-
)}
40-
<div className="divider w-full self-auto!" />
41-
<div className="flex flex-row gap-4">
42-
<button
43-
className="btn btn-warning"
44-
onClick={
45-
// Attempt to recover by trying to re-render the segment
46-
() => reset()
47-
}
48-
>
49-
やりなおす
50-
</button>
51-
<Link href="/" className="btn btn-primary">
52-
トップに戻る
53-
</Link>
54-
</div>
55-
</div>
13+
<ErrorMessage className="p-4 flex-1" h1 back error={error} reset={reset} />
5614
);
5715
}

app/errorMessage.tsx

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"use client";
2+
3+
import { captureException } from "@sentry/nextjs";
4+
import clsx from "clsx";
5+
import Link from "next/link";
6+
import { useEffect, useState } from "react";
7+
import { FallbackPre } from "./markdown/styledSyntaxHighlighter";
8+
import { Heading } from "./markdown/heading";
9+
10+
interface Props {
11+
className?: string;
12+
h1?: boolean;
13+
back?: boolean;
14+
error: unknown;
15+
reset?: () => void;
16+
}
17+
export function ErrorMessage({ error, reset, ...props }: Props) {
18+
const [eventId, setEventId] = useState<string>();
19+
useEffect(() => {
20+
setEventId(captureException(error));
21+
}, [error]);
22+
23+
const digest =
24+
"digest" in (error as { digest: string })
25+
? (error as { digest: string }).digest
26+
: undefined;
27+
28+
return (
29+
<div
30+
className={clsx(
31+
"w-full flex flex-col items-center justify-center",
32+
props.className
33+
)}
34+
>
35+
{props.h1 && <Heading level={1}>エラー</Heading>}
36+
<p className="my-2">ページの読み込み中にエラーが発生しました。</p>
37+
<FallbackPre className="mx-0! max-w-max whitespace-pre-wrap">
38+
{error instanceof Error ? error.message : String(error)}
39+
</FallbackPre>
40+
{digest && (
41+
<p className="my-1 text-sm text-base-content/50">Digest: {digest}</p>
42+
)}
43+
{eventId && (
44+
<p className="my-1 text-sm text-base-content/50">EventID: {eventId}</p>
45+
)}
46+
{eventId && (
47+
<a
48+
className="link link-info my-2"
49+
href={`https://docs.google.com/forms/d/e/1FAIpQLSfkM2LKhUDgCdY2fGntuv75O3jaWISwKuBIu9MW3h3UD1I3sw/viewform?usp=pp_url&entry.758323891=${eventId}${digest ? "/" + digest : ""}`}
50+
target="_blank"
51+
>
52+
問い合わせフォームで報告する
53+
</a>
54+
)}
55+
{(props.back || reset) && (
56+
<>
57+
<div className="divider w-full self-auto!" />
58+
<div className="flex flex-row gap-4">
59+
{reset && (
60+
<button
61+
className="btn btn-warning"
62+
onClick={
63+
// Attempt to recover by trying to re-render the segment
64+
() => reset()
65+
}
66+
>
67+
やりなおす
68+
</button>
69+
)}
70+
{props.back && (
71+
<Link href="/" className="btn btn-primary">
72+
トップに戻る
73+
</Link>
74+
)}
75+
</div>
76+
</>
77+
)}
78+
</div>
79+
);
80+
}

app/global-error.tsx

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
"use client"; // Error boundaries must be Client Components
22

3-
import { captureException } from "@sentry/nextjs";
4-
import clsx from "clsx";
5-
import Link from "next/link";
6-
import { useEffect, useState } from "react";
3+
import { ErrorMessage } from "./errorMessage";
74

85
export default function ErrorPage({
96
error,
@@ -12,46 +9,7 @@ export default function ErrorPage({
129
error: unknown;
1310
reset: () => void;
1411
}) {
15-
const [eventId, setEventId] = useState<string>();
16-
useEffect(() => {
17-
setEventId(captureException(error));
18-
}, [error]);
19-
2012
return (
21-
<div className="p-4 flex-1 w-max max-w-full mx-auto flex flex-col items-center justify-center">
22-
<h1 className="text-2xl font-bold mb-4">エラー</h1>
23-
<p>ページの読み込み中にエラーが発生しました。</p>
24-
<pre
25-
className={clsx(
26-
"border-2 border-current/20 mt-4 rounded-box p-4! bg-base-300! text-base-content!",
27-
"max-w-full whitespace-pre-wrap"
28-
)}
29-
>
30-
{error instanceof Error ? error.message : String(error)}
31-
</pre>
32-
{"digest" in (error as { digest: string }) && (
33-
<p className="mt-2 text-sm text-base-content/50">
34-
Digest: {(error as { digest: string }).digest}
35-
</p>
36-
)}
37-
{eventId && (
38-
<p className="mt-2 text-sm text-base-content/50">eventID: {eventId}</p>
39-
)}
40-
<div className="divider w-full self-auto!" />
41-
<div className="flex flex-row gap-4">
42-
<button
43-
className="btn btn-warning"
44-
onClick={
45-
// Attempt to recover by trying to re-render the segment
46-
() => reset()
47-
}
48-
>
49-
やりなおす
50-
</button>
51-
<Link href="/" className="btn btn-primary">
52-
トップに戻る
53-
</Link>
54-
</div>
55-
</div>
13+
<ErrorMessage className="p-4 flex-1" h1 back error={error} reset={reset} />
5614
);
5715
}

app/markdown/styledSyntaxHighlighter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function StyledSyntaxHighlighter(props: {
4949
<FallbackPre className={props.className}>{props.children}</FallbackPre>
5050
);
5151
}
52-
function FallbackPre({
52+
export function FallbackPre({
5353
children,
5454
className,
5555
}: {

next.config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ const nextConfig: NextConfig = {
8989
outputFilename: "static/oss-licenses.json",
9090
includeNoticeText: true,
9191
excludedPackageTest: (packageName /*, version*/) => {
92-
return packageName.startsWith("@my-code");
92+
return (
93+
packageName.startsWith("@my-code") || packageName === "my-code"
94+
);
9395
},
9496
licenseOverrides: {
9597
"@better-auth/core@1.4.20": "MIT",

0 commit comments

Comments
 (0)