Skip to content

Commit

Permalink
migrate to ts
Browse files Browse the repository at this point in the history
  • Loading branch information
yannbf committed Nov 22, 2024
1 parent 5eec519 commit 2f3b0c6
Show file tree
Hide file tree
Showing 45 changed files with 3,593 additions and 883 deletions.
18 changes: 0 additions & 18 deletions .storybook/main.js

This file was deleted.

19 changes: 19 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { StorybookConfig } from '@storybook/react-vite'

const config: StorybookConfig = {
stories: ['../src/components/**/*.stories.@(ts|tsx)'],
staticDirs: ['../public'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-a11y',
'@storybook/experimental-addon-test',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
}
export default config
25 changes: 0 additions & 25 deletions .storybook/preview.js

This file was deleted.

35 changes: 35 additions & 0 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Preview } from '@storybook/react'
import '../src/index.css'

// Registers the msw addon
import { initialize, mswLoader } from 'msw-storybook-addon'

// Initialize MSW
initialize({
quiet: true,
onUnhandledRequest(request, print) {
const url = new URL(request.url)

// Provide meaningful default to have fewer unhandled request warnings.
if (/(\/node_modules\/|\.((t|j)sx?)|\.woff$)/.test(url.pathname)) {
return
}

print.warning()
},
})

const preview: Preview = {
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
},
loaders: [mswLoader],
}

export default preview
File renamed without changes.
Binary file modified .yarn/install-state.gz
Binary file not shown.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@types/react-dom": "^18.2.22",
"@vitejs/plugin-react": "^4.2.1",
"@vitest/browser": "^2.1.5",
"@vitest/coverage-v8": "^2.1.5",
"chromatic": "^11.18.1",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.1",
Expand All @@ -51,6 +52,8 @@
"playwright": "^1.49.0",
"prop-types": "^15.8.1",
"storybook": "^8.4.0",
"ts-migrate": "^0.1.35",
"typescript": "^5.6.3",
"vite": "^5.2.0",
"vitest": "^2.1.5"
},
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Meta, StoryObj } from '@storybook/react'
import { HttpResponse, http, delay } from 'msw'
import { Provider } from 'react-redux'

import InboxScreen from './InboxScreen'
import store from '../lib/store'
import InboxScreen from './InboxScreen'
import { MockedState } from './TaskList.stories'

