Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

エラーページ用のComponentを作成 #48

Merged
merged 4 commits into from Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/app/_components/ErrorTemplate/BackToTopLink.tsx
@@ -0,0 +1,13 @@
import Link from 'next/link';

export const BackToTopLink = (): JSX.Element => {
return (
<Link
href="/"
className="text-sm font-semibold leading-6 text-orange-500 hover:text-orange-400"
prefetch={false}
>
<span aria-hidden="true">&larr;Back to Top</span>
</Link>
);
};
14 changes: 14 additions & 0 deletions src/app/_components/ErrorTemplate/ErrorResetButton.tsx
@@ -0,0 +1,14 @@
type Props = {
resetFunc: () => void;
};

export const ErrorResetButton = ({ resetFunc }: Props): JSX.Element => {
return (
<button
className="rounded-md bg-orange-500 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-orange-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
onClick={resetFunc}
>
もう一度試す
</button>
);
};
54 changes: 54 additions & 0 deletions src/app/_components/ErrorTemplate/ErrorTemplate.stories.tsx
@@ -0,0 +1,54 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ErrorTemplate } from './ErrorTemplate';

const meta: Meta = {
component: ErrorTemplate,
};

export default meta;

type Story = StoryObj<typeof ErrorTemplate>;

const TestComponent = (): JSX.Element => {
return (
<ul>
<li className="mt-2 text-sm leading-6 text-gray-600">テスト1</li>
<li className="mt-2 text-sm leading-6 text-gray-600">テスト2</li>
<li className="mt-2 text-sm leading-6 text-gray-600">テスト3</li>
</ul>
);
};

export const DefaultNotFound: Story = {
args: {
errorCode: 404,
},
};

export const NotFoundWithChildren: Story = {
args: {
errorCode: 404,
children: <TestComponent />,
},
};

export const DefaultInternalServerError = {
args: {
errorCode: 500,
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
resetFunc: () => {
console.log('reset error');
},
},
};

export const InternalServerErrorWithChildren = {
args: {
errorCode: 500,
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
resetFunc: () => {
console.log('reset error');
},
children: <TestComponent />,
},
};
105 changes: 105 additions & 0 deletions src/app/_components/ErrorTemplate/ErrorTemplate.tsx
@@ -0,0 +1,105 @@
import { Footer, Header } from '@/app/_components';
import { BackToTopLink } from '@/app/_components/ErrorTemplate/BackToTopLink';
import { ErrorResetButton } from '@/app/_components/ErrorTemplate/ErrorResetButton';
import { ExhaustiveError } from '@/utils';
import Image from 'next/image';
import type { JSX, ReactNode } from 'react';

type ErrorCode = 404 | 500;

type Props = {
errorCode: ErrorCode;
resetFunc?: () => void;
children?: ReactNode;
};

const showErrorImage = (errorCode: ErrorCode): JSX.Element => {
switch (errorCode) {
case 404:
return (
<Image
src="/404.webp"
width={300}
height={300}
alt="Cat in a Box"
className="mx-auto"
/>
);
case 500:
return (
<Image
src="/500.webp"
width={300}
height={300}
alt="Cat on a keyboard"
className="mx-auto"
/>
);
default:
throw new ExhaustiveError(errorCode);
}
};

const showErrorMessage = (errorCode: ErrorCode): string => {
switch (errorCode) {
case 404:
return 'Page not found';
case 500:
return 'Internal Server Error';
default:
throw new ExhaustiveError(errorCode);
}
};

const showErrorDiscription = (errorCode: ErrorCode) => {
switch (errorCode) {
case 404:
return 'Sorry, we couldn’t find the page you’re looking for😿';
case 500:
return 'Sorry, An unexpected error has occurred. Please try after a while😿';
default:
throw new ExhaustiveError(errorCode);
}
};

