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,8 +7,17 @@ import TrashContainer from './containers/TrashContainer/TrashContainer'
|
|||||||
import NotFoundContainer from './containers/NotFoundContainer/NotFoundContainer'
|
import NotFoundContainer from './containers/NotFoundContainer/NotFoundContainer'
|
||||||
import CssBaseLine from '@material-ui/core/CssBaseline'
|
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 }) => {
|
const App = ({ history }) => {
|
||||||
return (
|
return (
|
||||||
|
<ApolloProvider client={client}>
|
||||||
<>
|
<>
|
||||||
<CssBaseLine />
|
<CssBaseLine />
|
||||||
<Layout history={history}>
|
<Layout history={history}>
|
||||||
@ -21,6 +30,7 @@ const App = ({ history }) => {
|
|||||||
</Switch>
|
</Switch>
|
||||||
</Layout>
|
</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 }) => {
|
const Categories = ({ data, history, classes }) => {
|
||||||
return data.map((category, i) => {
|
return data.map((category, i) => {
|
||||||
return (
|
return (
|
||||||
<Link className={classes.link} key={i} to={`/category/${category._id.$oid}`}>
|
<Link className={classes.link} key={i} to={`/category/${category.id}`}>
|
||||||
<ListItem selected={history.location.pathname === `/category/${category._id.$oid}`} button className={classes.nested}>
|
<ListItem selected={history.location.pathname === `/category/${category.id}`} button className={classes.nested}>
|
||||||
<ListItemText primary={category.title} />
|
<ListItemText primary={category.title} />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</Link>
|
</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 { Dialog, DialogContent, DialogTitle, DialogActions, Button, TextField, Select, MenuItem, InputLabel, FormControl } from '@material-ui/core'
|
||||||
import AddIcon from '@material-ui/icons/Add'
|
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 CreateTodoModal = ({ isModalOpen, handleCloseModal }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
@ -14,15 +18,29 @@ const CreateTodoModal = ({ isModalOpen, handleCloseModal }) => {
|
|||||||
deadline: ''
|
deadline: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 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 => {
|
const handleFormSubmit = e => {
|
||||||
|
try {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
const elements = e.target.elements
|
const elements = e.target.elements
|
||||||
const data = {
|
createTodo({
|
||||||
|
variables: {
|
||||||
title: elements.title.value,
|
title: elements.title.value,
|
||||||
description: elements.description.value,
|
description: elements.description.value,
|
||||||
categoryId: elements.category.value,
|
categoryId: elements.category.value,
|
||||||
deadline: elements.deadline.value
|
deadline: elements.deadline.value
|
||||||
}
|
}
|
||||||
|
})
|
||||||
handleCloseModal()
|
handleCloseModal()
|
||||||
setFieldsData({
|
setFieldsData({
|
||||||
title: '',
|
title: '',
|
||||||
@ -30,7 +48,9 @@ const CreateTodoModal = ({ isModalOpen, handleCloseModal }) => {
|
|||||||
category: '',
|
category: '',
|
||||||
deadline: ''
|
deadline: ''
|
||||||
})
|
})
|
||||||
console.log('Request on create todo:', data)
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFieldChange = e => {
|
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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Dialog fullWidth={true} open={isModalOpen} onClose={handleCloseModal} color='default'>
|
<Dialog fullWidth={true} open={isModalOpen} onClose={handleCloseModal} color='default'>
|
||||||
@ -87,7 +112,7 @@ const CreateTodoModal = ({ isModalOpen, handleCloseModal }) => {
|
|||||||
onChange={handleFieldChange}
|
onChange={handleFieldChange}
|
||||||
label="Категория"
|
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>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<TextField
|
<TextField
|
||||||
|
|||||||
@ -12,8 +12,9 @@ import DeleteIcon from '@material-ui/icons/Delete';
|
|||||||
import GitHubIcon from '@material-ui/icons/GitHub';
|
import GitHubIcon from '@material-ui/icons/GitHub';
|
||||||
import ExpandLess from '@material-ui/icons/ExpandLess'
|
import ExpandLess from '@material-ui/icons/ExpandLess'
|
||||||
import ExpandMore from '@material-ui/icons/ExpandMore'
|
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 NavContent = ({ history, handleOpenModal }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
@ -53,7 +54,13 @@ const NavContent = ({ history, handleOpenModal }) => {
|
|||||||
</ListItem>
|
</ListItem>
|
||||||
<Collapse in={collapseInfo.isCollapseOpen} timeout="auto" unmountOnExit>
|
<Collapse in={collapseInfo.isCollapseOpen} timeout="auto" unmountOnExit>
|
||||||
<List component="div" disablePadding>
|
<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}>
|
<ListItem className={classes.addCategoryItem}>
|
||||||
<IconButton onClick={handleOpenModal} aria-label="add">
|
<IconButton onClick={handleOpenModal} aria-label="add">
|
||||||
<AddIcon />
|
<AddIcon />
|
||||||
|
|||||||
@ -11,8 +11,6 @@ import DeleteIcon from '@material-ui/icons/Delete'
|
|||||||
import AlarmIcon from '@material-ui/icons/Alarm';
|
import AlarmIcon from '@material-ui/icons/Alarm';
|
||||||
import EditIcon from '@material-ui/icons/Edit';
|
import EditIcon from '@material-ui/icons/Edit';
|
||||||
|
|
||||||
import categories from '../../db/categories.json'
|
|
||||||
|
|
||||||
const Todos = ({ data, fromTrashContainer }) => {
|
const Todos = ({ data, fromTrashContainer }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const [selectedTodo, setSelectedTodo] = React.useState({
|
const [selectedTodo, setSelectedTodo] = React.useState({
|
||||||
@ -27,10 +25,10 @@ const Todos = ({ data, fromTrashContainer }) => {
|
|||||||
|
|
||||||
const handleOpenModal = todo => {
|
const handleOpenModal = todo => {
|
||||||
const selectedTodo = {
|
const selectedTodo = {
|
||||||
id: todo._id.$oid,
|
id: todo.id,
|
||||||
title: todo.title,
|
title: todo.title,
|
||||||
description: todo.description,
|
description: todo.description,
|
||||||
category: todo.categoryId,
|
category: todo.category,
|
||||||
deadline: todo.deadline
|
deadline: todo.deadline
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,10 +39,10 @@ const Todos = ({ data, fromTrashContainer }) => {
|
|||||||
|
|
||||||
const handleOpenDialog = todo => {
|
const handleOpenDialog = todo => {
|
||||||
setSelectedTodo({
|
setSelectedTodo({
|
||||||
id: todo._id.$oid,
|
id: todo.id,
|
||||||
title: todo.title,
|
title: todo.title,
|
||||||
description: todo.description,
|
description: todo.description,
|
||||||
category: todo.categoryId,
|
category: todo.category,
|
||||||
deadline: todo.deadline
|
deadline: todo.deadline
|
||||||
})
|
})
|
||||||
setIsOpenDialog(true)
|
setIsOpenDialog(true)
|
||||||
@ -53,10 +51,10 @@ const Todos = ({ data, fromTrashContainer }) => {
|
|||||||
|
|
||||||
const handleOpenRestoreDialog = todo => {
|
const handleOpenRestoreDialog = todo => {
|
||||||
setSelectedTodo({
|
setSelectedTodo({
|
||||||
id: todo._id.$oid,
|
id: todo.id,
|
||||||
title: todo.title,
|
title: todo.title,
|
||||||
description: todo.description,
|
description: todo.description,
|
||||||
category: todo.categoryId,
|
category: todo.category,
|
||||||
deadline: todo.deadline
|
deadline: todo.deadline
|
||||||
})
|
})
|
||||||
setIsOpenRestoreDialog(true)
|
setIsOpenRestoreDialog(true)
|
||||||
@ -81,7 +79,7 @@ const Todos = ({ data, fromTrashContainer }) => {
|
|||||||
<Card>
|
<Card>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Typography className={classes.cardCategoryHeading} color="textSecondary" gutterBottom>
|
<Typography className={classes.cardCategoryHeading} color="textSecondary" gutterBottom>
|
||||||
{categories.find(category => category._id.$oid === todo.categoryId).title}
|
{todo.category.title}
|
||||||
<span className={classes.cardAlarm}>
|
<span className={classes.cardAlarm}>
|
||||||
<AlarmIcon className={classes.alarmIcon} color='action' />
|
<AlarmIcon className={classes.alarmIcon} color='action' />
|
||||||
{todo.deadline}
|
{todo.deadline}
|
||||||
|
|||||||
@ -3,13 +3,15 @@ import Todos from '../../components/Todos/Todos'
|
|||||||
import UpdateCategoryModal from '../../components/Modals/Category/UpdateCategoryModal'
|
import UpdateCategoryModal from '../../components/Modals/Category/UpdateCategoryModal'
|
||||||
import DeleteCategoryDialog from '../../components/Dialogs/Category/DeleteCategoryDialog'
|
import DeleteCategoryDialog from '../../components/Dialogs/Category/DeleteCategoryDialog'
|
||||||
import Fab from '../../components/Fab/Fab'
|
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 categories from '../../db/categories.json'
|
||||||
|
|
||||||
|
import { Query } from 'react-apollo'
|
||||||
import { useParams } from 'react-router-dom'
|
import { useParams } from 'react-router-dom'
|
||||||
|
|
||||||
|
import GET_TODOS_BY_CATEGORY from '../../apollo/queries/todos/todosByCategory'
|
||||||
|
|
||||||
const Category = () => {
|
const Category = () => {
|
||||||
const findCategoryById = id => categories.find(category => category._id.$oid === id)
|
const findCategoryById = id => categories.find(category => category._id.$oid === id)
|
||||||
|
|
||||||
@ -28,6 +30,11 @@ const Category = () => {
|
|||||||
const handleOpenDialog = () => setIsOpenDialog(true)
|
const handleOpenDialog = () => setIsOpenDialog(true)
|
||||||
const handleCloseDialog = () => setIsOpenDialog(false)
|
const handleCloseDialog = () => setIsOpenDialog(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Query query={GET_TODOS_BY_CATEGORY} variables={{ id }}>
|
||||||
|
{({ loading, error, data }) => {
|
||||||
|
if (loading) return <LinearProgress />
|
||||||
|
if (error) return `Error! ${error.message}`;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<UpdateCategoryModal isModalOpen={isModalOpen} handleCloseModal={handleCloseModal} selectedCategory={selectedCategory} setSelectedCategory={setSelectedCategory} />
|
<UpdateCategoryModal isModalOpen={isModalOpen} handleCloseModal={handleCloseModal} selectedCategory={selectedCategory} setSelectedCategory={setSelectedCategory} />
|
||||||
@ -41,10 +48,13 @@ const Category = () => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
{/* Здесь берем значение slug из query и передаем полученные данные в prop data !!!! */}
|
{/* Здесь берем значение slug из query и передаем полученные данные в prop data !!!! */}
|
||||||
<Todos data={todos} />
|
<Todos data={data.category.todos} />
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
}}
|
||||||
|
</Query>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Category
|
export default Category
|
||||||
@ -2,14 +2,21 @@ import React from 'react';
|
|||||||
import Fab from '../../components/Fab/Fab'
|
import Fab from '../../components/Fab/Fab'
|
||||||
import Todos from '../../components/Todos/Todos'
|
import Todos from '../../components/Todos/Todos'
|
||||||
import CreateTodoModal from '../../components/Modals/Todo/CreateTodoModal'
|
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 TodosContainer = () => {
|
||||||
const [isModalOpen, setIsModalOpen] = React.useState(false)
|
const [isModalOpen, setIsModalOpen] = React.useState(false)
|
||||||
const handleOpenModal = () => setIsModalOpen(true)
|
const handleOpenModal = () => setIsModalOpen(true)
|
||||||
const handleCloseModal = () => setIsModalOpen(false)
|
const handleCloseModal = () => setIsModalOpen(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Query query={GET_TODOS}>
|
||||||
|
{({ loading, error, data }) => {
|
||||||
|
if (loading) return <LinearProgress />
|
||||||
|
if (error) return `Error! ${error.message}`;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CreateTodoModal isModalOpen={isModalOpen} handleCloseModal={handleCloseModal} />
|
<CreateTodoModal isModalOpen={isModalOpen} handleCloseModal={handleCloseModal} />
|
||||||
@ -20,10 +27,13 @@ const TodosContainer = () => {
|
|||||||
Создавайте, редактируйте или удаляйте ваши повседневные дела.
|
Создавайте, редактируйте или удаляйте ваши повседневные дела.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Todos data={todos} />
|
<Todos data={data.todos} />
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
}}
|
||||||
|
</Query>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TodosContainer
|
export default TodosContainer
|
||||||
@ -2,8 +2,6 @@ import React from 'react';
|
|||||||
import Todos from '../../components/Todos/Todos'
|
import Todos from '../../components/Todos/Todos'
|
||||||
import { Grid, Typography } from '@material-ui/core'
|
import { Grid, Typography } from '@material-ui/core'
|
||||||
|
|
||||||
import todos from '../../db/todos.json'
|
|
||||||
|
|
||||||
const Trash = () => {
|
const Trash = () => {
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
@ -13,7 +11,7 @@ const Trash = () => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
{/* Здесь также выполняем нужный запрос на удаленные записи в БД !!!!!!!! */}
|
{/* Здесь также выполняем нужный запрос на удаленные записи в БД !!!!!!!! */}
|
||||||
<Todos data={todos} fromTrashContainer={true} />
|
{/* <Todos data={todos} fromTrashContainer={true} /> */}
|
||||||
</Grid>
|
</Grid>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user