Skip to content

Commit

Permalink
OPHJOD-295: Add note component
Browse files Browse the repository at this point in the history
  • Loading branch information
sauanto committed Apr 9, 2024
1 parent 5456624 commit 8cd7c25
Show file tree
Hide file tree
Showing 4 changed files with 521 additions and 0 deletions.
160 changes: 160 additions & 0 deletions lib/components/Note/Note.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';

import { Note } from './Note';

const meta = {
title: 'Snackbars/Note',
component: Note,
tags: ['autodocs'],
} satisfies Meta<typeof Note>;

export default meta;

type Story = StoryObj<typeof meta>;

const title = 'Lorem ipsum';
const description = 'Ipsum dolor est nonummy sit amet accusata mediocre me tulsa opus.';

export const ConfirmationNote: Story = {
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8296',
},
docs: {
description: {
story: 'This is a success toast component for displaying a text.',
},
},
layout: 'fullscreen',
viewport: {
defaultViewport: 'desktop',
},
},
args: {
title,
description,
readMoreText: 'Lue lisää',
readMoreHref: '/',
onCloseClick: fn(),
},
};

export const LongTitleText: Story = {
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8357',
},
docs: {
description: {
story: 'This is a success toast component for displaying a long title text.',
},
},
layout: 'fullscreen',
viewport: {
defaultViewport: 'desktop',
},
},
args: {
title: 'Lorem ipsum dolor est nonummy noblem ester!',
description,
readMoreText: 'Lue lisää',
readMoreHref: '/',
onCloseClick: fn(),
},
};

export const PermanentNote: Story = {
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8278',
},
docs: {
description: {
story: 'This is a success toast component for displaying a permanent note.',
},
},
layout: 'fullscreen',
viewport: {
defaultViewport: 'desktop',
},
},
args: {
title,
description,
readMoreText: 'Lue lisää',
readMoreHref: '/',
},
};

export const NoCTA: Story = {
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8316',
},
docs: {
description: {
story: 'This is a success toast component for displaying a permanent note.',
},
},
layout: 'fullscreen',
viewport: {
defaultViewport: 'desktop',
},
},
args: {
title,
description,
onCloseClick: fn(),
},
};

export const WarningNote: Story = {
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8344',
},
docs: {
description: {
story: 'This is a warning toast component for displaying a text.',
},
},
layout: 'fullscreen',
viewport: {
defaultViewport: 'desktop',
},
},
args: {
title,
description,
variant: 'warning',
},
};

export const ErrorNote: Story = {
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8331',
},
docs: {
description: {
story: 'This is a warning toast component for displaying a text.',
},
},
layout: 'fullscreen',
viewport: {
defaultViewport: 'desktop',
},
},
args: {
title,
description,
variant: 'error',
},
};
73 changes: 73 additions & 0 deletions lib/components/Note/Note.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { render, screen, cleanup } from '@testing-library/react';
import '@testing-library/jest-dom/vitest';

import { Note } from './Note';

afterEach(() => {
cleanup();
});

describe('Note component', () => {
it('renders with default variant', () => {
const { container } = render(<Note title="Test Title" description="Test Description" />);
const noteElement = screen.getByRole('alert');
expect(noteElement).toBeInTheDocument();
expect(noteElement).toHaveClass('bg-success text-white');
expect(container.firstChild).toMatchSnapshot();
});

it('renders with success variant', () => {
const { container } = render(<Note title="Test Title" description="Test Description" variant="success" />);
const noteElement = screen.getByRole('alert');
expect(noteElement).toBeInTheDocument();
expect(noteElement).toHaveClass('bg-success text-white');
expect(container.firstChild).toMatchSnapshot();
});

it('renders with warning variant', () => {
const { container } = render(<Note title="Test Title" description="Test Description" variant="warning" />);
const noteElement = screen.getByRole('alert');
expect(noteElement).toBeInTheDocument();
expect(noteElement).toHaveClass('bg-warning text-black');
expect(container.firstChild).toMatchSnapshot();
});

it('renders with error variant', () => {
const { container } = render(<Note title="Test Title" description="Test Description" variant="error" />);
const noteElement = screen.getByRole('alert');
expect(noteElement).toBeInTheDocument();
expect(noteElement).toHaveClass('bg-alert text-white');
expect(container.firstChild).toMatchSnapshot();
});

it('renders with read more link', () => {
const { container } = render(
<Note
title="Test Title"
description="Test Description"
variant="success"
readMoreText="Read more"
readMoreHref="/"
/>,
);
const readMoreLink = screen.getByRole('button', { name: 'Read more' });
expect(readMoreLink).toBeInTheDocument();
expect(readMoreLink).toHaveAttribute('href', '/');
expect(container.firstChild).toMatchSnapshot();
});

it('renders with close button', () => {
const onCloseClick = vi.fn();
const { container } = render(
<Note title="Test Title" description="Test Description" variant="success" onCloseClick={onCloseClick} />,
);
const closeButton = screen.getByLabelText('Close');
expect(closeButton).toBeInTheDocument();
expect(closeButton.firstChild).toHaveClass('material-symbols-outlined');
expect(closeButton).toHaveAttribute('aria-label', 'Close');
closeButton.click();
expect(onCloseClick).toHaveBeenCalled();
expect(container.firstChild).toMatchSnapshot();
});
});
57 changes: 57 additions & 0 deletions lib/components/Note/Note.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
export interface NoteProps {
/** Title shown on the note */
title?: string;
/** Description shown on the note */
description?: string;
/** Icon shown on the note */
variant?: 'success' | 'warning' | 'error';
/** Callback fired on tap/click of the close button */
onCloseClick?: () => void;
/** Text for read more link */
readMoreText?: string;
/** Link to read more */
readMoreHref?: string;
}

export const Note = ({
title,
description,
variant = 'success',
onCloseClick,
readMoreText,
readMoreHref,
}: NoteProps) => (
<div
role="alert"
aria-live="assertive"
aria-atomic="true"
className={`
${variant === 'success' ? 'bg-success text-white' : ''}
${variant === 'warning' ? 'bg-warning text-black' : ''}
${variant === 'error' ? 'bg-alert text-white' : ''}
`}
>
<div className="mx-auto flex min-h-11 max-w-[1092px] items-center justify-between pl-7 pr-0">
<div className="flex flex-wrap items-end gap-x-5 gap-y-2 py-5 ">
<div className="text-heading-4">{title}</div>
<div className="text-body-sm">{description}</div>
</div>
<div className="flex items-center">
{variant === 'success' && readMoreText && readMoreHref && (
<a
className="mx-7 text-nowrap rounded-[30px] bg-white px-6 py-[10px] text-button-md text-success"
href={readMoreHref}
role="button"
>
{readMoreText}
</a>
)}
{onCloseClick && (
<button className="mr-5 flex" type="button" aria-label="Close" onClick={onCloseClick}>
<span className="material-symbols-outlined size-24 select-none p-2">cancel</span>
</button>
)}
</div>
</div>
</div>
);
Loading

0 comments on commit 8cd7c25

Please sign in to comment.