chore: add prettier and run it on all files

This commit is contained in:
2024-08-17 17:30:56 +02:00
parent 143b48c7a9
commit 2f8ff0d004
28 changed files with 1609 additions and 1117 deletions

View File

@@ -5,34 +5,63 @@ import { Delete } from '@mui/icons-material'
import { TaskStatuses, TaskType } from '../../../../api/todolists-api'
type TaskPropsType = {
task: TaskType
todolistId: string
changeTaskStatus: (id: string, status: TaskStatuses, todolistId: string) => void
changeTaskTitle: (taskId: string, newTitle: string, todolistId: string) => void
removeTask: (taskId: string, todolistId: string) => void
task: TaskType
todolistId: string
changeTaskStatus: (
id: string,
status: TaskStatuses,
todolistId: string
) => void
changeTaskTitle: (
taskId: string,
newTitle: string,
todolistId: string
) => void
removeTask: (taskId: string, todolistId: string) => void
}
export const Task = React.memo((props: TaskPropsType) => {
const onClickHandler = useCallback(() => props.removeTask(props.task.id, props.todolistId), [props.task.id, props.todolistId]);
const onClickHandler = useCallback(
() => props.removeTask(props.task.id, props.todolistId),
[props.task.id, props.todolistId]
)
const onChangeHandler = useCallback((e: ChangeEvent<HTMLInputElement>) => {
let newIsDoneValue = e.currentTarget.checked
props.changeTaskStatus(props.task.id, newIsDoneValue ? TaskStatuses.Completed : TaskStatuses.New, props.todolistId)
}, [props.task.id, props.todolistId]);
const onChangeHandler = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
let newIsDoneValue = e.currentTarget.checked
props.changeTaskStatus(
props.task.id,
newIsDoneValue ? TaskStatuses.Completed : TaskStatuses.New,
props.todolistId
)
},
[props.task.id, props.todolistId]
)
const onTitleChangeHandler = useCallback((newValue: string) => {
props.changeTaskTitle(props.task.id, newValue, props.todolistId)
}, [props.task.id, props.todolistId]);
const onTitleChangeHandler = useCallback(
(newValue: string) => {
props.changeTaskTitle(props.task.id, newValue, props.todolistId)
},
[props.task.id, props.todolistId]
)
return <div key={props.task.id} className={props.task.status === TaskStatuses.Completed ? 'is-done' : ''}>
<Checkbox
checked={props.task.status === TaskStatuses.Completed}
color="primary"
onChange={onChangeHandler}
/>
return (
<div
key={props.task.id}
className={props.task.status === TaskStatuses.Completed ? 'is-done' : ''}
>
<Checkbox
checked={props.task.status === TaskStatuses.Completed}
color='primary'
onChange={onChangeHandler}
/>
<EditableSpan value={props.task.title} onChange={onTitleChangeHandler}/>
<IconButton onClick={onClickHandler}>
<Delete/>
</IconButton>
</div>
<EditableSpan
value={props.task.title}
onChange={onTitleChangeHandler}
/>
<IconButton onClick={onClickHandler}>
<Delete />
</IconButton>
</div>
)
})

View File

