mirror of
https://github.com/sergeyyarkov/todo-app.git
synced 2026-10-11 18:39:09 +03:00
added apollo client & cache on create todo
This commit is contained in:
parent
437b18536d
commit
02ad7d86de
@ -7,20 +7,30 @@ import TrashContainer from './containers/TrashContainer/TrashContainer'
|
||||
import NotFoundContainer from './containers/NotFoundContainer/NotFoundContainer'
|
||||
import CssBaseLine from '@material-ui/core/CssBaseline'
|
||||
|
||||
import ApolloClient from 'apollo-boost'
|
||||
import { ApolloProvider } from 'react-apollo'
|
||||
|
||||
|
||||
const client = new ApolloClient({
|
||||
uri: 'http://localhost:3001'
|
||||
})
|
||||
|
||||
const App = ({ history }) => {
|
||||
return (
|
||||
<>
|
||||
<CssBaseLine />
|
||||
<Layout history={history}>
|
||||
<Switch>
|
||||
<Route history={history} exact path='/category/:id' component={CategoryContainer} />
|
||||
<Route history={history} exact path='/trash' component={TrashContainer} />
|
||||
<Route history={history} exact path='/' component={TodosContainer} />
|
||||
<Route path='/404' component={NotFoundContainer} />
|
||||
<Redirect from='*' to='/404' />
|
||||
</Switch>
|
||||
</Layout>
|
||||
</>
|
||||
<ApolloProvider client={client}>
|
||||
<>
|
||||
<CssBaseLine />
|
||||
<Layout history={history}>
|
||||
<Switch>
|
||||
<Route history={history} exact path='/category/:id' component={CategoryContainer} />
|
||||
<Route history={history} exact path='/trash' component={TrashContainer} />
|
||||
<Route history={history} exact path='/' component={TodosContainer} />
|
||||
<Route path='/404' component={NotFoundContainer} />
|
||||
<Redirect from='*' to='/404' />
|
||||
</Switch>
|
||||
</Layout>
|
||||
</>
|
||||
</ApolloProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
18
client/src/apollo/mutations/todos/createTodo.js
Normal file
18
client/src/apollo/mutations/todos/createTodo.js
Normal file
@ -0,0 +1,18 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
const CREATE_TODO = gql`
|
||||
mutation CreateTodo($title: String! $description: String! $deadline: String! $categoryId: String!) {
|
||||
createTodo(title: $title description: $description deadline: $deadline categoryId: $categoryId) {
|
||||
id
|
||||
title
|
||||
description
|
||||
status
|
||||
deadline
|
||||
category {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export default CREATE_TODO
|
||||
12
client/src/apollo/queries/categories/categories.js
Normal file
12
client/src/apollo/queries/categories/categories.js
Normal file
@ -0,0 +1,12 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
const GET_CATEGORIES = gql`
|
||||
{
|
||||
categories {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export default GET_CATEGORIES
|
||||
18
client/src/apollo/queries/todos/todos.js
Normal file
18
client/src/apollo/queries/todos/todos.js
Normal file
@ -0,0 +1,18 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
const GET_TODOS = gql`
|
||||
query getTodos {
|
||||
todos {
|
||||
id
|
||||
title
|
||||
description
|
||||
status
|
||||
deadline
|
||||
category {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default GET_TODOS
|
||||
22
client/src/apollo/queries/todos/todosByCategory.js
Normal file
22
client/src/apollo/queries/todos/todosByCategory.js
Normal file
@ -0,0 +1,22 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
const GET_TODOS_BY_CATEGORY = gql`
|
||||
query getTodosByCategory($id: ID!) {
|
||||
category(id: $id) {
|
||||
id
|
||||
title
|
||||
todos {
|
||||
id
|
||||
title
|
||||
description
|
||||
status
|
||||
deadline
|
||||
category {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export default GET_TODOS_BY_CATEGORY
|
||||
@ -5,8 +5,8 @@ import { ListItem, ListItemText } from '@material-ui/core'
|
||||
const Categories = ({ data, history, classes }) => {
|
||||
return data.map((category, i) => {
|
||||
return (
|
||||
<Link className={classes.link} key={i} to={`/category/${category._id.$oid}`}>
|
||||
<ListItem selected={history.location.pathname === `/category/${category._id.$oid}`} button className={classes.nested}>
|
||||
<Link className={classes.link} key={i} to={`/category/${category.id}`}>
|
||||
<ListItem selected={history.location.pathname === `/category/${category.id}`} button className={classes.nested}>
|
||||
<ListItemText primary={category.title} />
|
||||
</ListItem>
|
||||
</Link>
|
||||
|
||||
@ -3,7 +3,11 @@ import useStyles from '../styles'
|
||||
import { Dialog, DialogContent, DialogTitle, DialogActions, Button, TextField, Select, MenuItem, InputLabel, FormControl } from '@material-ui/core'
|
||||
import AddIcon from '@material-ui/icons/Add'
|
||||
|
||||
import categories from '../../../db/categories.json'
|
||||
import { useQuery, useMutation } from '@apollo/react-hooks'
|
||||
|
||||
import CREATE_TODO from '../../../apollo/mutations/todos/createTodo';
|
||||
import GET_TODOS from '../../../apollo/queries/todos/todos';
|
||||
import GET_CATEGORIES from '../../../apollo/queries/categories/categories'
|
||||
|
||||
const CreateTodoModal = ({ isModalOpen, handleCloseModal }) => {
|
||||
const classes = useStyles()
|
||||
@ -14,23 +18,39 @@ const CreateTodoModal = ({ isModalOpen, handleCloseModal }) => {
|
||||
deadline: ''
|
||||
})
|
||||
|
||||
const handleFormSubmit = e => {
|
||||
e.preventDefault()
|
||||
const elements = e.target.elements
|
||||
const data = {
|
||||
title: elements.title.value,
|
||||
description: elements.description.value,
|
||||
categoryId: elements.category.value,
|
||||
deadline: elements.deadline.value
|
||||
// create todo mutation
|
||||
const [createTodo] = useMutation(CREATE_TODO, {
|
||||
update(cache, { data: { createTodo } }) {
|
||||
const { todos } = cache.readQuery({ query: GET_TODOS })
|
||||
cache.writeQuery({
|
||||
query: GET_TODOS,
|
||||
data: { todos: todos.concat([createTodo]) }
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
const handleFormSubmit = e => {
|
||||
try {
|
||||
e.preventDefault()
|
||||
const elements = e.target.elements
|
||||
createTodo({
|
||||
variables: {
|
||||
title: elements.title.value,
|
||||
description: elements.description.value,
|
||||
categoryId: elements.category.value,
|
||||
deadline: elements.deadline.value
|
||||
}
|
||||
})
|
||||
handleCloseModal()
|
||||
setFieldsData({
|
||||
title: '',
|
||||
description: '',
|
||||
category: '',
|
||||
deadline: ''
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
handleCloseModal()
|
||||
setFieldsData({
|
||||
title: '',
|
||||
description: '',
|
||||
category: '',
|
||||
deadline: ''
|
||||
})
|
||||
console.log('Request on create todo:', data)
|
||||
}
|
||||
|
||||
const handleFieldChange = e => {
|
||||
@ -43,6 +63,11 @@ const CreateTodoModal = ({ isModalOpen, handleCloseModal }) => {
|
||||
})
|
||||
}
|
||||
|
||||
const { loading, error, data } = useQuery(GET_CATEGORIES);
|
||||
|
||||
if (loading) return null;
|
||||
if (error) return `Error! ${error.message}`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Dialog fullWidth={true} open={isModalOpen} onClose={handleCloseModal} color='default'>
|
||||
@ -87,7 +112,7 @@ const CreateTodoModal = ({ isModalOpen, handleCloseModal }) => {
|
||||
onChange={handleFieldChange}
|
||||
label="Категория"
|
||||
>
|
||||
{categories.map((category, i) => <MenuItem key={i} value={category._id.$oid}>{category.title}</MenuItem>)}
|
||||
{data.categories.map((category, i) => <MenuItem key={i} value={category.id}>{category.title}</MenuItem>)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<TextField
|
||||
|
||||
@ -12,8 +12,9 @@ import DeleteIcon from '@material-ui/icons/Delete';
|
||||
import GitHubIcon from '@material-ui/icons/GitHub';
|
||||
import ExpandLess from '@material-ui/icons/ExpandLess'
|
||||
import ExpandMore from '@material-ui/icons/ExpandMore'
|
||||
import { Query } from 'react-apollo'
|
||||
|
||||
import categories from '../../../db/categories.json'
|
||||
import GET_CATEGORIES from '../../../apollo/queries/categories/categories'
|
||||
|
||||
const NavContent = ({ history, handleOpenModal }) => {
|
||||
const classes = useStyles()
|
||||
@ -53,7 +54,13 @@ const NavContent = ({ history, handleOpenModal }) => {
|
||||
</ListItem>
|
||||
<Collapse in={collapseInfo.isCollapseOpen} timeout="auto" unmountOnExit>
|
||||
<List component="div" disablePadding>
|
||||
<Categories data={categories} history={history} classes={classes} />
|
||||
<Query query={GET_CATEGORIES}>
|
||||
{({ loading, error, data }) => {
|
||||
if (loading) return null;
|
||||
if (error) return `Error! ${error}`;
|
||||
return <Categories data={data.categories} history={history} classes={classes} />
|
||||
}}
|
||||
</Query>
|
||||
<ListItem className={classes.addCategoryItem}>
|
||||
<IconButton onClick={handleOpenModal} aria-label="add">
|
||||
<AddIcon />
|
||||
|
||||
@ -11,8 +11,6 @@ import DeleteIcon from '@material-ui/icons/Delete'
|
||||
import AlarmIcon from '@material-ui/icons/Alarm';
|
||||
import EditIcon from '@material-ui/icons/Edit';
|
||||
|
||||
import categories from '../../db/categories.json'
|
||||
|
||||
const Todos = ({ data, fromTrashContainer }) => {
|
||||
const classes = useStyles()
|
||||
const [selectedTodo, setSelectedTodo] = React.useState({
|
||||
@ -27,10 +25,10 @@ const Todos = ({ data, fromTrashContainer }) => {
|
||||
|
||||
const handleOpenModal = todo => {
|
||||
const selectedTodo = {
|
||||
id: todo._id.$oid,
|
||||
id: todo.id,
|
||||
title: todo.title,
|
||||
description: todo.description,
|
||||
category: todo.categoryId,
|
||||
category: todo.category,
|
||||
deadline: todo.deadline
|
||||
}
|
||||
|
||||
@ -41,10 +39,10 @@ const Todos = ({ data, fromTrashContainer }) => {
|
||||
|
||||
const handleOpenDialog = todo => {
|
||||
setSelectedTodo({
|
||||
id: todo._id.$oid,
|
||||
id: todo.id,
|
||||
title: todo.title,
|
||||
description: todo.description,
|
||||
category: todo.categoryId,
|
||||
category: todo.category,
|
||||
deadline: todo.deadline
|
||||
})
|
||||
setIsOpenDialog(true)
|
||||
@ -53,10 +51,10 @@ const Todos = ({ data, fromTrashContainer }) => {
|
||||
|
||||
const handleOpenRestoreDialog = todo => {
|
||||
setSelectedTodo({
|
||||
id: todo._id.$oid,
|
||||
id: todo.id,
|
||||
title: todo.title,
|
||||
description: todo.description,
|
||||
category: todo.categoryId,
|
||||
category: todo.category,
|
||||
deadline: todo.deadline
|
||||
})
|
||||
setIsOpenRestoreDialog(true)
|
||||
@ -81,7 +79,7 @@ const Todos = ({ data, fromTrashContainer }) => {
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography className={classes.cardCategoryHeading} color="textSecondary" gutterBottom>
|
||||
{categories.find(category => category._id.$oid === todo.categoryId).title}
|
||||
{todo.category.title}
|
||||
<span className={classes.cardAlarm}>
|
||||
<AlarmIcon className={classes.alarmIcon} color='action' />
|
||||
{todo.deadline}
|
||||
|
||||
@ -3,13 +3,15 @@ import Todos from '../../components/Todos/Todos'
|
||||
import UpdateCategoryModal from '../../components/Modals/Category/UpdateCategoryModal'
|
||||
import DeleteCategoryDialog from '../../components/Dialogs/Category/DeleteCategoryDialog'
|
||||
import Fab from '../../components/Fab/Fab'
|
||||
import { Grid, Typography } from '@material-ui/core'
|
||||
import { Grid, Typography, LinearProgress } from '@material-ui/core'
|
||||
|
||||
import todos from '../../db/todos.json'
|
||||
import categories from '../../db/categories.json'
|
||||
|
||||
import { Query } from 'react-apollo'
|
||||
import { useParams } from 'react-router-dom'
|
||||
|
||||
import GET_TODOS_BY_CATEGORY from '../../apollo/queries/todos/todosByCategory'
|
||||
|
||||
const Category = () => {
|
||||
const findCategoryById = id => categories.find(category => category._id.$oid === id)
|
||||
|
||||
@ -29,21 +31,29 @@ const Category = () => {
|
||||
const handleCloseDialog = () => setIsOpenDialog(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
<UpdateCategoryModal isModalOpen={isModalOpen} handleCloseModal={handleCloseModal} selectedCategory={selectedCategory} setSelectedCategory={setSelectedCategory} />
|
||||
<DeleteCategoryDialog isOpenDialog={isOpenDialog} handleCloseDialog={handleCloseDialog} />
|
||||
<Fab style={{ marginRight: '6.5rem' }} size='large' ariaLabel='add' typeIcon='edit' onClick={handleOpenModal} />
|
||||
<Fab size='large' color="secondary" ariaLabel='delete' typeIcon='delete' onClick={handleOpenDialog} />
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography>
|
||||
Сортируйте свои повседневные дела используя категории.
|
||||
</Typography>
|
||||
</Grid>
|
||||
{/* Здесь берем значение slug из query и передаем полученные данные в prop data !!!! */}
|
||||
<Todos data={todos} />
|
||||
</Grid>
|
||||
</>
|
||||
<Query query={GET_TODOS_BY_CATEGORY} variables={{ id }}>
|
||||
{({ loading, error, data }) => {
|
||||
if (loading) return <LinearProgress />
|
||||
if (error) return `Error! ${error.message}`;
|
||||
return (
|
||||
<>
|
||||
<UpdateCategoryModal isModalOpen={isModalOpen} handleCloseModal={handleCloseModal} selectedCategory={selectedCategory} setSelectedCategory={setSelectedCategory} />
|
||||
<DeleteCategoryDialog isOpenDialog={isOpenDialog} handleCloseDialog={handleCloseDialog} />
|
||||
<Fab style={{ marginRight: '6.5rem' }} size='large' ariaLabel='add' typeIcon='edit' onClick={handleOpenModal} />
|
||||
<Fab size='large' color="secondary" ariaLabel='delete' typeIcon='delete' onClick={handleOpenDialog} />
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography>
|
||||
Сортируйте свои повседневные дела используя категории.
|
||||
</Typography>
|
||||
</Grid>
|
||||
{/* Здесь берем значение slug из query и передаем полученные данные в prop data !!!! */}
|
||||
<Todos data={data.category.todos} />
|
||||
</Grid>
|
||||
</>
|
||||
)
|
||||
}}
|
||||
</Query>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -2,27 +2,37 @@ import React from 'react';
|
||||
import Fab from '../../components/Fab/Fab'
|
||||
import Todos from '../../components/Todos/Todos'
|
||||
import CreateTodoModal from '../../components/Modals/Todo/CreateTodoModal'
|
||||
import { Typography, Grid } from '@material-ui/core'
|
||||
import { Query } from 'react-apollo'
|
||||
import { Typography, Grid, LinearProgress } from '@material-ui/core'
|
||||
|
||||
import todos from '../../db/todos.json'
|
||||
import GET_TODOS from '../../apollo/queries/todos/todos'
|
||||
|
||||
const TodosContainer = () => {
|
||||
const [isModalOpen, setIsModalOpen] = React.useState(false)
|
||||
const handleOpenModal = () => setIsModalOpen(true)
|
||||
const handleCloseModal = () => setIsModalOpen(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
<CreateTodoModal isModalOpen={isModalOpen} handleCloseModal={handleCloseModal} />
|
||||
<Fab typeIcon='add' color="secondary" size='large' ariaLabel="add" onClick={handleOpenModal} />
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography>
|
||||
Создавайте, редактируйте или удаляйте ваши повседневные дела.
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Todos data={todos} />
|
||||
</Grid>
|
||||
</>
|
||||
<Query query={GET_TODOS}>
|
||||
{({ loading, error, data }) => {
|
||||
if (loading) return <LinearProgress />
|
||||
if (error) return `Error! ${error.message}`;
|
||||
return (
|
||||
<>
|
||||
<CreateTodoModal isModalOpen={isModalOpen} handleCloseModal={handleCloseModal} />
|
||||
<Fab typeIcon='add' color="secondary" size='large' ariaLabel="add" onClick={handleOpenModal} />
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography>
|
||||
Создавайте, редактируйте или удаляйте ваши повседневные дела.
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Todos data={data.todos} />
|
||||
</Grid>
|
||||
</>
|
||||
)
|
||||
}}
|
||||
</Query>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -2,8 +2,6 @@ import React from 'react';
|
||||
import Todos from '../../components/Todos/Todos'
|
||||
import { Grid, Typography } from '@material-ui/core'
|
||||
|
||||
import todos from '../../db/todos.json'
|
||||
|
||||
const Trash = () => {
|
||||
return (
|
||||
<Grid container spacing={2}>
|
||||
@ -13,7 +11,7 @@ const Trash = () => {
|
||||
</Typography>
|
||||
</Grid>
|
||||
{/* Здесь также выполняем нужный запрос на удаленные записи в БД !!!!!!!! */}
|
||||
<Todos data={todos} fromTrashContainer={true} />
|
||||
{/* <Todos data={todos} fromTrashContainer={true} /> */}
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user