Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
},
"homepage": "https://github.com/leanstacks/react-common#readme",
"dependencies": {
"classnames": "^2.3.2"
"classnames": "^2.3.2",
"dayjs": "^1.11.9"
},
"devDependencies": {
"@babel/preset-env": "^7.22.15",
Expand Down
85 changes: 85 additions & 0 deletions src/components/Date/Date.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import type { Meta, StoryObj } from '@storybook/react';

import { default as DateComponent } from './Date';
import { DateFormat } from './Date.types';

const meta = {
title: 'Components/Date',
component: DateComponent,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
date: { description: 'The text to display.' },
className: { description: 'Additional CSS classes.' },
testId: { description: 'Unit test identifier.' },
format: {
control: {
type: 'select',
labels: {
'MM/DD/YYYY': 'Date',
dddd: 'Day of the Week',
'H[h] mm[m]': 'Hours and Minutes',
'h:mma': 'Time',
'h:mma ddd MMM D': 'Timestamp Short',
'dddd MMMM D [at] h:mma': 'Timestamp',
},
},
options: [
DateFormat.DATE,
DateFormat.DAY_OF_WEEK,
DateFormat.HOURS_AND_MINUTES,
DateFormat.TIME,
DateFormat.TIMESTAMP,
DateFormat.TIMESTAMP_SHORT,
],
description: 'The date format.',
},
},
} satisfies Meta<typeof DateComponent>;

export default meta;

type Story = StoryObj<typeof meta>;

export const FormatDate: Story = {
args: {
date: new Date().toISOString(),
},
};

export const FormatDayOfWeek: Story = {
args: {
date: new Date().toISOString(),
format: DateFormat.DAY_OF_WEEK,
},
};

export const FormatHoursAndMinutes: Story = {
args: {
date: new Date().toISOString(),
format: DateFormat.HOURS_AND_MINUTES,
},
};

export const FormatTime: Story = {
args: {
date: new Date().toISOString(),
format: DateFormat.TIME,
},
};

export const FormatTimestamp: Story = {
args: {
date: new Date().toISOString(),
format: DateFormat.TIMESTAMP,
},
};

export const FormatTimestampShort: Story = {
args: {
date: new Date().toISOString(),
format: DateFormat.TIMESTAMP_SHORT,
},
};
62 changes: 62 additions & 0 deletions src/components/Date/Date.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import { getAllByTestId, render } from '@testing-library/react';

import Date from './Date';
import { DateFormat } from './Date.types';

describe('Date', () => {
it('should render successfully', () => {
const { getByTestId } = render(<Date date={0} />);

expect(getByTestId('date')).toBeDefined();
});

it('should render format Date successfully', () => {
const { getByTestId } = render(<Date date={0} format={DateFormat.DATE} />);

expect(getByTestId('date')).toBeDefined();
});

it('should render format DayOfWeek successfully', () => {
const { getByTestId } = render(<Date date={0} format={DateFormat.DAY_OF_WEEK} />);

expect(getByTestId('date')).toBeDefined();
});

it('should render format HoursAndMinutes successfully', () => {
const { getByTestId } = render(<Date date={0} format={DateFormat.HOURS_AND_MINUTES} />);

expect(getByTestId('date')).toBeDefined();
});

it('should render format Time successfully', () => {
const { getByTestId } = render(<Date date={0} format={DateFormat.TIME} />);

expect(getByTestId('date')).toBeDefined();
});

it('should render format Timestamp successfully', () => {
const { getByTestId } = render(<Date date={0} format={DateFormat.TIMESTAMP} />);

expect(getByTestId('date')).toBeDefined();
});

it('should render format TimestampShort successfully', () => {
const { getByTestId } = render(<Date date={0} format={DateFormat.TIMESTAMP_SHORT} />);

expect(getByTestId('date')).toBeDefined();
});

it('should use custom testID', () => {
const { getByTestId, queryByTestId } = render(<Date date={0} testId="custom-testid" />);

expect(queryByTestId('date')).toBeNull();
expect(getByTestId('custom-testid')).toBeDefined();
});

it('should use classes from className property', () => {
const { getByTestId } = render(<Date date={0} className="custom-class" />);

expect(getByTestId('date').classList).toContain('custom-class');
});
});
19 changes: 19 additions & 0 deletions src/components/Date/Date.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import dayjs from 'dayjs';

import { DateFormat, DateProps } from './Date.types';

const Date: React.FC<DateProps> = ({
className,
date,
testId = 'date',
format = DateFormat.DATE,
}) => {
return (
<span className={className} data-testid={testId}>
{dayjs(date).format(format)}
</span>
);
};

export default Date;
15 changes: 15 additions & 0 deletions src/components/Date/Date.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export enum DateFormat {
DATE = 'MM/DD/YYYY',
DAY_OF_WEEK = 'dddd',
HOURS_AND_MINUTES = 'H[h] mm[m]',
TIME = 'h:mma',
TIMESTAMP_SHORT = 'h:mma ddd MMM D',
TIMESTAMP = 'dddd MMMM D [at] h:mma',
}

export interface DateProps {
className?: string;
date: string | number;
format?: DateFormat;
testId?: string;
}
3 changes: 3 additions & 0 deletions src/components/Date/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as Date } from './Date';

export { DateFormat } from './Date.types';
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './Date';
export * from './Text';