export const ErrorTemplate = ({
errorCode,
resetFunc,
children,
}: Props): JSX.Element => {
return (
<div className="flex h-screen flex-col bg-yellow-100">
<Header enableLoginLink={false} />
<main className="mx-auto w-full max-w-7xl px-6 pb-16 pt-10 sm:pb-24 lg:px-8">
<div className="mx-auto mt-20 max-w-2xl text-center sm:mt-24">
<p className="text-6xl font-semibold leading-8 text-orange-500">
{errorCode}
</p>
{showErrorImage(errorCode)}
<h1 className="mt-4 text-3xl font-bold tracking-tight text-gray-900 sm:text-5xl">
{showErrorMessage(errorCode)}
</h1>
<p className="mt-4 text-base leading-7 text-gray-600 sm:mt-6 sm:text-lg sm:leading-8">
{showErrorDiscription(errorCode)}
</p>
</div>
<div className="mx-auto mt-16 flow-root max-w-lg sm:mt-20">
<div className="flex justify-center">
{children != null ? children : ''}
</div>
<div className="mt-10 flex justify-center">
{errorCode === 404 ? <BackToTopLink /> : ''}
{errorCode === 500 && resetFunc != null ? (
<ErrorResetButton resetFunc={resetFunc} />
) : (
''
)}
</div>
</div>
</main>
<div className="mt-auto">
<Footer />
</div>
</div>
);
};
1 change: 1 addition & 0 deletions src/app/_components/ErrorTemplate/index.ts
@@ -0,0 +1 @@
export { ErrorTemplate } from './ErrorTemplate';
1 change: 1 addition & 0 deletions src/app/_components/index.ts
@@ -1,2 +1,3 @@
export { Footer } from './Footer';
export { Header } from './Header';
export { ErrorTemplate } from './ErrorTemplate';
43 changes: 2 additions & 41 deletions src/app/chat/[catId]/error.tsx
@@ -1,53 +1,14 @@
'use client';

import { Footer, Header } from '@/app/_components';
import Image from 'next/image';
import { ErrorTemplate } from '@/app/_components';

type Props = {
error: Error & { digest?: string };
reset: () => void;
};

const Error = ({ reset }: Props): JSX.Element => {
return (
<div className="flex h-screen flex-col bg-yellow-100">
<Header enableLoginLink={false} />
<main className="mx-auto w-full max-w-7xl px-6 pb-16 pt-10 sm:pb-24 lg:px-8">
<div className="mx-auto mt-20 max-w-2xl text-center sm:mt-24">
<p className="text-6xl font-semibold leading-8 text-orange-500">
500
</p>
<Image
src="/500.webp"
width={300}
height={300}
alt="Cat on a keyboard"
className="mx-auto"
/>
<h1 className="mt-4 text-3xl font-bold tracking-tight text-gray-900 sm:text-5xl">
Internal Server Error
</h1>
<p className="mt-4 text-base leading-7 text-gray-600 sm:mt-6 sm:text-lg sm:leading-8">
Sorry, An unexpected error has occurred. Please try after a while.😿
</p>
</div>
<div className="mx-auto mt-16 flow-root max-w-lg sm:mt-20">
<h2 className="sr-only">Popular pages</h2>
<div className="mt-10 flex justify-center">
<button
className="rounded-md bg-orange-500 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-orange-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
onClick={reset}
>
もう一度試す
</button>
</div>
</div>
</main>
<div className="mt-auto">
<Footer />
</div>
</div>
);
return <ErrorTemplate errorCode={500} resetFunc={reset} />;
};

export default Error;
45 changes: 2 additions & 43 deletions src/app/not-found.tsx
@@ -1,49 +1,8 @@
import { Footer, Header } from '@/app/_components';
import Image from 'next/image';
import Link from 'next/link';
import { ErrorTemplate } from '@/app/_components';
import type { JSX } from 'react';

const NotFound = (): JSX.Element => {
return (
<div className="flex h-screen flex-col bg-yellow-100">
<Header enableLoginLink={false} />
<main className="mx-auto w-full max-w-7xl px-6 pb-16 pt-10 sm:pb-24 lg:px-8">
<div className="mx-auto mt-20 max-w-2xl text-center sm:mt-24">
<p className="text-6xl font-semibold leading-8 text-orange-500">
404
</p>
<Image
src="/404.webp"
width={300}
height={300}
alt="Cat in a Box"
className="mx-auto"
/>
<h1 className="mt-4 text-3xl font-bold tracking-tight text-gray-900 sm:text-5xl">
Page not found
</h1>
<p className="mt-4 text-base leading-7 text-gray-600 sm:mt-6 sm:text-lg sm:leading-8">
Sorry, we couldn’t find the page you’re looking for😿
</p>
</div>
<div className="mx-auto mt-16 flow-root max-w-lg sm:mt-20">
<h2 className="sr-only">Popular pages</h2>
<div className="mt-10 flex justify-center">
<Link
href="/"
className="text-sm font-semibold leading-6 text-orange-500 hover:text-orange-400"
prefetch={false}
>
<span aria-hidden="true">&larr;Back to Top</span>
</Link>
</div>
</div>
</main>
<div className="mt-auto">
<Footer />
</div>
</div>
);
return <ErrorTemplate errorCode={404} />;
};

export default NotFound;