Skip to content

Commit 20981ac

Browse files
authored
Date component (#5)
- create `Date` component, tests, and stories
1 parent fd913a8 commit 20981ac

8 files changed

Lines changed: 194 additions & 2 deletions

File tree

package-lock.json

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
},
2727
"homepage": "https://github.com/leanstacks/react-common#readme",
2828
"dependencies": {
29-
"classnames": "^2.3.2"
29+
"classnames": "^2.3.2",
30+
"dayjs": "^1.11.9"
3031
},
3132
"devDependencies": {
3233
"@babel/preset-env": "^7.22.15",
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import type { Meta, StoryObj } from '@storybook/react';
2+
3+
import { default as DateComponent } from './Date';
4+
import { DateFormat } from './Date.types';
5+
6+
const meta = {
7+
title: 'Components/Date',
8+
component: DateComponent,
9+
parameters: {
10+
layout: 'centered',
11+
},
12+
tags: ['autodocs'],
13+
argTypes: {
14+
date: { description: 'The text to display.' },
15+
className: { description: 'Additional CSS classes.' },
16+
testId: { description: 'Unit test identifier.' },
17+
format: {
18+
control: {
19+
type: 'select',
20+
labels: {
21+
'MM/DD/YYYY': 'Date',
22+
dddd: 'Day of the Week',
23+
'H[h] mm[m]': 'Hours and Minutes',
24+
'h:mma': 'Time',
25+
'h:mma ddd MMM D': 'Timestamp Short',
26+
'dddd MMMM D [at] h:mma': 'Timestamp',
27+
},
28+
},
29+
options: [
30+
DateFormat.DATE,
31+
DateFormat.DAY_OF_WEEK,
32+
DateFormat.HOURS_AND_MINUTES,
33+
DateFormat.TIME,
34+
DateFormat.TIMESTAMP,
35+
DateFormat.TIMESTAMP_SHORT,
36+
],
37+
description: 'The date format.',
38+
},
39+
},
40+
} satisfies Meta<typeof DateComponent>;
41+
42+
export default meta;
43+
44+
type Story = StoryObj<typeof meta>;
45+
46+
export const FormatDate: Story = {
47+
args: {
48+
date: new Date().toISOString(),
49+
},
50+
};
51+
52+
export const FormatDayOfWeek: Story = {
53+
args: {
54+
date: new Date().toISOString(),
55+
format: DateFormat.DAY_OF_WEEK,
56+
},
57+
};
58+
59+
export const FormatHoursAndMinutes: Story = {
60+
args: {
61+
date: new Date().toISOString(),
62+
format: DateFormat.HOURS_AND_MINUTES,
63+
},
64+
};
65+
66+
export const FormatTime: Story = {
67+
args: {
68+
date: new Date().toISOString(),
69+
format: DateFormat.TIME,
70+
},
71+
};
72+
73+
export const FormatTimestamp: Story = {
74+
args: {
75+
date: new Date().toISOString(),
76+
format: DateFormat.TIMESTAMP,
77+
},
78+
};
79+
80+
export const FormatTimestampShort: Story = {
81+
args: {
82+
date: new Date().toISOString(),
83+
format: DateFormat.TIMESTAMP_SHORT,
84+
},
85+
};

src/components/Date/Date.test.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React from 'react';
2+
import { getAllByTestId, render } from '@testing-library/react';
3+
4+
import Date from './Date';
5+
import { DateFormat } from './Date.types';
6+
7+
describe('Date', () => {
8+
it('should render successfully', () => {
9+
const { getByTestId } = render(<Date date={0} />);
10+
11+
expect(getByTestId('date')).toBeDefined();
12+
});
13+
14+
it('should render format Date successfully', () => {
15+
const { getByTestId } = render(<Date date={0} format={DateFormat.DATE} />);
16+
17+
expect(getByTestId('date')).toBeDefined();
18+
});
19+
20+
it('should render format DayOfWeek successfully', () => {
21+
const { getByTestId } = render(<Date date={0} format={DateFormat.DAY_OF_WEEK} />);
22+
23+
expect(getByTestId('date')).toBeDefined();
24+
});
25+
26+
it('should render format HoursAndMinutes successfully', () => {
27+
const { getByTestId } = render(<Date date={0} format={DateFormat.HOURS_AND_MINUTES} />);
28+
29+
expect(getByTestId('date')).toBeDefined();
30+
});
31+
32+
it('should render format Time successfully', () => {
33+
const { getByTestId } = render(<Date date={0} format={DateFormat.TIME} />);
34+
35+
expect(getByTestId('date')).toBeDefined();
36+
});
37+
38+
it('should render format Timestamp successfully', () => {
39+
const { getByTestId } = render(<Date date={0} format={DateFormat.TIMESTAMP} />);
40+
41+
expect(getByTestId('date')).toBeDefined();
42+
});
43+
44+
it('should render format TimestampShort successfully', () => {
45+
const { getByTestId } = render(<Date date={0} format={DateFormat.TIMESTAMP_SHORT} />);
46+
47+
expect(getByTestId('date')).toBeDefined();
48+
});
49+
50+
it('should use custom testID', () => {
51+
const { getByTestId, queryByTestId } = render(<Date date={0} testId="custom-testid" />);
52+
53+
expect(queryByTestId('date')).toBeNull();
54+
expect(getByTestId('custom-testid')).toBeDefined();
55+
});
56+
57+
it('should use classes from className property', () => {
58+
const { getByTestId } = render(<Date date={0} className="custom-class" />);
59+
60+
expect(getByTestId('date').classList).toContain('custom-class');
61+
});
62+
});

src/components/Date/Date.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from 'react';
2+
import dayjs from 'dayjs';
3+
4+
import { DateFormat, DateProps } from './Date.types';
5+
6+
const Date: React.FC<DateProps> = ({
7+
className,
8+
date,
9+
testId = 'date',
10+
format = DateFormat.DATE,
11+
}) => {
12+
return (
13+
<span className={className} data-testid={testId}>
14+
{dayjs(date).format(format)}
15+
</span>
16+
);
17+
};
18+
19+
export default Date;

src/components/Date/Date.types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export enum DateFormat {
2+
DATE = 'MM/DD/YYYY',
3+
DAY_OF_WEEK = 'dddd',
4+
HOURS_AND_MINUTES = 'H[h] mm[m]',
5+
TIME = 'h:mma',
6+
TIMESTAMP_SHORT = 'h:mma ddd MMM D',
7+
TIMESTAMP = 'dddd MMMM D [at] h:mma',
8+
}
9+
10+
export interface DateProps {
11+
className?: string;
12+
date: string | number;
13+
format?: DateFormat;
14+
testId?: string;
15+
}

src/components/Date/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export { default as Date } from './Date';
2+
3+
export { DateFormat } from './Date.types';

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export * from './Date';
12
export * from './Text';

0 commit comments

Comments
 (0)