@@ -5,92 +5,139 @@ import { Task } from './Task/Task'
import { TaskStatuses, TaskType } from '../../../api/todolists-api'
import { FilterValuesType, TodolistDomainType } from '../todolists-reducer'
import { fetchTasksTC } from '../tasks-reducer'
import { useAppDispatch } from '../../../hooks/useAppDispatch';
import { useAppDispatch } from '../../../hooks/useAppDispatch'
import { Button, IconButton } from '@mui/material'
import { Delete } from '@mui/icons-material'
type PropsType = {
todolist: TodolistDomainType
tasks: Array<TaskType>
changeFilter: (value: FilterValuesType, todolistId: string) => void
addTask: (title: string, todolistId: string) => void
changeTaskStatus: (id: string, status: TaskStatuses, todolistId: string) => void
changeTaskTitle: (taskId: string, newTitle: string, todolistId: string) => void
removeTask: (taskId: string, todolistId: string) => void
removeTodolist: (id: string) => void
changeTodolistTitle: (id: string, newTitle: string) => void
demo?: boolean
todolist: TodolistDomainType
tasks: Array<TaskType>
changeFilter: (value: FilterValuesType, todolistId: string) => void
addTask: (title: string, todolistId: string) => void
changeTaskStatus: (
id: string,
status: TaskStatuses,
todolistId: string
) => void
changeTaskTitle: (
taskId: string,
newTitle: string,
todolistId: string
) => void
removeTask: (taskId: string, todolistId: string) => void
removeTodolist: (id: string) => void
changeTodolistTitle: (id: string, newTitle: string) => void
demo?: boolean
}
export const Todolist = React.memo(function ({demo = false, ...props}: PropsType) {
export const Todolist = React.memo(function ({
demo = false,
...props
}: PropsType) {
const dispatch = useAppDispatch()
const dispatch = useAppDispatch()
useEffect(() => {
if (demo) {
return
}
const thunk = fetchTasksTC(props.todolist.id)
dispatch(thunk)
}, [])
const addTask = useCallback((title: string) => {
props.addTask(title, props.todolist.id)
}, [props.addTask, props.todolist.id])
const removeTodolist = () => {
props.removeTodolist(props.todolist.id)
useEffect(() => {
if (demo) {
return
}
const changeTodolistTitle = useCallback((title: string) => {
props.changeTodolistTitle(props.todolist.id, title)
}, [props.todolist.id, props.changeTodolistTitle])
const thunk = fetchTasksTC(props.todolist.id)
dispatch(thunk)
}, [])
const onAllClickHandler = useCallback(() => props.changeFilter('all', props.todolist.id), [props.todolist.id, props.changeFilter])
const onActiveClickHandler = useCallback(() => props.changeFilter('active', props.todolist.id), [props.todolist.id, props.changeFilter])
const onCompletedClickHandler = useCallback(() => props.changeFilter('completed', props.todolist.id), [props.todolist.id, props.changeFilter])
const addTask = useCallback(
(title: string) => {
props.addTask(title, props.todolist.id)
},
[props.addTask, props.todolist.id]
)
const removeTodolist = () => {
props.removeTodolist(props.todolist.id)
}
const changeTodolistTitle = useCallback(
(title: string) => {
props.changeTodolistTitle(props.todolist.id, title)
},
[props.todolist.id, props.changeTodolistTitle]
)
let tasksForTodolist = props.tasks
const onAllClickHandler = useCallback(
() => props.changeFilter('all', props.todolist.id),
[props.todolist.id, props.changeFilter]
)
const onActiveClickHandler = useCallback(
() => props.changeFilter('active', props.todolist.id),
[props.todolist.id, props.changeFilter]
)
const onCompletedClickHandler = useCallback(
() => props.changeFilter('completed', props.todolist.id),
[props.todolist.id, props.changeFilter]
)
if (props.todolist.filter === 'active') {
tasksForTodolist = props.tasks.filter(t => t.status === TaskStatuses.New)
}
if (props.todolist.filter === 'completed') {
tasksForTodolist = props.tasks.filter(t => t.status === TaskStatuses.Completed)
}
let tasksForTodolist = props.tasks
return <div>
<h3><EditableSpan value={props.todolist.title} onChange={changeTodolistTitle}/>
<IconButton onClick={removeTodolist} disabled={props.todolist.entityStatus === 'loading'}>
<Delete/>
</IconButton>
</h3>
<AddItemForm addItem={addTask} disabled={props.todolist.entityStatus === 'loading'}/>
<div>
{
tasksForTodolist.map(t => <Task key={t.id} task={t} todolistId={props.todolist.id}
removeTask={props.removeTask}
changeTaskTitle={props.changeTaskTitle}
changeTaskStatus={props.changeTaskStatus}
/>)
}
</div>
<div style={{paddingTop: '10px'}}>
<Button variant={props.todolist.filter === 'all' ? 'outlined' : 'text'}
onClick={onAllClickHandler}
color={'inherit'}
>All
</Button>
<Button variant={props.todolist.filter === 'active' ? 'outlined' : 'text'}
onClick={onActiveClickHandler}
color={'primary'}>Active
</Button>
<Button variant={props.todolist.filter === 'completed' ? 'outlined' : 'text'}
onClick={onCompletedClickHandler}
color={'secondary'}>Completed
</Button>
</div>
if (props.todolist.filter === 'active') {
tasksForTodolist = props.tasks.filter((t) => t.status === TaskStatuses.New)
}
if (props.todolist.filter === 'completed') {
tasksForTodolist = props.tasks.filter(
(t) => t.status === TaskStatuses.Completed
)
}
return (
<div>
<h3>
<EditableSpan
value={props.todolist.title}
onChange={changeTodolistTitle}
/>
<IconButton
onClick={removeTodolist}
disabled={props.todolist.entityStatus === 'loading'}
>
<Delete />
</IconButton>
</h3>
<AddItemForm
addItem={addTask}
disabled={props.todolist.entityStatus === 'loading'}
/>
<div>
{tasksForTodolist.map((t) => (
<Task
key={t.id}
task={t}
todolistId={props.todolist.id}
removeTask={props.removeTask}
changeTaskTitle={props.changeTaskTitle}
changeTaskStatus={props.changeTaskStatus}
/>
))}
</div>
<div style={{ paddingTop: '10px' }}>
<Button
variant={props.todolist.filter === 'all' ? 'outlined' : 'text'}
onClick={onAllClickHandler}
color={'inherit'}
>
All
</Button>
<Button
variant={props.todolist.filter === 'active' ? 'outlined' : 'text'}
onClick={onActiveClickHandler}
color={'primary'}
>
Active
</Button>
<Button
variant={props.todolist.filter === 'completed' ? 'outlined' : 'text'}
onClick={onCompletedClickHandler}
color={'secondary'}
>
Completed
</Button>
</div>
</div>
)
})

View File

@@ -2,112 +2,148 @@ import React, { useCallback, useEffect } from 'react'
import { useSelector } from 'react-redux'
import { AppRootStateType } from '../../app/store'
import {
addTodolistTC,
changeTodolistFilterAC,
changeTodolistTitleTC,
fetchTodolistsTC,
FilterValuesType,
removeTodolistTC,
TodolistDomainType
addTodolistTC,
changeTodolistFilterAC,
changeTodolistTitleTC,
fetchTodolistsTC,
FilterValuesType,
removeTodolistTC,
TodolistDomainType,
} from './todolists-reducer'
import { addTaskTC, removeTaskTC, TasksStateType, updateTaskTC } from './tasks-reducer'
import {
addTaskTC,
removeTaskTC,
TasksStateType,
updateTaskTC,
} from './tasks-reducer'
import { TaskStatuses } from '../../api/todolists-api'
import { Grid, Paper } from '@mui/material'
import { AddItemForm } from '../../components/AddItemForm/AddItemForm'
import { Todolist } from './Todolist/Todolist'
import { Navigate } from 'react-router-dom'
import { useAppDispatch } from '../../hooks/useAppDispatch';
import { useAppDispatch } from '../../hooks/useAppDispatch'
type PropsType = {
demo?: boolean
demo?: boolean
}
export const TodolistsList: React.FC<PropsType> = ({demo = false}) => {
const todolists = useSelector<AppRootStateType, Array<TodolistDomainType>>(state => state.todolists)
const tasks = useSelector<AppRootStateType, TasksStateType>(state => state.tasks)
const isLoggedIn = useSelector<AppRootStateType, boolean>(state => state.auth.isLoggedIn)
export const TodolistsList: React.FC<PropsType> = ({ demo = false }) => {
const todolists = useSelector<AppRootStateType, Array<TodolistDomainType>>(
(state) => state.todolists
)
const tasks = useSelector<AppRootStateType, TasksStateType>(
(state) => state.tasks
)
const isLoggedIn = useSelector<AppRootStateType, boolean>(
(state) => state.auth.isLoggedIn
)
const dispatch = useAppDispatch()
const dispatch = useAppDispatch()
useEffect(() => {
if (demo || !isLoggedIn) {
return;
}
const thunk = fetchTodolistsTC()
dispatch(thunk)
}, [])
const removeTask = useCallback(function (id: string, todolistId: string) {
const thunk = removeTaskTC(id, todolistId)
dispatch(thunk)
}, [])
const addTask = useCallback(function (title: string, todolistId: string) {
const thunk = addTaskTC(title, todolistId)
dispatch(thunk)
}, [])
const changeStatus = useCallback(function (id: string, status: TaskStatuses, todolistId: string) {
const thunk = updateTaskTC(id, {status}, todolistId)
dispatch(thunk)
}, [])
const changeTaskTitle = useCallback(function (id: string, newTitle: string, todolistId: string) {
const thunk = updateTaskTC(id, {title: newTitle}, todolistId)
dispatch(thunk)
}, [])
const changeFilter = useCallback(function (value: FilterValuesType, todolistId: string) {
const action = changeTodolistFilterAC(todolistId, value)
dispatch(action)
}, [])
const removeTodolist = useCallback(function (id: string) {
const thunk = removeTodolistTC(id)
dispatch(thunk)
}, [])
const changeTodolistTitle = useCallback(function (id: string, title: string) {
const thunk = changeTodolistTitleTC(id, title)
dispatch(thunk)
}, [])
const addTodolist = useCallback((title: string) => {
const thunk = addTodolistTC(title)
dispatch(thunk)
}, [dispatch])
if (!isLoggedIn) {
return <Navigate to={"/login"} />
useEffect(() => {
if (demo || !isLoggedIn) {
return
}
const thunk = fetchTodolistsTC()
dispatch(thunk)
}, [])
return <>
<Grid container style={{padding: '20px'}}>
<AddItemForm addItem={addTodolist}/>
</Grid>
<Grid container spacing={3}>
{
todolists.map(tl => {
let allTodolistTasks = tasks[tl.id]
const removeTask = useCallback(function (id: string, todolistId: string) {
const thunk = removeTaskTC(id, todolistId)
dispatch(thunk)
}, [])
return <Grid item key={tl.id}>
<Paper style={{padding: '10px'}}>
<Todolist
todolist={tl}
tasks={allTodolistTasks}
removeTask={removeTask}
changeFilter={changeFilter}
addTask={addTask}
changeTaskStatus={changeStatus}
removeTodolist={removeTodolist}
changeTaskTitle={changeTaskTitle}
changeTodolistTitle={changeTodolistTitle}
demo={demo}
/>
</Paper>
</Grid>
})
}
</Grid>
const addTask = useCallback(function (title: string, todolistId: string) {
const thunk = addTaskTC(title, todolistId)
dispatch(thunk)
}, [])
const changeStatus = useCallback(function (
id: string,
status: TaskStatuses,
todolistId: string
) {
const thunk = updateTaskTC(id, { status }, todolistId)
dispatch(thunk)
}, [])
const changeTaskTitle = useCallback(function (
id: string,
newTitle: string,
todolistId: string
) {
const thunk = updateTaskTC(id, { title: newTitle }, todolistId)
dispatch(thunk)
}, [])
const changeFilter = useCallback(function (
value: FilterValuesType,
todolistId: string
) {
const action = changeTodolistFilterAC(todolistId, value)
dispatch(action)
}, [])
const removeTodolist = useCallback(function (id: string) {
const thunk = removeTodolistTC(id)
dispatch(thunk)
}, [])
const changeTodolistTitle = useCallback(function (id: string, title: string) {
const thunk = changeTodolistTitleTC(id, title)
dispatch(thunk)
}, [])
const addTodolist = useCallback(
(title: string) => {
const thunk = addTodolistTC(title)
dispatch(thunk)
},
[dispatch]
)
if (!isLoggedIn) {
return <Navigate to={'/login'} />
}
return (
<>
<Grid
container
style={{ padding: '20px' }}
>
<AddItemForm addItem={addTodolist} />
</Grid>
<Grid
container
spacing={3}
>
{todolists.map((tl) => {
let allTodolistTasks = tasks[tl.id]
return (
<Grid
item
key={tl.id}
>
<Paper style={{ padding: '10px' }}>
<Todolist
todolist={tl}
tasks={allTodolistTasks}
removeTask={removeTask}
changeFilter={changeFilter}
addTask={addTask}
changeTaskStatus={changeStatus}
removeTodolist={removeTodolist}
changeTaskTitle={changeTaskTitle}
changeTodolistTitle={changeTodolistTitle}
demo={demo}
/>
</Paper>
</Grid>
)
})}
</Grid>
</>
)
}

View File

@@ -1,133 +1,205 @@
import { addTaskAC, removeTaskAC, setTasksAC, tasksReducer, TasksStateType, updateTaskAC } from './tasks-reducer'
import {
addTaskAC,
removeTaskAC,
setTasksAC,
tasksReducer,
TasksStateType,
updateTaskAC,
} from './tasks-reducer'
import {addTodolistAC, removeTodolistAC, setTodolistsAC} from './todolists-reducer'
import {TaskPriorities, TaskStatuses} from '../../api/todolists-api'
import {
addTodolistAC,
removeTodolistAC,
setTodolistsAC,
} from './todolists-reducer'
import { TaskPriorities, TaskStatuses } from '../../api/todolists-api'
let startState: TasksStateType = {};
let startState: TasksStateType = {}
beforeEach(() => {
startState = {
"todolistId1": [
{ id: "1", title: "CSS", status: TaskStatuses.New, todoListId: "todolistId1", description: '',
startDate: '', deadline: '', addedDate: '', order: 0, priority: TaskPriorities.Low },
{ id: "2", title: "JS", status: TaskStatuses.Completed, todoListId: "todolistId1", description: '',
startDate: '', deadline: '', addedDate: '', order: 0, priority: TaskPriorities.Low },
{ id: "3", title: "React", status: TaskStatuses.New, todoListId: "todolistId1", description: '',
startDate: '', deadline: '', addedDate: '', order: 0, priority: TaskPriorities.Low }
],
"todolistId2": [
{ id: "1", title: "bread", status: TaskStatuses.New, todoListId: "todolistId2", description: '',
startDate: '', deadline: '', addedDate: '', order: 0, priority: TaskPriorities.Low },
{ id: "2", title: "milk", status: TaskStatuses.Completed, todoListId: "todolistId2", description: '',
startDate: '', deadline: '', addedDate: '', order: 0, priority: TaskPriorities.Low },
{ id: "3", title: "tea", status: TaskStatuses.New, todoListId: "todolistId2", description: '',
startDate: '', deadline: '', addedDate: '', order: 0, priority: TaskPriorities.Low }
]
};
});
startState = {
todolistId1: [
{
id: '1',
title: 'CSS',
status: TaskStatuses.New,
todoListId: 'todolistId1',
description: '',
startDate: '',
deadline: '',
addedDate: '',
order: 0,
priority: TaskPriorities.Low,
},
{
id: '2',
title: 'JS',
status: TaskStatuses.Completed,
todoListId: 'todolistId1',
description: '',
startDate: '',
deadline: '',
addedDate: '',
order: 0,
priority: TaskPriorities.Low,
},
{
id: '3',
title: 'React',
status: TaskStatuses.New,
todoListId: 'todolistId1',
description: '',
startDate: '',
deadline: '',
addedDate: '',
order: 0,
priority: TaskPriorities.Low,
},
],
todolistId2: [
{
id: '1',
title: 'bread',
status: TaskStatuses.New,
todoListId: 'todolistId2',
description: '',
startDate: '',
deadline: '',
addedDate: '',
order: 0,
priority: TaskPriorities.Low,
},
{
id: '2',
title: 'milk',
status: TaskStatuses.Completed,
todoListId: 'todolistId2',
description: '',
startDate: '',
deadline: '',
addedDate: '',
order: 0,
priority: TaskPriorities.Low,
},
{
id: '3',
title: 'tea',
status: TaskStatuses.New,
todoListId: 'todolistId2',
description: '',
startDate: '',
deadline: '',
addedDate: '',
order: 0,
priority: TaskPriorities.Low,
},
],
}
})
test('correct task should be deleted from correct array', () => {
const action = removeTaskAC("2", "todolistId2");
const action = removeTaskAC('2', 'todolistId2')
const endState = tasksReducer(startState, action)
const endState = tasksReducer(startState, action)
expect(endState["todolistId1"].length).toBe(3);
expect(endState["todolistId2"].length).toBe(2);
expect(endState["todolistId2"].every(t => t.id != "2")).toBeTruthy();
});
expect(endState['todolistId1'].length).toBe(3)
expect(endState['todolistId2'].length).toBe(2)
expect(endState['todolistId2'].every((t) => t.id != '2')).toBeTruthy()
})
test('correct task should be added to correct array', () => {
//const action = addTaskAC("juce", "todolistId2");
const action = addTaskAC({
todoListId: "todolistId2",
title: "juce",
status: TaskStatuses.New,
addedDate: "",
deadline: "",
description: "",
order: 0,
priority: 0,
startDate: "",
id: "id exists"
});
//const action = addTaskAC("juce", "todolistId2");
const action = addTaskAC({
todoListId: 'todolistId2',
title: 'juce',
status: TaskStatuses.New,
addedDate: '',
deadline: '',
description: '',
order: 0,
priority: 0,
startDate: '',
id: 'id exists',
})
const endState = tasksReducer(startState, action)
const endState = tasksReducer(startState, action)
expect(endState["todolistId1"].length).toBe(3);
expect(endState["todolistId2"].length).toBe(4);
expect(endState["todolistId2"][0].id).toBeDefined();
expect(endState["todolistId2"][0].title).toBe("juce");
expect(endState["todolistId2"][0].status).toBe(TaskStatuses.New);
});
expect(endState['todolistId1'].length).toBe(3)
expect(endState['todolistId2'].length).toBe(4)
expect(endState['todolistId2'][0].id).toBeDefined()
expect(endState['todolistId2'][0].title).toBe('juce')
expect(endState['todolistId2'][0].status).toBe(TaskStatuses.New)
})
test('status of specified task should be changed', () => {
const action = updateTaskAC("2", {status: TaskStatuses.New}, "todolistId2");
const action = updateTaskAC('2', { status: TaskStatuses.New }, 'todolistId2')
const endState = tasksReducer(startState, action)
const endState = tasksReducer(startState, action)
expect(endState["todolistId1"][1].status).toBe(TaskStatuses.Completed);
expect(endState["todolistId2"][1].status).toBe(TaskStatuses.New);
});
expect(endState['todolistId1'][1].status).toBe(TaskStatuses.Completed)
expect(endState['todolistId2'][1].status).toBe(TaskStatuses.New)
})
test('title of specified task should be changed', () => {
const action = updateTaskAC("2", {title: "yogurt"}, "todolistId2");
const action = updateTaskAC('2', { title: 'yogurt' }, 'todolistId2')
const endState = tasksReducer(startState, action)
const endState = tasksReducer(startState, action)
expect(endState["todolistId1"][1].title).toBe("JS");
expect(endState["todolistId2"][1].title).toBe("yogurt");
expect(endState["todolistId2"][0].title).toBe("bread");
});
expect(endState['todolistId1'][1].title).toBe('JS')
expect(endState['todolistId2'][1].title).toBe('yogurt')
expect(endState['todolistId2'][0].title).toBe('bread')
})
test('new array should be added when new todolist is added', () => {
const action = addTodolistAC({
id: "blabla",
title: "new todolist",
order: 0,
addedDate: ''
});
const action = addTodolistAC({
id: 'blabla',
title: 'new todolist',
order: 0,
addedDate: '',
})
const endState = tasksReducer(startState, action)
const endState = tasksReducer(startState, action)
const keys = Object.keys(endState)
const newKey = keys.find((k) => k != 'todolistId1' && k != 'todolistId2')
if (!newKey) {
throw Error('new key should be added')
}
const keys = Object.keys(endState);
const newKey = keys.find(k => k != "todolistId1" && k != "todolistId2");
if (!newKey) {
throw Error("new key should be added")
}
expect(keys.length).toBe(3);
expect(endState[newKey]).toEqual([]);
});
expect(keys.length).toBe(3)
expect(endState[newKey]).toEqual([])
})
test('propertry with todolistId should be deleted', () => {
const action = removeTodolistAC("todolistId2");
const action = removeTodolistAC('todolistId2')
const endState = tasksReducer(startState, action)
const endState = tasksReducer(startState, action)
const keys = Object.keys(endState);
const keys = Object.keys(endState)
expect(keys.length).toBe(1);
expect(endState["todolistId2"]).not.toBeDefined();
});
expect(keys.length).toBe(1)
expect(endState['todolistId2']).not.toBeDefined()
})
test('empty arrays should be added when we set todolists', () => {
const action = setTodolistsAC([
{id: "1", title: "title 1", order: 0, addedDate: ""},
{id: "2", title: "title 2", order: 0, addedDate: ""}
])
const action = setTodolistsAC([
{ id: '1', title: 'title 1', order: 0, addedDate: '' },
{ id: '2', title: 'title 2', order: 0, addedDate: '' },
])
const endState = tasksReducer({}, action)
const endState = tasksReducer({}, action)
const keys = Object.keys(endState)
const keys = Object.keys(endState)
expect(keys.length).toBe(2)
expect(endState['1']).toBeDefined()
expect(endState['2']).toBeDefined()
expect(keys.length).toBe(2)
expect(endState['1']).toBeDefined()
expect(endState['2']).toBeDefined()
})
test('tasks should be added for todolist', () => {
const action = setTasksAC(startState["todolistId1"], "todolistId1");
const action = setTasksAC(startState['todolistId1'], 'todolistId1')
const endState = tasksReducer({
"todolistId2": [],
"todolistId1": []
}, action)
const endState = tasksReducer(
{
todolistId2: [],
todolistId1: [],
},
action
)
expect(endState["todolistId1"].length).toBe(3)
expect(endState["todolistId2"].length).toBe(0)
expect(endState['todolistId1'].length).toBe(3)
expect(endState['todolistId2'].length).toBe(0)
})

