mirror of
https://github.com/usatiuk/ustk-todolist.git
synced 2025-10-28 15:47:48 +01:00
animate add todo/filter selector
This commit is contained in:
40
app.js
40
app.js
@@ -3,12 +3,12 @@ const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const morgan = require('morgan');
|
||||
const cors = require('cors');
|
||||
const config = require('./config');
|
||||
const db = require('./config/db');
|
||||
const path = require('path');
|
||||
const hsts = require('hsts');
|
||||
const compression = require('compression');
|
||||
const { redirectToHTTPS } = require('express-http-to-https');
|
||||
const db = require('./config/db');
|
||||
const config = require('./config');
|
||||
|
||||
require('./models/TodoList');
|
||||
require('./models/User');
|
||||
@@ -74,22 +74,26 @@ app.use((req, res) => {
|
||||
|
||||
// handle errors
|
||||
app.use((error, req, res, next) => {
|
||||
switch (error.name) {
|
||||
case 'ValidationError':
|
||||
case 'MissingPasswordError':
|
||||
case 'BadRequest':
|
||||
case 'BadRequestError':
|
||||
res.status(400);
|
||||
break;
|
||||
case 'AuthenticationError':
|
||||
case 'UnauthorizedError':
|
||||
res.status(401);
|
||||
break;
|
||||
case 'NotFound':
|
||||
res.status(404);
|
||||
break;
|
||||
default:
|
||||
res.status(500);
|
||||
if (error.code) {
|
||||
res.status(error.code);
|
||||
} else {
|
||||
switch (error.name) {
|
||||
case 'ValidationError':
|
||||
case 'MissingPasswordError':
|
||||
case 'BadRequest':
|
||||
case 'BadRequestError':
|
||||
res.status(400);
|
||||
break;
|
||||
case 'AuthenticationError':
|
||||
case 'UnauthorizedError':
|
||||
res.status(401);
|
||||
break;
|
||||
case 'NotFound':
|
||||
res.status(404);
|
||||
break;
|
||||
default:
|
||||
res.status(500);
|
||||
}
|
||||
}
|
||||
res.json({ success: false, error });
|
||||
if (
|
||||
|
||||
@@ -4,6 +4,7 @@ class NotFoundError extends Error {
|
||||
Error.captureStackTrace(this, NotFoundError);
|
||||
this.name = 'NotFound';
|
||||
this.text = text;
|
||||
this.code = 404;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +14,7 @@ class BadRequestError extends Error {
|
||||
Error.captureStackTrace(this, NotFoundError);
|
||||
this.name = 'BadRequest';
|
||||
this.text = text;
|
||||
this.code = 400;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
146
package-lock.json
generated
146
package-lock.json
generated
@@ -1688,6 +1688,94 @@
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"concurrently": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-3.6.0.tgz",
|
||||
"integrity": "sha512-6XiIYtYzmGEccNZFkih5JOH92jLA4ulZArAYy5j1uDSdrPLB3KzdE8GW7t2fHPcg9ry2+5LP9IEYzXzxw9lFdA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.1",
|
||||
"commander": "2.6.0",
|
||||
"date-fns": "^1.23.0",
|
||||
"lodash": "^4.5.1",
|
||||
"read-pkg": "^3.0.0",
|
||||
"rx": "2.3.24",
|
||||
"spawn-command": "^0.0.2-1",
|
||||
"supports-color": "^3.2.3",
|
||||
"tree-kill": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz",
|
||||
"integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=",
|
||||
"dev": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
|
||||
"integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
|
||||
"dev": true
|
||||
},
|
||||
"load-json-file": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
|
||||
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"parse-json": "^4.0.0",
|
||||
"pify": "^3.0.0",
|
||||
"strip-bom": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"error-ex": "^1.3.1",
|
||||
"json-parse-better-errors": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"path-type": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
|
||||
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pify": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||
"dev": true
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
||||
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"load-json-file": "^4.0.0",
|
||||
"normalize-package-data": "^2.3.2",
|
||||
"path-type": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
|
||||
"integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"configstore": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz",
|
||||
@@ -1853,6 +1941,12 @@
|
||||
"whatwg-url": "^6.4.0"
|
||||
}
|
||||
},
|
||||
"date-fns": {
|
||||
"version": "1.29.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz",
|
||||
"integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
@@ -3514,14 +3608,12 @@
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -3536,20 +3628,17 @@
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@@ -3666,8 +3755,7 @@
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@@ -3679,7 +3767,6 @@
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@@ -3694,7 +3781,6 @@
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
@@ -3702,14 +3788,12 @@
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
@@ -3728,7 +3812,6 @@
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@@ -3809,8 +3892,7 @@
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -3822,7 +3904,6 @@
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -3944,7 +4025,6 @@
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
@@ -5482,6 +5562,12 @@
|
||||
"integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=",
|
||||
"dev": true
|
||||
},
|
||||
"json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
|
||||
"dev": true
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
@@ -7593,6 +7679,12 @@
|
||||
"is-promise": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"rx": {
|
||||
"version": "2.3.24",
|
||||
"resolved": "https://registry.npmjs.org/rx/-/rx-2.3.24.tgz",
|
||||
"integrity": "sha1-FPlQpCF9fjXapxu8vljv9o6ksrc=",
|
||||
"dev": true
|
||||
},
|
||||
"rx-lite": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
|
||||
@@ -8001,6 +8093,12 @@
|
||||
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
|
||||
"dev": true
|
||||
},
|
||||
"spawn-command": {
|
||||
"version": "0.0.2-1",
|
||||
"resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz",
|
||||
"integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=",
|
||||
"dev": true
|
||||
},
|
||||
"spdx-correct": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
|
||||
@@ -8527,6 +8625,12 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"tree-kill": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.0.tgz",
|
||||
"integrity": "sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg==",
|
||||
"dev": true
|
||||
},
|
||||
"trim-right": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"start": "node ./app.js",
|
||||
"debug": "cross-env NODE_ENV=development npx nodemon --inspect ./app.js",
|
||||
"test": "cross-env NODE_ENV=test jest",
|
||||
"dev": "npx concurrently \"npm run server\" \"npm run client\" ",
|
||||
"client": "cd react && npm start",
|
||||
"server": "npx cross-env NODE_ENV=development npx nodemon --inspect ./app.js",
|
||||
"test": "npx cross-env NODE_ENV=test jest",
|
||||
"heroku-postbuild": "cd react && npm install && npm run build"
|
||||
},
|
||||
"cacheDirectories": [
|
||||
@@ -38,6 +40,7 @@
|
||||
"passport-local-mongoose": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^3.6.0",
|
||||
"cross-env": "^5.2.0",
|
||||
"eslint": "^5.1.0",
|
||||
"eslint-config-airbnb-base": "^13.0.0",
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
}
|
||||
|
||||
#inputs {
|
||||
transition: 0.4s ease-in-out;
|
||||
box-shadow: 0 2px 7px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
height: 2.5rem;
|
||||
|
||||
@@ -6,7 +6,7 @@ import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import './Container.css';
|
||||
import './App.css';
|
||||
|
||||
import TodosContainer from '../containers/TodosContainer';
|
||||
import MainViewContainer from '../containers/MainViewContainer';
|
||||
import LoginForm from './user/LoginForm';
|
||||
import SignupForm from './user/SignupForm';
|
||||
|
||||
@@ -22,7 +22,7 @@ export default class App extends React.PureComponent {
|
||||
<CssBaseline />
|
||||
<Router>
|
||||
<div id="container">
|
||||
<Route exact path="/" component={TodosContainer} />
|
||||
<Route exact path="/" component={MainViewContainer} />
|
||||
<Route path="/login" component={LoginForm} />
|
||||
<Route path="/signup" component={SignupForm} />
|
||||
</div>
|
||||
|
||||
@@ -2,9 +2,9 @@ import React from 'react';
|
||||
import FilterLink from '../containers/FilterLink';
|
||||
import { VisibilityFilters } from '../actions/defs';
|
||||
|
||||
function Filters() {
|
||||
function Filters(styles) {
|
||||
return (
|
||||
<div id="filters">
|
||||
<div style={styles} id="filters">
|
||||
<FilterLink filter={VisibilityFilters.SHOW_ALL}>all</FilterLink>
|
||||
<FilterLink filter={VisibilityFilters.SHOW_ACTIVE}>active</FilterLink>
|
||||
<FilterLink filter={VisibilityFilters.SHOW_COMPLETED}>
|
||||
|
||||
@@ -3,18 +3,18 @@ import PropTypes from 'prop-types';
|
||||
import { Button } from '@material-ui/core';
|
||||
import AddIcon from '@material-ui/icons/Add';
|
||||
|
||||
function Input(props) {
|
||||
function Input({ onClick, styles }) {
|
||||
let input;
|
||||
|
||||
function submit() {
|
||||
if (input.value.trim() !== '') {
|
||||
props.onClick(input.value);
|
||||
onClick(input.value);
|
||||
}
|
||||
input.value = '';
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="inputs">
|
||||
<div style={styles} id="inputs">
|
||||
<input
|
||||
ref={node => {
|
||||
input = node;
|
||||
@@ -36,6 +36,7 @@ function Input(props) {
|
||||
}
|
||||
|
||||
Input.propTypes = {
|
||||
styles: PropTypes.any.isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
|
||||
21
react/src/components/MainView.js
Normal file
21
react/src/components/MainView.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import TodosContainer from '../containers/TodosContainer';
|
||||
|
||||
export default class MainView extends React.PureComponent {
|
||||
componentDidUpdate() {
|
||||
const { user, history } = this.props;
|
||||
if (!user.user && !user.dirty) {
|
||||
history.replace('/login');
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return <TodosContainer />;
|
||||
}
|
||||
}
|
||||
|
||||
MainView.propTypes = {
|
||||
user: PropTypes.any.isRequired,
|
||||
history: PropTypes.any.isRequired,
|
||||
};
|
||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { Select, MenuItem } from '@material-ui/core';
|
||||
import AddIcon from '@material-ui/icons/Add';
|
||||
import CheckIcon from '@material-ui/icons/Check';
|
||||
import { Spring, animated } from 'react-spring';
|
||||
import { Transition, animated } from 'react-spring';
|
||||
|
||||
import './Selector.css';
|
||||
|
||||
@@ -28,65 +28,83 @@ export default function Selector({
|
||||
if (creating) {
|
||||
let input = null;
|
||||
return (
|
||||
<div id="listselector" className="list--input">
|
||||
<input
|
||||
ref={node => {
|
||||
input = node;
|
||||
}}
|
||||
id="input"
|
||||
type="text"
|
||||
onKeyPress={e => {
|
||||
if (e.key === 'Enter') {
|
||||
addList(input.value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Spring native from={{ opacity: 0 }} to={{ opacity: 1 }}>
|
||||
{styles => (
|
||||
<Transition
|
||||
native
|
||||
from={{ opacity: 0, maxHeight: 0 }}
|
||||
enter={{ opacity: 1, maxHeight: 64 }}
|
||||
leave={{ opacity: 0, maxHeight: 0 }}
|
||||
>
|
||||
{styles => (
|
||||
<animated.div
|
||||
style={styles}
|
||||
id="listselector"
|
||||
className="list--input"
|
||||
>
|
||||
<input
|
||||
ref={node => {
|
||||
input = node;
|
||||
}}
|
||||
id="input"
|
||||
type="text"
|
||||
onKeyPress={e => {
|
||||
if (e.key === 'Enter') {
|
||||
addList(input.value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<animated.button
|
||||
style={{ ...button, ...styles }}
|
||||
onClick={() => input.value.trim() && addList(input.value)}
|
||||
>
|
||||
<AddIcon style={icon} />
|
||||
</animated.button>
|
||||
)}
|
||||
</Spring>
|
||||
</div>
|
||||
</animated.div>
|
||||
)}
|
||||
</Transition>
|
||||
);
|
||||
}
|
||||
if (editing) {
|
||||
let input = null;
|
||||
return (
|
||||
<div id="listselector" className="list--input">
|
||||
<input
|
||||
ref={node => {
|
||||
input = node;
|
||||
}}
|
||||
defaultValue={lists.lists[list].name}
|
||||
id="input"
|
||||
type="text"
|
||||
onKeyPress={e => {
|
||||
if (e.key === 'Enter') {
|
||||
editList(input.value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Spring native from={{ opacity: 0 }} to={{ opacity: 1 }}>
|
||||
{styles => (
|
||||
<Transition
|
||||
native
|
||||
from={{ opacity: 0, maxHeight: 0 }}
|
||||
enter={{ opacity: 1, maxHeight: 64 }}
|
||||
leave={{ opacity: 0, maxHeight: 0 }}
|
||||
>
|
||||
{styles => (
|
||||
<animated.div
|
||||
style={styles}
|
||||
id="listselector"
|
||||
className="list--input"
|
||||
>
|
||||
<input
|
||||
ref={node => {
|
||||
input = node;
|
||||
}}
|
||||
defaultValue={lists.lists[list].name}
|
||||
id="input"
|
||||
type="text"
|
||||
onKeyPress={e => {
|
||||
if (e.key === 'Enter') {
|
||||
editList(input.value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<animated.button
|
||||
style={{ ...button, ...styles }}
|
||||
style={{ ...button }}
|
||||
onClick={() => input.value.trim() && editList(input.value)}
|
||||
>
|
||||
<CheckIcon style={icon} />
|
||||
</animated.button>
|
||||
)}
|
||||
</Spring>
|
||||
</div>
|
||||
</animated.div>
|
||||
)}
|
||||
</Transition>
|
||||
);
|
||||
}
|
||||
if (list) {
|
||||
return (
|
||||
<div id="listselector">
|
||||
<animated.div id="listselector">
|
||||
<Select
|
||||
style={{ fontSize: '1.5rem', width: '100%' }}
|
||||
value={list}
|
||||
@@ -98,7 +116,7 @@ export default function Selector({
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
</animated.div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1,32 +1,35 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Transition } from 'react-spring';
|
||||
|
||||
import InputContainer from '../containers/InputContainer';
|
||||
import TodoListContainer from '../containers/TodoListContainer';
|
||||
import Header from './Header';
|
||||
import Filters from './Filters';
|
||||
|
||||
export default class Todos extends React.PureComponent {
|
||||
componentDidUpdate() {
|
||||
const { user, history } = this.props;
|
||||
if (!user.user && !user.dirty) {
|
||||
history.replace('/login');
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div id="todos">
|
||||
<Header />
|
||||
<InputContainer />
|
||||
<TodoListContainer />
|
||||
<Filters />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default function Todos({ list }) {
|
||||
return (
|
||||
<div id="todos">
|
||||
<Header />
|
||||
<Transition
|
||||
from={{ opacity: 0, maxHeight: 0 }}
|
||||
enter={{ opacity: 1, maxHeight: 38 }}
|
||||
leave={{ opacity: 0, maxHeight: 0 }}
|
||||
>
|
||||
{list && (styles => <InputContainer styles={styles} />)}
|
||||
</Transition>
|
||||
<TodoListContainer />
|
||||
<Transition
|
||||
from={{ opacity: 0, maxHeight: 0 }}
|
||||
enter={{ opacity: 1, maxHeight: 32 }}
|
||||
leave={{ opacity: 0, maxHeight: 0 }}
|
||||
>
|
||||
{list && Filters}
|
||||
</Transition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Todos.propTypes = {
|
||||
history: PropTypes.object.isRequired,
|
||||
user: PropTypes.object.isRequired,
|
||||
list: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
@@ -3,6 +3,10 @@ import { connect } from 'react-redux';
|
||||
import Input from '../components/Input';
|
||||
import { addTodo } from '../actions/todos';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return { ...ownProps };
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
onClick: text => dispatch(addTodo(text)),
|
||||
@@ -10,6 +14,6 @@ function mapDispatchToProps(dispatch) {
|
||||
}
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(Input);
|
||||
|
||||
12
react/src/containers/MainViewContainer.js
Normal file
12
react/src/containers/MainViewContainer.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import MainView from '../components/MainView';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
user: state.user,
|
||||
};
|
||||
}
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(MainView));
|
||||
@@ -1,12 +1,11 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import Todos from '../components/Todos';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
user: state.user,
|
||||
list: Boolean(state.lists.list),
|
||||
};
|
||||
}
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(Todos));
|
||||
export default connect(mapStateToProps)(Todos);
|
||||
|
||||
Reference in New Issue
Block a user