import {
Expand All @@ -12,18 +13,21 @@ import {
waitForElementToBeRemoved,
} from '@storybook/test'

export default {
const meta = {
component: InboxScreen,
title: 'InboxScreen',
decorators: [(story) => <Provider store={store}>{story()}</Provider>],
}
} satisfies Meta<typeof InboxScreen>
export default meta;

export const Default = {
type Story = StoryObj<typeof meta>

export const Default: Story = {
parameters: {
msw: {
handlers: [
http.get(
'https://jsonplaceholder.typicode.com/todos?userId=1',
'https://jsonplaceholder.typicode.com/todos',
() => {
return HttpResponse.json(MockedState.tasks)
}
Expand All @@ -44,22 +48,24 @@ export const Default = {
})
},
}
export const Error = {

export const Error: Story = {
parameters: {
msw: {
handlers: [
http.get('https://jsonplaceholder.typicode.com/todos?userId=1', () => {
http.get('https://jsonplaceholder.typicode.com/todos', () => {
return HttpResponse.json({}, { status: 500 })
}),
],
},
},
}
export const Loading = {

export const Loading: Story = {
parameters: {
msw: {
handlers: [
http.get('https://jsonplaceholder.typicode.com/todos?userId=1', async () => {
http.get('https://jsonplaceholder.typicode.com/todos', async () => {
await delay('infinite')
}),
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react";

import { useDispatch, useSelector } from "../lib/hooks";
import { fetchTasks } from "../lib/store";
import { selectTaskbox } from "../lib/selectors";
import TaskList from "./TaskList";

export default function InboxScreen() {
const dispatch = useDispatch();
// We're retrieving the error field from our updated store
const { error } = useSelector((state) => state.taskbox);
const { error } = useSelector(selectTaskbox);
// The useEffect triggers the data fetching when the component is mounted
useEffect(() => {
dispatch(fetchTasks());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { Meta, StoryObj } from '@storybook/react'
import { fn } from '@storybook/test';

import Task from "./Task";

export default {
const meta = {
component: Task,
title: "Task",
tags: ["autodocs"],
};
args: {
onArchiveTask: fn(),
onPinTask: fn(),
}
} satisfies Meta<typeof Task>
export default meta;

type Story = StoryObj<typeof meta>

export const Default = {
export const Default: Story = {
args: {
task: {
id: "1",
Expand All @@ -16,7 +26,7 @@ export const Default = {
},
};

export const Pinned = {
export const Pinned: Story = {
args: {
task: {
...Default.args.task,
Expand All @@ -25,7 +35,7 @@ export const Pinned = {
},
};

export const Archived = {
export const Archived: Story = {
args: {
task: {
...Default.args.task,
Expand All @@ -36,7 +46,7 @@ export const Archived = {

const longTitleString = `This task's name is absurdly large. In fact, I think if I keep going I might end up with content overflow. What will happen? The star that represents a pinned task could have text overlapping. The text could cut-off abruptly when it reaches the star. I hope not!`;

export const LongTitle = {
export const LongTitle: Story = {
args: {
task: {
...Default.args.task,
Expand Down
29 changes: 9 additions & 20 deletions src/components/Task.jsx → src/components/Task.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import React from "react";
import PropTypes from "prop-types";
import { Task } from "../types";

export default function Task({
type TaskProps = {
task: Task;
onArchiveTask: (id: string) => void;
onPinTask: (id: string) => void;
};

export default function TaskComponent({
task: { id, title, state },
onArchiveTask,
onPinTask,
}) {
}: TaskProps) {
return (
<div className={`list-item ${state}`}>
<label
Expand Down Expand Up @@ -48,19 +53,3 @@ export default function Task({
</div>
);
}

Task.propTypes = {
/** Composition of the task */
task: PropTypes.shape({
/** Id of the task */
id: PropTypes.string.isRequired,
/** Title of the task */
title: PropTypes.string.isRequired,
/** Current state of the task */
state: PropTypes.string.isRequired,
}),
/** Event to change the task to archived */
onArchiveTask: PropTypes.func,
/** Event to change the task to pinned */
onPinTask: PropTypes.func,
};
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import TaskList from "./TaskList";
import * as TaskStories from "./Task.stories";

import { Meta, StoryObj } from '@storybook/react'
import { Provider } from "react-redux";

import { configureStore, createSlice } from "@reduxjs/toolkit";

import TaskList from "./TaskList";
import * as TaskStories from "./Task.stories";
import { State } from '../lib/store';
import { ReactElement } from 'react';
import { Task } from '../types';

// A super-simple mock of the state of the store
export const MockedState = {
export const MockedState: State = {
tasks: [
{ ...TaskStories.Default.args.task, id: "1", title: "Task 1" },
{ ...TaskStories.Default.args.task, id: "2", title: "Task 2" },
Expand All @@ -20,7 +23,7 @@ export const MockedState = {
};

// A super-simple mock of a redux store
const Mockstore = ({ taskboxState, children }) => (
const Mockstore = ({ taskboxState, children }: { taskboxState: State, children: ReactElement }) => (
<Provider
store={configureStore({
reducer: {
Expand All @@ -44,24 +47,27 @@ const Mockstore = ({ taskboxState, children }) => (
</Provider>
);

export default {
const meta = {
component: TaskList,
title: "TaskList",
tags: ["autodocs"],
decorators: [(story) => <div style={{ padding: "3rem" }}>{story()}</div>],
excludeStories: /.*MockedState$/,
};
} satisfies Meta<typeof TaskList>
export default meta;

type Story = StoryObj<typeof meta>

export const Default = {
export const Default: Story = {
decorators: [
(story) => <Mockstore taskboxState={MockedState}>{story()}</Mockstore>,
],
};

export const WithPinnedTasks = {
export const WithPinnedTasks: Story = {
decorators: [
(story) => {
const pinnedtasks = [
const pinnedtasks: Task[] = [
...MockedState.tasks.slice(0, 5),
{ id: "6", title: "Task 6 (pinned)", state: "TASK_PINNED" },
];
Expand All @@ -80,7 +86,7 @@ export const WithPinnedTasks = {
],
};

export const Loading = {
export const Loading: Story = {
decorators: [
(story) => (
<Mockstore
Expand All @@ -95,7 +101,7 @@ export const Loading = {
],
};

export const Empty = {
export const Empty: Story = {
decorators: [
(story) => (
<Mockstore
Expand Down
Loading

0 comments on commit 2f3b0c6

Please sign in to comment.