View File

@@ -1,140 +1,192 @@
import {AddTodolistActionType, RemoveTodolistActionType, SetTodolistsActionType} from './todolists-reducer'
import {TaskPriorities, TaskStatuses, TaskType, todolistsAPI, UpdateTaskModelType} from '../../api/todolists-api'
import {Dispatch} from 'redux'
import {AppRootStateType} from '../../app/store'
import {setAppErrorAC, SetAppErrorActionType, setAppStatusAC, SetAppStatusActionType} from '../../app/app-reducer'
import {handleServerAppError, handleServerNetworkError} from '../../utils/error-utils'
import {
AddTodolistActionType,
RemoveTodolistActionType,
SetTodolistsActionType,
} from './todolists-reducer'
import {
TaskPriorities,
TaskStatuses,
TaskType,
todolistsAPI,
UpdateTaskModelType,
} from '../../api/todolists-api'
import { Dispatch } from 'redux'
import { AppRootStateType } from '../../app/store'
import {
setAppErrorAC,
SetAppErrorActionType,
setAppStatusAC,
SetAppStatusActionType,
} from '../../app/app-reducer'
import {
handleServerAppError,
handleServerNetworkError,
} from '../../utils/error-utils'
const initialState: TasksStateType = {}
export const tasksReducer = (state: TasksStateType = initialState, action: ActionsType): TasksStateType => {
switch (action.type) {
case 'REMOVE-TASK':
return {...state, [action.todolistId]: state[action.todolistId].filter(t => t.id != action.taskId)}
case 'ADD-TASK':
return {...state, [action.task.todoListId]: [action.task, ...state[action.task.todoListId]]}
case 'UPDATE-TASK':
return {
...state,
[action.todolistId]: state[action.todolistId]
.map(t => t.id === action.taskId ? {...t, ...action.model} : t)
}
case 'ADD-TODOLIST':
return {...state, [action.todolist.id]: []}
case 'REMOVE-TODOLIST':
const copyState = {...state}
delete copyState[action.id]
return copyState
case 'SET-TODOLISTS': {
const copyState = {...state}
action.todolists.forEach(tl => {
copyState[tl.id] = []
})
return copyState
}
case 'SET-TASKS':
return {...state, [action.todolistId]: action.tasks}
default:
return state
export const tasksReducer = (
state: TasksStateType = initialState,
action: ActionsType
): TasksStateType => {
switch (action.type) {
case 'REMOVE-TASK':
return {
...state,
[action.todolistId]: state[action.todolistId].filter(
(t) => t.id != action.taskId
),
}
case 'ADD-TASK':
return {
...state,
[action.task.todoListId]: [
action.task,
...state[action.task.todoListId],
],
}
case 'UPDATE-TASK':
return {
...state,
[action.todolistId]: state[action.todolistId].map((t) =>
t.id === action.taskId ? { ...t, ...action.model } : t
),
}
case 'ADD-TODOLIST':
return { ...state, [action.todolist.id]: [] }
case 'REMOVE-TODOLIST':
const copyState = { ...state }
delete copyState[action.id]
return copyState
case 'SET-TODOLISTS': {
const copyState = { ...state }
action.todolists.forEach((tl) => {
copyState[tl.id] = []
})
return copyState
}
case 'SET-TASKS':
return { ...state, [action.todolistId]: action.tasks }
default:
return state
}
}
// actions
export const removeTaskAC = (taskId: string, todolistId: string) =>
({type: 'REMOVE-TASK', taskId, todolistId} as const)
({ type: 'REMOVE-TASK', taskId, todolistId }) as const
export const addTaskAC = (task: TaskType) =>
({type: 'ADD-TASK', task} as const)
export const updateTaskAC = (taskId: string, model: UpdateDomainTaskModelType, todolistId: string) =>
({type: 'UPDATE-TASK', model, todolistId, taskId} as const)
({ type: 'ADD-TASK', task }) as const
export const updateTaskAC = (
taskId: string,
model: UpdateDomainTaskModelType,
todolistId: string
) => ({ type: 'UPDATE-TASK', model, todolistId, taskId }) as const
export const setTasksAC = (tasks: Array<TaskType>, todolistId: string) =>
({type: 'SET-TASKS', tasks, todolistId} as const)
({ type: 'SET-TASKS', tasks, todolistId }) as const
// thunks
export const fetchTasksTC = (todolistId: string) => (dispatch: Dispatch<ActionsType | SetAppStatusActionType>) => {
export const fetchTasksTC =
(todolistId: string) =>
(dispatch: Dispatch<ActionsType | SetAppStatusActionType>) => {
dispatch(setAppStatusAC('loading'))
todolistsAPI.getTasks(todolistId)
.then((res) => {
const tasks = res.data.items
dispatch(setTasksAC(tasks, todolistId))
dispatch(setAppStatusAC('succeeded'))
})
}
export const removeTaskTC = (taskId: string, todolistId: string) => (dispatch: Dispatch<ActionsType>) => {
todolistsAPI.deleteTask(todolistId, taskId)
.then(res => {
const action = removeTaskAC(taskId, todolistId)
dispatch(action)
})
}
export const addTaskTC = (title: string, todolistId: string) => (dispatch: Dispatch<ActionsType | SetAppErrorActionType | SetAppStatusActionType>) => {
todolistsAPI.getTasks(todolistId).then((res) => {
const tasks = res.data.items
dispatch(setTasksAC(tasks, todolistId))
dispatch(setAppStatusAC('succeeded'))
})
}
export const removeTaskTC =
(taskId: string, todolistId: string) => (dispatch: Dispatch<ActionsType>) => {
todolistsAPI.deleteTask(todolistId, taskId).then((res) => {
const action = removeTaskAC(taskId, todolistId)
dispatch(action)
})
}
export const addTaskTC =
(title: string, todolistId: string) =>
(
dispatch: Dispatch<
ActionsType | SetAppErrorActionType | SetAppStatusActionType
>
) => {
dispatch(setAppStatusAC('loading'))
todolistsAPI.createTask(todolistId, title)
.then(res => {
if (res.data.resultCode === 0) {
const task = res.data.data.item
const action = addTaskAC(task)
dispatch(action)
dispatch(setAppStatusAC('succeeded'))
} else {
handleServerAppError(res.data, dispatch);
}
})
.catch((error) => {
handleServerNetworkError(error, dispatch)
})
}
export const updateTaskTC = (taskId: string, domainModel: UpdateDomainTaskModelType, todolistId: string) =>
(dispatch: ThunkDispatch, getState: () => AppRootStateType) => {
const state = getState()
const task = state.tasks[todolistId].find(t => t.id === taskId)
if (!task) {
//throw new Error("task not found in the state");
console.warn('task not found in the state')
return
todolistsAPI
.createTask(todolistId, title)
.then((res) => {
if (res.data.resultCode === 0) {
const task = res.data.data.item
const action = addTaskAC(task)
dispatch(action)
dispatch(setAppStatusAC('succeeded'))
} else {
handleServerAppError(res.data, dispatch)
}
const apiModel: UpdateTaskModelType = {
deadline: task.deadline,
description: task.description,
priority: task.priority,
startDate: task.startDate,
title: task.title,
status: task.status,
...domainModel
}
todolistsAPI.updateTask(todolistId, taskId, apiModel)
.then(res => {
if (res.data.resultCode === 0) {
const action = updateTaskAC(taskId, domainModel, todolistId)
dispatch(action)
} else {
handleServerAppError(res.data, dispatch);
}
})
.catch((error) => {
handleServerNetworkError(error, dispatch);
})
})
.catch((error) => {
handleServerNetworkError(error, dispatch)
})
}
export const updateTaskTC =
(
taskId: string,
domainModel: UpdateDomainTaskModelType,
todolistId: string
) =>
(dispatch: ThunkDispatch, getState: () => AppRootStateType) => {
const state = getState()
const task = state.tasks[todolistId].find((t) => t.id === taskId)
if (!task) {
//throw new Error("task not found in the state");
console.warn('task not found in the state')
return
}
const apiModel: UpdateTaskModelType = {
deadline: task.deadline,
description: task.description,
priority: task.priority,
startDate: task.startDate,
title: task.title,
status: task.status,
...domainModel,
}
todolistsAPI
.updateTask(todolistId, taskId, apiModel)
.then((res) => {
if (res.data.resultCode === 0) {
const action = updateTaskAC(taskId, domainModel, todolistId)
dispatch(action)
} else {
handleServerAppError(res.data, dispatch)
}
})
.catch((error) => {
handleServerNetworkError(error, dispatch)
})
}
// types
export type UpdateDomainTaskModelType = {
title?: string
description?: string
status?: TaskStatuses
priority?: TaskPriorities
startDate?: string
deadline?: string
title?: string
description?: string
status?: TaskStatuses
priority?: TaskPriorities
startDate?: string
deadline?: string
}
export type TasksStateType = {
[key: string]: Array<TaskType>
[key: string]: Array<TaskType>
}
type ActionsType =
| ReturnType<typeof removeTaskAC>
| ReturnType<typeof addTaskAC>
| ReturnType<typeof updateTaskAC>
| AddTodolistActionType
| RemoveTodolistActionType
| SetTodolistsActionType
| ReturnType<typeof setTasksAC>
type ThunkDispatch = Dispatch<ActionsType | SetAppStatusActionType | SetAppErrorActionType>
| ReturnType<typeof removeTaskAC>
| ReturnType<typeof addTaskAC>
| ReturnType<typeof updateTaskAC>
| AddTodolistActionType
| RemoveTodolistActionType
| SetTodolistsActionType
| ReturnType<typeof setTasksAC>
type ThunkDispatch = Dispatch<
ActionsType | SetAppStatusActionType | SetAppErrorActionType
>

View File

@@ -1,89 +1,102 @@
import {
addTodolistAC, changeTodolistEntityStatusAC,
changeTodolistFilterAC,
changeTodolistTitleAC, FilterValuesType,
removeTodolistAC, setTodolistsAC, TodolistDomainType,
todolistsReducer
addTodolistAC,
changeTodolistEntityStatusAC,
changeTodolistFilterAC,
changeTodolistTitleAC,
FilterValuesType,
removeTodolistAC,
setTodolistsAC,
TodolistDomainType,
todolistsReducer,
} from './todolists-reducer'
import {v1} from 'uuid'
import {TodolistType} from '../../api/todolists-api'
import {RequestStatusType} from '../../app/app-reducer'
import { v1 } from 'uuid'
import { TodolistType } from '../../api/todolists-api'
import { RequestStatusType } from '../../app/app-reducer'
let todolistId1: string
let todolistId2: string
let startState: Array<TodolistDomainType> = []
beforeEach(() => {
todolistId1 = v1()
todolistId2 = v1()
startState = [
{id: todolistId1, title: 'What to learn', filter: 'all', entityStatus: 'idle', addedDate: '', order: 0},
{id: todolistId2, title: 'What to buy', filter: 'all', entityStatus: 'idle', addedDate: '', order: 0}
]
todolistId1 = v1()
todolistId2 = v1()
startState = [
{
id: todolistId1,
title: 'What to learn',
filter: 'all',
entityStatus: 'idle',
addedDate: '',
order: 0,
},
{
id: todolistId2,
title: 'What to buy',
filter: 'all',
entityStatus: 'idle',
addedDate: '',
order: 0,
},
]
})
test('correct todolist should be removed', () => {
const endState = todolistsReducer(startState, removeTodolistAC(todolistId1))
const endState = todolistsReducer(startState, removeTodolistAC(todolistId1))
expect(endState.length).toBe(1)
expect(endState[0].id).toBe(todolistId2)
expect(endState.length).toBe(1)
expect(endState[0].id).toBe(todolistId2)
})
test('correct todolist should be added', () => {
let todolist: TodolistType = {
title: 'New Todolist',
id: 'any id',
addedDate: '',
order: 0
}
let todolist: TodolistType = {
title: 'New Todolist',
id: 'any id',
addedDate: '',
order: 0,
}
const endState = todolistsReducer(startState, addTodolistAC(todolist))
const endState = todolistsReducer(startState, addTodolistAC(todolist))
expect(endState.length).toBe(3)
expect(endState[0].title).toBe(todolist.title)
expect(endState[0].filter).toBe('all')
expect(endState.length).toBe(3)
expect(endState[0].title).toBe(todolist.title)
expect(endState[0].filter).toBe('all')
})
test('correct todolist should change its name', () => {
let newTodolistTitle = 'New Todolist'
let newTodolistTitle = 'New Todolist'
const action = changeTodolistTitleAC(todolistId2, newTodolistTitle)
const action = changeTodolistTitleAC(todolistId2, newTodolistTitle)
const endState = todolistsReducer(startState, action)
const endState = todolistsReducer(startState, action)
expect(endState[0].title).toBe('What to learn')
expect(endState[1].title).toBe(newTodolistTitle)
expect(endState[0].title).toBe('What to learn')
expect(endState[1].title).toBe(newTodolistTitle)
})
test('correct filter of todolist should be changed', () => {
let newFilter: FilterValuesType = 'completed'
let newFilter: FilterValuesType = 'completed'
const action = changeTodolistFilterAC(todolistId2, newFilter)
const action = changeTodolistFilterAC(todolistId2, newFilter)
const endState = todolistsReducer(startState, action)
const endState = todolistsReducer(startState, action)
expect(endState[0].filter).toBe('all')
expect(endState[1].filter).toBe(newFilter)
expect(endState[0].filter).toBe('all')
expect(endState[1].filter).toBe(newFilter)
})
test('todolists should be added', () => {
const action = setTodolistsAC(startState)
const action = setTodolistsAC(startState)
const endState = todolistsReducer([], action)
const endState = todolistsReducer([], action)
expect(endState.length).toBe(2)
expect(endState.length).toBe(2)
})
test('correct entity status of todolist should be changed', () => {
let newStatus: RequestStatusType = 'loading'
let newStatus: RequestStatusType = 'loading'
const action = changeTodolistEntityStatusAC(todolistId2, newStatus)
const action = changeTodolistEntityStatusAC(todolistId2, newStatus)
const endState = todolistsReducer(startState, action)
const endState = todolistsReducer(startState, action)
expect(endState[0].entityStatus).toBe('idle')
expect(endState[1].entityStatus).toBe(newStatus)
expect(endState[0].entityStatus).toBe('idle')
expect(endState[1].entityStatus).toBe(newStatus)
})

View File

@@ -1,109 +1,142 @@
import {todolistsAPI, TodolistType} from '../../api/todolists-api'
import {Dispatch} from 'redux'
import {RequestStatusType, SetAppErrorActionType, setAppStatusAC, SetAppStatusActionType} from '../../app/app-reducer'
import {handleServerNetworkError} from '../../utils/error-utils'
import { AppThunk } from '../../app/store';
import { todolistsAPI, TodolistType } from '../../api/todolists-api'
import { Dispatch } from 'redux'
import {
RequestStatusType,
SetAppErrorActionType,
setAppStatusAC,
SetAppStatusActionType,
} from '../../app/app-reducer'
import { handleServerNetworkError } from '../../utils/error-utils'
import { AppThunk } from '../../app/store'
const initialState: Array<TodolistDomainType> = []
export const todolistsReducer = (state: Array<TodolistDomainType> = initialState, action: ActionsType): Array<TodolistDomainType> => {
switch (action.type) {
case 'REMOVE-TODOLIST':
return state.filter(tl => tl.id != action.id)
case 'ADD-TODOLIST':
return [{...action.todolist, filter: 'all', entityStatus: 'idle'}, ...state]
export const todolistsReducer = (
state: Array<TodolistDomainType> = initialState,
action: ActionsType
): Array<TodolistDomainType> => {
switch (action.type) {
case 'REMOVE-TODOLIST':
return state.filter((tl) => tl.id != action.id)
case 'ADD-TODOLIST':
return [
{ ...action.todolist, filter: 'all', entityStatus: 'idle' },
...state,
]
case 'CHANGE-TODOLIST-TITLE':
return state.map(tl => tl.id === action.id ? {...tl, title: action.title} : tl)
case 'CHANGE-TODOLIST-FILTER':
return state.map(tl => tl.id === action.id ? {...tl, filter: action.filter} : tl)
case 'CHANGE-TODOLIST-ENTITY-STATUS':
return state.map(tl => tl.id === action.id ? {...tl, entityStatus: action.status} : tl)
case 'SET-TODOLISTS':
return action.todolists.map(tl => ({...tl, filter: 'all', entityStatus: 'idle'}))
default:
return state
}
case 'CHANGE-TODOLIST-TITLE':
return state.map((tl) =>
tl.id === action.id ? { ...tl, title: action.title } : tl
)
case 'CHANGE-TODOLIST-FILTER':
return state.map((tl) =>
tl.id === action.id ? { ...tl, filter: action.filter } : tl
)
case 'CHANGE-TODOLIST-ENTITY-STATUS':
return state.map((tl) =>
tl.id === action.id ? { ...tl, entityStatus: action.status } : tl
)
case 'SET-TODOLISTS':
return action.todolists.map((tl) => ({
...tl,
filter: 'all',
entityStatus: 'idle',
}))
default:
return state
}
}
// actions
export const removeTodolistAC = (id: string) => ({type: 'REMOVE-TODOLIST', id} as const)
export const addTodolistAC = (todolist: TodolistType) => ({type: 'ADD-TODOLIST', todolist} as const)
export const changeTodolistTitleAC = (id: string, title: string) => ({
export const removeTodolistAC = (id: string) =>
({ type: 'REMOVE-TODOLIST', id }) as const
export const addTodolistAC = (todolist: TodolistType) =>
({ type: 'ADD-TODOLIST', todolist }) as const
export const changeTodolistTitleAC = (id: string, title: string) =>
({
type: 'CHANGE-TODOLIST-TITLE',
id,
title
} as const)
export const changeTodolistFilterAC = (id: string, filter: FilterValuesType) => ({
title,
}) as const
export const changeTodolistFilterAC = (id: string, filter: FilterValuesType) =>
({
type: 'CHANGE-TODOLIST-FILTER',
id,
filter
} as const)
export const changeTodolistEntityStatusAC = (id: string, status: RequestStatusType) => ({
type: 'CHANGE-TODOLIST-ENTITY-STATUS', id, status } as const)
export const setTodolistsAC = (todolists: Array<TodolistType>) => ({type: 'SET-TODOLISTS', todolists} as const)
filter,
}) as const
export const changeTodolistEntityStatusAC = (
id: string,
status: RequestStatusType
) =>
({
type: 'CHANGE-TODOLIST-ENTITY-STATUS',
id,
status,
}) as const
export const setTodolistsAC = (todolists: Array<TodolistType>) =>
({ type: 'SET-TODOLISTS', todolists }) as const
// thunks
export const fetchTodolistsTC = (): AppThunk => {
return (dispatch) => {
dispatch(setAppStatusAC('loading'))
todolistsAPI.getTodolists()
.then((res) => {
dispatch(setTodolistsAC(res.data))
dispatch(setAppStatusAC('succeeded'))
})
.catch(error => {
handleServerNetworkError(error, dispatch);
})
}
return (dispatch) => {
dispatch(setAppStatusAC('loading'))
todolistsAPI
.getTodolists()
.then((res) => {
dispatch(setTodolistsAC(res.data))
dispatch(setAppStatusAC('succeeded'))
})
.catch((error) => {
handleServerNetworkError(error, dispatch)
})
}
}
export const removeTodolistTC = (todolistId: string) => {
return (dispatch: ThunkDispatch) => {
//изменим глобальный статус приложения, чтобы вверху полоса побежала
dispatch(setAppStatusAC('loading'))
//изменим статус конкретного тудулиста, чтобы он мог задизеблить что надо
dispatch(changeTodolistEntityStatusAC(todolistId, 'loading'))
todolistsAPI.deleteTodolist(todolistId)
.then((res) => {
dispatch(removeTodolistAC(todolistId))
//скажем глобально приложению, что асинхронная операция завершена
dispatch(setAppStatusAC('succeeded'))
})
}
return (dispatch: ThunkDispatch) => {
//изменим глобальный статус приложения, чтобы вверху полоса побежала
dispatch(setAppStatusAC('loading'))
//изменим статус конкретного тудулиста, чтобы он мог задизеблить что надо
dispatch(changeTodolistEntityStatusAC(todolistId, 'loading'))
todolistsAPI.deleteTodolist(todolistId).then((res) => {
dispatch(removeTodolistAC(todolistId))
//скажем глобально приложению, что асинхронная операция завершена
dispatch(setAppStatusAC('succeeded'))
})
}
}
export const addTodolistTC = (title: string) => {
return (dispatch: ThunkDispatch) => {
dispatch(setAppStatusAC('loading'))
todolistsAPI.createTodolist(title)
.then((res) => {
dispatch(addTodolistAC(res.data.data.item))
dispatch(setAppStatusAC('succeeded'))
})
}
return (dispatch: ThunkDispatch) => {
dispatch(setAppStatusAC('loading'))
todolistsAPI.createTodolist(title).then((res) => {
dispatch(addTodolistAC(res.data.data.item))
dispatch(setAppStatusAC('succeeded'))
})
}
}
export const changeTodolistTitleTC = (id: string, title: string) => {
return (dispatch: Dispatch<ActionsType>) => {
todolistsAPI.updateTodolist(id, title)
.then((res) => {
dispatch(changeTodolistTitleAC(id, title))
})
}
return (dispatch: Dispatch<ActionsType>) => {
todolistsAPI.updateTodolist(id, title).then((res) => {
dispatch(changeTodolistTitleAC(id, title))
})
}
}
// types
export type AddTodolistActionType = ReturnType<typeof addTodolistAC>;
export type RemoveTodolistActionType = ReturnType<typeof removeTodolistAC>;
export type SetTodolistsActionType = ReturnType<typeof setTodolistsAC>;
export type AddTodolistActionType = ReturnType<typeof addTodolistAC>
export type RemoveTodolistActionType = ReturnType<typeof removeTodolistAC>
export type SetTodolistsActionType = ReturnType<typeof setTodolistsAC>
type ActionsType =
| RemoveTodolistActionType
| AddTodolistActionType
| ReturnType<typeof changeTodolistTitleAC>
| ReturnType<typeof changeTodolistFilterAC>
| SetTodolistsActionType
| ReturnType<typeof changeTodolistEntityStatusAC>
export type FilterValuesType = 'all' | 'active' | 'completed';
| RemoveTodolistActionType
| AddTodolistActionType
| ReturnType<typeof changeTodolistTitleAC>
| ReturnType<typeof changeTodolistFilterAC>
| SetTodolistsActionType
| ReturnType<typeof changeTodolistEntityStatusAC>
export type FilterValuesType = 'all' | 'active' | 'completed'
export type TodolistDomainType = TodolistType & {
filter: FilterValuesType
entityStatus: RequestStatusType
filter: FilterValuesType
entityStatus: RequestStatusType
}
type ThunkDispatch = Dispatch<ActionsType | SetAppStatusActionType | SetAppErrorActionType>
type ThunkDispatch = Dispatch<
ActionsType | SetAppStatusActionType | SetAppErrorActionType
>

View File

@@ -1,27 +1,31 @@
import {addTodolistAC, TodolistDomainType, todolistsReducer} from './todolists-reducer'
import {tasksReducer, TasksStateType} from './tasks-reducer'
import {TodolistType} from '../../api/todolists-api'
import {
addTodolistAC,
TodolistDomainType,
todolistsReducer,
} from './todolists-reducer'
import { tasksReducer, TasksStateType } from './tasks-reducer'
import { TodolistType } from '../../api/todolists-api'
test('ids should be equals', () => {
const startTasksState: TasksStateType = {};
const startTodolistsState: Array<TodolistDomainType> = [];
const startTasksState: TasksStateType = {}
const startTodolistsState: Array<TodolistDomainType> = []
let todolist: TodolistType = {
title: 'new todolist',
id: 'any id',
addedDate: '',
order: 0
}
let todolist: TodolistType = {
title: 'new todolist',
id: 'any id',
addedDate: '',
order: 0,
}
const action = addTodolistAC(todolist);
const action = addTodolistAC(todolist)
const endTasksState = tasksReducer(startTasksState, action)
const endTodolistsState = todolistsReducer(startTodolistsState, action)
const endTasksState = tasksReducer(startTasksState, action)
const endTodolistsState = todolistsReducer(startTodolistsState, action)
const keys = Object.keys(endTasksState);
const idFromTasks = keys[0];
const idFromTodolists = endTodolistsState[0].id;
const keys = Object.keys(endTasksState)
const idFromTasks = keys[0]
const idFromTodolists = endTodolistsState[0].id
expect(idFromTasks).toBe(action.todolist.id);
expect(idFromTodolists).toBe(action.todolist.id);
});
expect(idFromTasks).toBe(action.todolist.id)
expect(idFromTodolists).toBe(action.todolist.id)
})