Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export CSV Component #620

Merged
merged 12 commits into from
Mar 17, 2023
4 changes: 3 additions & 1 deletion dashboard/components/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function Button({

const primary = `${base} bg-gradient-to-br from-primary bg-secondary hover:bg-primary active:from-secondary active:bg-secondary text-white disabled:from-primary disabled:bg-secondary disabled:opacity-50`;

const secondary = `${base} hover:bg-black-100 active:bg-black-150 text-black-400 disabled:bg-black-100 disabled:opacity-50`;
const secondary = `${base} hover:bg-black-100 text-black-900 active:bg-black-150 text-black-400 disabled:hover:bg-transparent disabled:opacity-30`;

const bulk = `${base} bg-white hover:bg-komiser-200 active:bg-komiser-300 text-secondary disabled:bg-white disabled:opacity-50`;

Expand Down Expand Up @@ -94,6 +94,7 @@ function Button({
type={type}
className={handleStyle()}
disabled={disabled || loading}
data-testid={style}
>
{loading && (
<>
Expand All @@ -102,6 +103,7 @@ function Button({
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
data-testid="loading-spinner"
>
<circle
className="opacity-25"
Expand Down
38 changes: 38 additions & 0 deletions dashboard/components/export-csv/ExportCSV.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useRouter } from 'next/router';
import { useState } from 'react';
import settingsService from '../../services/settingsService';
import { ToastProps } from '../toast/hooks/useToast';
import ExportCSVButton from './ExportCSVButton';

type ExportCSVProps = {
displayInTable?: boolean;
setToast: (toast: ToastProps | undefined) => void;
};

function ExportCSV({ displayInTable = false, setToast }: ExportCSVProps) {
const router = useRouter();

function exportCSV(id?: string) {
settingsService.exportCSV(id);
setToast({
hasError: false,
title: 'CSV exported',
message: 'The download of the CSV file should begin shortly.'
});
}

const isFilteredList =
Object.keys(router.query).length > 0 && !router.query.view;
const id = router.query.view ? router.query.view.toString() : undefined;

return (
<ExportCSVButton
id={id}
disabled={isFilteredList}
displayInTable={displayInTable}
exportCSV={exportCSV}
/>
);
}

export default ExportCSV;
29 changes: 29 additions & 0 deletions dashboard/components/export-csv/ExportCSVButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { Meta, StoryObj } from '@storybook/react';
import ExportCSVButton from './ExportCSVButton';

const meta: Meta<typeof ExportCSVButton> = {
title: 'Komiser/Export CSV',
component: ExportCSVButton,
tags: ['autodocs'],
argTypes: {},
decorators: [
Story => (
<div className="flex items-center justify-center">
<div className="min-w-24 relative">
<Story />
</div>
</div>
)
]
};

export default meta;
type Story = StoryObj<typeof ExportCSVButton>;

export const Primary: Story = {
args: {
disabled: false,
displayInTable: false,
exportCSV: () => {}
}
};
27 changes: 27 additions & 0 deletions dashboard/components/export-csv/ExportCSVButton.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { render, screen } from '@testing-library/react';
import ExportCSVButton from './ExportCSVButton';

const props = {
id: undefined,
disabled: false,
displayInTable: false,
exportCSV: jest.fn()
};

describe('Export CSV component', () => {
it('should render without crashing', () => {
render(<ExportCSVButton {...props} />);
});

it('should render the correct button props if displayInTable is true', () => {
render(<ExportCSVButton {...props} displayInTable={true} />);
const button = screen.getByTestId('secondary');
expect(button).toBeInTheDocument();
});

it('should display the auxiliary info in the tooltip if disabled is true', () => {
render(<ExportCSVButton {...props} disabled={true} />);
const tooltip = screen.getByRole('tooltip');
expect(tooltip).toBeInTheDocument();
});
});
44 changes: 44 additions & 0 deletions dashboard/components/export-csv/ExportCSVButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Button from '../button/Button';
import DownloadIcon from '../icons/DownloadIcon';
import Tooltip from '../tooltip/Tooltip';

type ExportCSVButtonProps = {
id?: string;
disabled: boolean;
displayInTable: boolean;
exportCSV: (id?: string) => void;
};

function ExportCSVButton({
id,
disabled,
displayInTable,
exportCSV
}: ExportCSVButtonProps) {
return (
<>
<div className="peer flex flex-col">
<Button
style={displayInTable ? 'secondary' : 'ghost'}
size="sm"
align="left"
gap="md"
transition={false}
disabled={disabled}
onClick={() => exportCSV(id)}
>
<DownloadIcon width={24} height={24} />
Download CSV
</Button>
</div>
{disabled && (
<Tooltip top="sm" align="right" width="lg">
This feature isn&apos;t available yet. To download data from a
filtered table, save it as a view and download it from there.
</Tooltip>
)}
</>
);
}

export default ExportCSVButton;
34 changes: 34 additions & 0 deletions dashboard/components/icons/AlertIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { SVGProps } from 'react';

const AlertIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeMiterlimit="10"
strokeWidth="1.5"
d="M12.02 2.91c-3.31 0-6 2.69-6 6v2.89c0 .61-.26 1.54-.57 2.06L4.3 15.77c-.71 1.18-.22 2.49 1.08 2.93 4.31 1.44 8.96 1.44 13.27 0 1.21-.4 1.74-1.83 1.08-2.93l-1.15-1.91c-.3-.52-.56-1.45-.56-2.06V8.91c0-3.3-2.7-6-6-6z"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeMiterlimit="10"
strokeWidth="1.5"
d="M13.87 3.2a6.754 6.754 0 00-3.7 0c.29-.74 1.01-1.26 1.85-1.26.84 0 1.56.52 1.85 1.26z"
></path>
<path
stroke="currentColor"
strokeMiterlimit="10"
strokeWidth="1.5"
d="M15.02 19.06c0 1.65-1.35 3-3 3-.82 0-1.58-.34-2.12-.88a3.01 3.01 0 01-.88-2.12"
></path>
</svg>
);

export default AlertIcon;
27 changes: 27 additions & 0 deletions dashboard/components/icons/BookmarkIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { SVGProps } from 'react';

const BookmarkIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M16 8.99v11.36c0 1.45-1.04 2.06-2.31 1.36l-3.93-2.19c-.42-.23-1.1-.23-1.52 0l-3.93 2.19c-1.27.7-2.31.09-2.31-1.36V8.99c0-1.71 1.4-3.11 3.11-3.11h7.78c1.71 0 3.11 1.4 3.11 3.11z"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M22 5.11v11.36c0 1.45-1.04 2.06-2.31 1.36L16 15.77V8.99c0-1.71-1.4-3.11-3.11-3.11H8v-.77C8 3.4 9.4 2 11.11 2h7.78C20.6 2 22 3.4 22 5.11zM7 12h4M9 14v-4"
></path>
</svg>
);

export default BookmarkIcon;
21 changes: 21 additions & 0 deletions dashboard/components/icons/ChevronDownIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { SVGProps } from 'react';

const ChevronDownIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeMiterlimit="10"
strokeWidth="1.5"
d="M19.92 8.95l-6.52 6.52c-.77.77-2.03.77-2.8 0L4.08 8.95"
></path>
</svg>
);

export default ChevronDownIcon;
20 changes: 20 additions & 0 deletions dashboard/components/icons/CloseIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { SVGProps } from 'react';

const CloseIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M7.757 16.243l8.486-8.486M16.243 16.243L7.757 7.757"
></path>
</svg>
);

export default CloseIcon;
20 changes: 20 additions & 0 deletions dashboard/components/icons/DeleteIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { SVGProps } from 'react';

const DeleteIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M21 5.98c-3.33-.33-6.68-.5-10.02-.5-1.98 0-3.96.1-5.94.3L3 5.98M8.5 4.97l.22-1.31C8.88 2.71 9 2 10.69 2h2.62c1.69 0 1.82.75 1.97 1.67l.22 1.3M18.85 9.14l-.65 10.07C18.09 20.78 18 22 15.21 22H8.79C6 22 5.91 20.78 5.8 19.21L5.15 9.14M10.33 16.5h3.33M9.5 12.5h5"
></path>
</svg>
);

export default DeleteIcon;
34 changes: 34 additions & 0 deletions dashboard/components/icons/DownloadIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { SVGProps } from 'react';

const DownloadIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M9 11.5v6l2-2M9 17.5l-2-2"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M22 10.5v5c0 5-2 7-7 7H9c-5 0-7-2-7-7v-6c0-5 2-7 7-7h5"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M22 10.5h-4c-3 0-4-1-4-4v-4l8 8z"
></path>
</svg>
);

export default DownloadIcon;
27 changes: 27 additions & 0 deletions dashboard/components/icons/DuplicateIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { SVGProps } from 'react';

const DuplicateIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M16 12.9v4.2c0 3.5-1.4 4.9-4.9 4.9H6.9C3.4 22 2 20.6 2 17.1v-4.2C2 9.4 3.4 8 6.9 8h4.2c3.5 0 4.9 1.4 4.9 4.9z"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M22 6.9v4.2c0 3.5-1.4 4.9-4.9 4.9H16v-3.1C16 9.4 14.6 8 11.1 8H8V6.9C8 3.4 9.4 2 12.9 2h4.2C20.6 2 22 3.4 22 6.9z"
></path>
</svg>
);

export default DuplicateIcon;
28 changes: 28 additions & 0 deletions dashboard/components/icons/EditIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { SVGProps } from 'react';

const EditIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M11 2H9C4 2 2 4 2 9v6c0 5 2 7 7 7h6c5 0 7-2 7-7v-2"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeMiterlimit="10"
strokeWidth="1.5"
d="M16.04 3.02L8.16 10.9c-.3.3-.6.89-.66 1.32l-.43 3.01c-.16 1.09.61 1.85 1.7 1.7l3.01-.43c.42-.06 1.01-.36 1.32-.66l7.88-7.88c1.36-1.36 2-2.94 0-4.94-2-2-3.58-1.36-4.94 0zM14.91 4.15a7.144 7.144 0 004.94 4.94"
></path>
</svg>
);

export default EditIcon;
Loading