Skip to content

Commit

Permalink
Create organization tasks page, resolves pets-oss#151
Browse files Browse the repository at this point in the history
pergaliuke committed Apr 27, 2021
1 parent 5523a59 commit 32ff5d2
Showing 9 changed files with 851 additions and 542 deletions.
5 changes: 5 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -55,6 +55,11 @@ export default function App() {
path="/animal/:id"
component={React.lazy(() => import('./pages/AnimalDetailsPage'))}
/>
<PrivateRoute
exact
path="/organization-tasks"
component={React.lazy(() => import('./pages/OrganizationTasksPage'))}
/>
<Route
exact
path="/search"
66 changes: 66 additions & 0 deletions src/components/task/TaskCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';

import { Box, Card, CardHeader, Typography } from '@material-ui/core';
import { Theme } from '@material-ui/core/styles';
import makeStyles from '@material-ui/core/styles/makeStyles';
import { OrganizationTask } from '../../graphql/types';

const DONE = 'Task is done';
const TODO = 'Task to be taken';

export default function TaskCard({ task }: TaskCardProps) {
const classes = useStyles();

return (
<Box my={2}>
<Card>
<CardHeader
title={
<Typography component="h6" className={classes.headerText} noWrap>
{task.title}
</Typography>
}
subheader={<Typography className={classes.subHeaderText}>{task.description}</Typography>}
/>
<Box display="flex" className={task.isDone ? classes.done : classes.todo}>
<Box my={1} mx="auto" py={1} color="white">
{task.isDone ? DONE : TODO}
</Box>
</Box>
</Card>
</Box>
);
}

const useStyles = makeStyles((theme: Theme) => ({
root: {
width: '100%',
},
headerText: {
maxWidth: 150,
[theme.breakpoints.up('md')]: {
maxWidth: 350,
},
[theme.breakpoints.up('lg')]: {
maxWidth: 600,
},
fontSize: 20,
lineHeight: '24px',
fontWeight: 600,
},
done: {
color: theme.palette.success.contrastText,
backgroundColor: theme.palette.success.main,
},
todo: {
backgroundColor: theme.palette.error.light,
color: theme.palette.error.contrastText,
},
subHeaderText: {
color: theme.palette.grey['600'],
},
}));

interface TaskCardProps {
task: OrganizationTask;
}
19 changes: 19 additions & 0 deletions src/components/task/TaskList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';

import { Box } from '@material-ui/core';
import { OrganizationTask } from '../../graphql/types';
import TaskCard from './TaskCard';

interface TaskListProps {
tasks: OrganizationTask[];
}

export default function TaskList({ tasks }: TaskListProps) {
return (
<Box component="ul">
{tasks.map(task => (
<TaskCard task={task} key={task.id} />
))}
</Box>
);
}
28 changes: 28 additions & 0 deletions src/components/task/TaskListContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { loader } from 'graphql.macro';
import React from 'react';

import { useQuery } from '@apollo/client';
import { Skeleton } from '@material-ui/lab';
import TaskList from './TaskList';

const GET_ORGANIZATION_TASKS_QUERY = loader('src/graphql/queries/organization-tasks.graphql');

export default function TaskListContainer() {
const { loading, data, error } = useQuery(GET_ORGANIZATION_TASKS_QUERY);

if (loading) {
return <Skeleton animation="wave" variant="rect" height="70vh" />;
}

if (error) {
// TODO: replace with proper UI elements
return <p>Error!</p>;
}

if (!data?.organizationTasks?.length) {
// TODO: replace with proper UI elements
return <p>No data!</p>;
}

return <TaskList tasks={data.organizationTasks} />;
}
8 changes: 8 additions & 0 deletions src/graphql/queries/organization-tasks.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
query getOrganizationTasks {
organizationTasks {
id,
title,
description,
isDone
}
}
1,207 changes: 665 additions & 542 deletions src/graphql/types.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/navigation.ts
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ const navigation: Array<NavigationItem> = [
{ authRequired: true, title: 'Animals', to: '/animal-list', pageTitle: 'Animal list' },
{ authRequired: true, title: 'Favourites', to: '/favourites', pageTitle: 'Favourites' },
{ authRequired: true, title: 'Reports', to: '/reports', pageTitle: 'Reports' },
{ authRequired: true, title: 'Organization Tasks', to: '/organization-tasks', pageTitle: 'Organization Tasks' },
];

export { navigation };
45 changes: 45 additions & 0 deletions src/pages/OrganizationTasksPage.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { loader } from 'graphql.macro';
import React from 'react';
import { act } from 'react-dom/test-utils';

import { screen } from '@testing-library/react';
import { renderWithMockProvider } from '../test-utils/render-mock-provider';
import OrganizationTasksPage from './OrganizationTasksPage';

jest.mock('@material-ui/lab/Skeleton', () => () => <div>Loading...</div>);

const GET_ORGANIZATION_TASKS_QUERY = loader('src/graphql/queries/organization-tasks.graphql');

test('should have loading state', () => {
renderWithMockProvider(<OrganizationTasksPage />, { query: GET_ORGANIZATION_TASKS_QUERY });
expect(screen.getByText(/Loading.../i)).toBeInTheDocument();
});

test('should handle error state', async () => {
renderWithMockProvider(<OrganizationTasksPage />, {
query: GET_ORGANIZATION_TASKS_QUERY,
error: new Error('Something went wrong'),
});
// Wait for the application to update
await act(async () => new Promise(resolve => setTimeout(resolve, 0)));
expect(screen.getByText(/Error!/i)).toBeInTheDocument();
});

test('should load organization task list', async () => {
renderWithMockProvider(<OrganizationTasksPage />, {
query: GET_ORGANIZATION_TASKS_QUERY,
data: {
organizationTasks: [
{
id: 1,
title: 'Vet for Murkė',
description: 'Place: Kaunakiemio g. 15a',
isDone: false,
},
],
},
});
// Wait for the application to update
await act(async () => new Promise(resolve => setTimeout(resolve, 0)));
expect(screen.getByText(/Organization Tasks/i)).toBeInTheDocument();
});
14 changes: 14 additions & 0 deletions src/pages/OrganizationTasksPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

import TaskListContainer from '../components/task/TaskListContainer';
import Page from './Page';

function OrganizationTasksPage() {
return (
<Page title="Organization Tasks">
<TaskListContainer />
</Page>
);
}

export default OrganizationTasksPage;

0 comments on commit 32ff5d2

Please sign in to comment.