├── .gitattributes ├── .prettierrc ├── src ├── react-app-env.d.ts ├── routes.ts ├── setupTests.ts ├── App.test.tsx ├── redux │ ├── store.ts │ ├── initialState.ts │ ├── labels.ts │ └── todos.ts ├── reportWebVitals.ts ├── theme.ts ├── Labels │ ├── LabelsSelect.tsx │ └── LabelsPreview.tsx ├── index.tsx ├── types.ts ├── Todo │ ├── styles.ts │ └── index.tsx ├── Calendar │ ├── index.tsx │ └── happy.svg ├── NavigationMenu │ └── index.tsx ├── App.tsx └── Overview │ └── index.tsx ├── preview-1.png ├── preview-2.png ├── preview-3.png ├── preview-4.png ├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── robots.txt ├── manifest.json └── index.html ├── .editorconfig ├── .gitignore ├── tsconfig.json ├── LICENSE ├── package.json └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 256 3 | } 4 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /preview-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cozmy/todo-react-redux/HEAD/preview-1.png -------------------------------------------------------------------------------- /preview-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cozmy/todo-react-redux/HEAD/preview-2.png -------------------------------------------------------------------------------- /preview-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cozmy/todo-react-redux/HEAD/preview-3.png -------------------------------------------------------------------------------- /preview-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cozmy/todo-react-redux/HEAD/preview-4.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cozmy/todo-react-redux/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cozmy/todo-react-redux/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cozmy/todo-react-redux/HEAD/public/logo512.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/routes.ts: -------------------------------------------------------------------------------- 1 | export const routes = { 2 | overview: "/", 3 | calendar: "/calendar", 4 | label: { 5 | path: `/label/:id`, 6 | to: (label: string) => `/label/${label}`, 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import "@testing-library/jest-dom"; 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 2 10 | max_line_length = 256 11 | trim_trailing_whitespace = true 12 | -------------------------------------------------------------------------------- /src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | import React from "react"; 3 | 4 | import App from "./App"; 5 | 6 | test("renders learn react link", () => { 7 | render(); 8 | const linkElement = screen.getByText(/learn react/i); 9 | expect(linkElement).toBeInTheDocument(); 10 | }); 11 | -------------------------------------------------------------------------------- /src/redux/store.ts: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | 3 | import { labelsReducer } from "./labels"; 4 | import { todosReducer } from "./todos"; 5 | 6 | export const store = configureStore({ 7 | reducer: { 8 | labels: labelsReducer, 9 | todos: todosReducer, 10 | }, 11 | }); 12 | 13 | export type TState = ReturnType; 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | .eslintcache 26 | -------------------------------------------------------------------------------- /src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from "web-vitals"; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/theme.ts: -------------------------------------------------------------------------------- 1 | import { createMuiTheme } from "@material-ui/core"; 2 | 3 | export const theme = createMuiTheme({ 4 | palette: { 5 | type: "dark", 6 | }, 7 | props: { 8 | MuiTextField: { 9 | margin: "dense", 10 | variant: "outlined", 11 | }, 12 | MuiButton: { 13 | size: "small", 14 | variant: "outlined", 15 | }, 16 | MuiSelect: { 17 | MenuProps: { 18 | variant: "menu", 19 | getContentAnchorEl: null, 20 | anchorOrigin: { 21 | vertical: "bottom", 22 | horizontal: "center", 23 | }, 24 | transformOrigin: { 25 | vertical: "top", 26 | horizontal: "center", 27 | }, 28 | }, 29 | }, 30 | }, 31 | }); 32 | -------------------------------------------------------------------------------- /src/Labels/LabelsSelect.tsx: -------------------------------------------------------------------------------- 1 | import { MenuItem, TextField, TextFieldProps } from "@material-ui/core"; 2 | import React from "react"; 3 | import { useSelector } from "react-redux"; 4 | 5 | import { labelsSelectors } from "../redux/labels"; 6 | 7 | function LabelsSelect({ SelectProps, ...rest }: Partial) { 8 | const labels = useSelector(labelsSelectors.selectAll); 9 | 10 | return ( 11 | 12 | {labels.map((label) => ( 13 | 14 | {label.title} 15 | 16 | ))} 17 | 18 | ); 19 | } 20 | 21 | export default React.memo(LabelsSelect); 22 | -------------------------------------------------------------------------------- /src/Labels/LabelsPreview.tsx: -------------------------------------------------------------------------------- 1 | import { Chip, makeStyles } from "@material-ui/core"; 2 | import React from "react"; 3 | import { useSelector } from "react-redux"; 4 | 5 | import { labelsSelectors } from "../redux/labels"; 6 | import { TState } from "../redux/store"; 7 | import { Todo } from "../types"; 8 | 9 | export const useStyles = makeStyles((theme) => ({ 10 | label: { 11 | marginLeft: theme.spacing(1), 12 | }, 13 | })); 14 | 15 | function LabelsPreview({ value }: { value: Todo["labels"] }) { 16 | const classes = useStyles(); 17 | const labels = useSelector((state: TState) => labelsSelectors.selectByIds(state, value)); 18 | 19 | return ( 20 | <> 21 | {labels.map((label) => ( 22 | 23 | ))} 24 | 25 | ); 26 | } 27 | 28 | export default React.memo(LabelsPreview); 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Cosmin Ababei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import DateFnsUtils from "@date-io/date-fns"; 2 | import { ThemeProvider } from "@material-ui/core"; 3 | import { MuiPickersUtilsProvider } from "@material-ui/pickers"; 4 | import "fontsource-roboto"; 5 | import React from "react"; 6 | import ReactDOM from "react-dom"; 7 | import { Provider as StoreProvider } from "react-redux"; 8 | import { HashRouter } from "react-router-dom"; 9 | 10 | import App from "./App"; 11 | import { store } from "./redux/store"; 12 | import reportWebVitals from "./reportWebVitals"; 13 | import { theme } from "./theme"; 14 | 15 | ReactDOM.render( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | , 27 | document.getElementById("root"), 28 | ); 29 | 30 | // If you want to start measuring performance in your app, pass a function 31 | // to log results (for example: reportWebVitals(console.log)) 32 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 33 | reportWebVitals(); 34 | -------------------------------------------------------------------------------- /src/redux/initialState.ts: -------------------------------------------------------------------------------- 1 | import { Label, Todo, TTodoPriority } from "../types"; 2 | 3 | export const labelsInitialState: Label[] = [{ ...new Label({ id: "oYS6jCV-9_r6-gApwP-a0", title: "Work" }) }, { ...new Label({ id: "6upNOC-XWS_LKn0Cdcgc_", title: "Leisure" }) }, { ...new Label({ id: "HrlBY9eBGad8ShNV5XWry", title: "Personal" }) }]; 4 | 5 | export const todosInitialState: Todo[] = [ 6 | { ...new Todo({ description: "It is imperative", title: "Make this app work", priority: TTodoPriority.HIGH, dueDate: "2021-04-27", labels: [labelsInitialState[0].id] }) }, 7 | { ...new Todo({ description: "Maybe play some video games?", title: "Relax a bit", dueDate: "2021-04-12", labels: [labelsInitialState[1].id] }) }, 8 | { ...new Todo({ title: "Have some fun" }) }, 9 | { ...new Todo({ title: "Workout!", priority: TTodoPriority.MEDIUM, labels: [labelsInitialState[2].id] }) }, 10 | { ...new Todo({ title: "Do the laundry", dueDate: "2021-04-16" }) }, 11 | { ...new Todo({ description: "Just a bit", title: "Try to document it", priority: TTodoPriority.LOW, dueDate: "2021-04-16", labels: [labelsInitialState[0].id, labelsInitialState[1].id] }) }, 12 | { ...new Todo({ description: "Hello!", title: "Publish this on GitHub", completionDate: "2021-04-09T18:28:39.266Z" }) }, 13 | ]; 14 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from "@reduxjs/toolkit"; 2 | 3 | export class Label { 4 | id: string; 5 | title: string; 6 | 7 | // TODO add a `color?: string;` property 8 | 9 | constructor({ id = undefined, title = "" }: Partial