Skip to content

Commit

Permalink
Add NotFound component
Browse files Browse the repository at this point in the history
  • Loading branch information
arkadiuszbachorski committed Nov 5, 2024
1 parent 258db15 commit d00ede4
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 0 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@
"types": "./dist/molecules/Notifications.d.ts",
"default": "./dist/molecules/Notifications.js"
},
"./molecules/NotFound": {
"types": "./dist/molecules/NotFound.d.ts",
"default": "./dist/molecules/NotFound.js"
},
"./SpeziProvider": {
"types": "./dist/SpeziProvider.d.ts",
"default": "./dist/SpeziProvider.js"
Expand Down
30 changes: 30 additions & 0 deletions src/molecules/NotFound/NotFound.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// This source file is part of the Stanford Biodesign Digital Health Spezi Web Design System open-source project
//
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import { type Meta, type StoryObj } from '@storybook/react'
import { NotFound } from './NotFound'

const meta: Meta<typeof NotFound> = {
title: 'Molecules/NotFound',
component: NotFound,
}

export default meta

type Story = StoryObj<typeof NotFound>

export const Generic: Story = {
args: { backPage: { href: '/', name: 'home' }, entityName: 'page' },
}

export const UserNotFound: Story = {
args: {
backPage: { href: '/users', name: 'users list' },
entityName: 'user',
},
}
28 changes: 28 additions & 0 deletions src/molecules/NotFound/NotFound.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// This source file is part of the Stanford Biodesign Digital Health Spezi Web Design System open-source project
//
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import { screen } from '@testing-library/react'
import { renderWithProviders } from '@/tests/helpers'
import { NotFound } from './'

describe('NotFound', () => {
it('renders not found error page', () => {
renderWithProviders(
<NotFound
backPage={{ name: 'users', href: '/users' }}
entityName="user"
/>,
)

const backLink = screen.getByRole('link', { name: /users/ })
expect(backLink).toBeInTheDocument()

const title = screen.getByText(`This user doesn't exist`)
expect(title).toBeInTheDocument()
})
})
89 changes: 89 additions & 0 deletions src/molecules/NotFound/NotFound.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//
// This source file is part of the Stanford Biodesign Digital Health Spezi Web Design System open-source project
//
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import { Link } from '@tanstack/react-router'
import { RouteOff } from 'lucide-react'
import { type ComponentProps, type ReactNode } from 'react'
import { Button } from '@/components/Button'
import { cn } from '@/utils/className'

export const NotFoundIcon = ({
className,
...props
}: Omit<ComponentProps<'div'>, 'children'>) => (
<div
className={cn('flex-center mb-2 size-20 rounded-full bg-muted', className)}
{...props}
>
<RouteOff className="size-7" />
</div>
)

export const NotFoundContainer = ({
className,
...props
}: ComponentProps<'div'>) => (
<div
className={cn('flex-center grow flex-col gap-1', className)}
{...props}
/>
)

export const NotFoundTitle = ({
className,
...props
}: ComponentProps<'h1'>) => (
<h1 className={cn('text-2xl font-medium', className)} {...props} />
)

export const NotFoundParagraph = ({
className,
...props
}: ComponentProps<'p'>) => (
<p className={cn('text-muted-foreground', className)} {...props} />
)

interface NotFoundActionProps extends ComponentProps<typeof Button> {}

export const NotFoundAction = (props: NotFoundActionProps) => (
<Button size="sm" className="mt-3" asChild {...props} />
)

interface NotFoundProps {
/**
* Configures where user should go instead
* @example { name: "users list", href: "/user" }
* */
backPage: {
name: ReactNode
href: string
}
/**
* Singular name of accessed entity
* @example "user"
* */
entityName: ReactNode
className?: string
}

export const NotFound = ({
backPage,
entityName,
className,
}: NotFoundProps) => (
<NotFoundContainer className={className}>
<NotFoundIcon />
<NotFoundTitle>This {entityName} doesn't exist</NotFoundTitle>
<NotFoundParagraph>
Please check your URL or return to {backPage.name}
</NotFoundParagraph>
<NotFoundAction>
<Link href={backPage.href}>Go to {backPage.name}</Link>
</NotFoundAction>
</NotFoundContainer>
)
9 changes: 9 additions & 0 deletions src/molecules/NotFound/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//
// This source file is part of the Stanford Biodesign Digital Health Spezi Web Design System open-source project
//
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

export * from './NotFound'

0 comments on commit d00ede4

Please sign in to comment.