[
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nfirebase-debug.log*\n.firebaserc\n\n# Firebase cache\n.firebase/\n\n# Firebase config\n\n# Uncomment this if you'd like others to create their own Firebase project.\n# For a team working on the same Firebase project(s), it is recommended to leave\n# it commented so all members can deploy to the same project(s) in .firebaserc.\n# .firebaserc\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\nfunctions/package-lock.json\nfunctions/util/config.js\nfunctions/package-lock.json\nfunctions/package-lock.json\nfunctions/package-lock.json\n"
  },
  {
    "path": "README.md",
    "content": "# Todo Application using ReactJS and Firebase\n\n-----\n\n### Account creation:\n\n![Account](doc/images/Account.gif)\n\n### Todo Dashboard:\n\n![Account](doc/images/Todo.gif)\n\n\n### Application Architecture:\n\n![Application Architecture](doc/images/TodoApp.png)\n\n### Components used in the Application:\n\n1. ReactJS\n2. Material UI\n3. Firebase Firestore, Functions and Authentication\n4. ExpressJS\n5. Postman."
  },
  {
    "path": "firebase.json",
    "content": "{}\n"
  },
  {
    "path": "functions/.gitignore",
    "content": "node_modules/"
  },
  {
    "path": "functions/APIs/todos.js",
    "content": "const { db } = require('../util/admin');\n\nexports.getAllTodos = (request, response) => {\n\tdb\n        .collection('todos')\n        .where('username', '==', request.user.username)\n\t\t.orderBy('createdAt', 'desc')\n\t\t.get()\n\t\t.then((data) => {\n\t\t\tlet todos = [];\n\t\t\tdata.forEach((doc) => {\n\t\t\t\ttodos.push({\n                    todoId: doc.id,\n                    title: doc.data().title,\n                    username: doc.data().username,\n\t\t\t\t\tbody: doc.data().body,\n\t\t\t\t\tcreatedAt: doc.data().createdAt,\n\t\t\t\t});\n\t\t\t});\n\t\t\treturn response.json(todos);\n\t\t})\n\t\t.catch((err) => {\n\t\t\tconsole.error(err);\n\t\t\treturn response.status(500).json({ error: err.code});\n\t\t});\n};\n\nexports.getOneTodo = (request, response) => {\n\tdb\n        .doc(`/todos/${request.params.todoId}`)\n\t\t.get()\n\t\t.then((doc) => {\n\t\t\tif (!doc.exists) {\n\t\t\t\treturn response.status(404).json(\n                    { \n                        error: 'Todo not found' \n                    });\n            }\n            if(doc.data().username !== request.user.username){\n                return response.status(403).json({error:\"UnAuthorized\"})\n            }\n\t\t\tTodoData = doc.data();\n\t\t\tTodoData.todoId = doc.id;\n\t\t\treturn response.json(TodoData);\n\t\t})\n\t\t.catch((err) => {\n\t\t\tconsole.error(err);\n\t\t\treturn response.status(500).json({ error: error.code });\n\t\t});\n};\n\nexports.postOneTodo = (request, response) => {\n\tif (request.body.body.trim() === '') {\n\t\treturn response.status(400).json({ body: 'Must not be empty' });\n    }\n    \n    if(request.body.title.trim() === '') {\n        return response.status(400).json({ title: 'Must not be empty' });\n    }\n    \n    const newTodoItem = {\n        title: request.body.title,\n        username: request.user.username,\n        body: request.body.body,\n        createdAt: new Date().toISOString()\n    }\n\n    db\n        .collection('todos')\n        .add(newTodoItem)\n        .then((doc)=>{\n            const responseTodoItem = newTodoItem;\n            responseTodoItem.id = doc.id;\n            return response.json(responseTodoItem);\n        })\n        .catch((error) => {\n            console.error(error);\n\t\t\tresponse.status(500).json({ error: 'Something went wrong' });\n\t\t});\n};\n\nexports.deleteTodo = (request, response) => {\n    const document = db.doc(`/todos/${request.params.todoId}`);\n    document\n        .get()\n        .then((doc) => {\n            if (!doc.exists) {\n                return response.status(404).json({ \n                    error: 'Todo not found' \n            })}\n            if(doc.data().username !== request.user.username){\n                return response.status(403).json({error:\"UnAuthorized\"})\n            }\n            return document.delete();\n        })\n        .then(() => {\n            response.json({ message: 'Delete successfull' });\n        })\n        .catch((err) => {\n            console.error(err);\n            return response.status(500).json({ \n                error: err.code \n            });\n        });\n};\n\nexports.editTodo = ( request, response ) => { \n    if(request.body.todoId || request.body.createdAt){\n        response.status(403).json({message: 'Not allowed to edit'});\n    }\n    let document = db.collection('todos').doc(`${request.params.todoId}`);\n    document.update(request.body)\n    .then((doc)=> {\n        response.json({message: 'Updated successfully'});\n    })\n    .catch((error) => {\n        if(error.code === 5){\n            response.status(404).json({message: 'Not Found'});\n        }\n        console.error(error);\n        return response.status(500).json({ \n                error: error.code \n        });\n    });\n};"
  },
  {
    "path": "functions/APIs/users.js",
    "content": "const { admin, db } = require('../util/admin');\nconst config = require('../util/config');\n\nconst firebase = require('firebase');\n\nfirebase.initializeApp(config);\n\nconst { validateLoginData, validateSignUpData } = require('../util/validators');\n\n// Login\nexports.loginUser = (request, response) => {\n    const user = {\n        email: request.body.email,\n        password: request.body.password\n    }\n\n    const { valid, errors } = validateLoginData(user);\n\tif (!valid) return response.status(400).json(errors);\n\n    firebase\n        .auth()\n        .signInWithEmailAndPassword(user.email, user.password)\n        .then((data) => {\n            return data.user.getIdToken();\n        })\n        .then((token) => {\n            return response.json({ token });\n        })\n        .catch((error) => {\n            console.error(error);\n            return response.status(403).json(\n                { \n                    general: 'wrong credentials, please try again' \n                }\n            );\n        })\n};\n\n// Sign up\nexports.signUpUser = (request, response) => {\n    const newUser = {\n        firstName: request.body.firstName,\n        lastName: request.body.lastName,\n        email: request.body.email,\n        phoneNumber: request.body.phoneNumber,\n        country: request.body.country,\n\t\tpassword: request.body.password,\n\t\tconfirmPassword: request.body.confirmPassword,\n\t\tusername: request.body.username\n    };\n\n    const { valid, errors } = validateSignUpData(newUser);\n\n\tif (!valid) return response.status(400).json(errors);\n\n    let token, userId;\n    db\n        .doc(`/users/${newUser.username}`)\n        .get()\n        .then((doc) => {\n            if (doc.exists) {\n                return response.status(400).json({ username: 'this username is already taken' });\n            } else {\n                return firebase\n                        .auth()\n                        .createUserWithEmailAndPassword(\n                            newUser.email, \n                            newUser.password\n                    );\n            }\n        })\n        .then((data) => {\n            userId = data.user.uid;\n            return data.user.getIdToken();\n        })\n        .then((idtoken) => {\n            token = idtoken;\n            const userCredentials = {\n                firstName: newUser.firstName,\n                lastName: newUser.lastName,\n                username: newUser.username,\n                phoneNumber: newUser.phoneNumber,\n                country: newUser.country,\n                email: newUser.email,\n                createdAt: new Date().toISOString(),\n                userId\n            };\n            return db\n                    .doc(`/users/${newUser.username}`)\n                    .set(userCredentials);\n        })\n        .then(()=>{\n            return response.status(201).json({ token });\n        })\n        .catch((err) => {\n\t\t\tconsole.error(err);\n\t\t\tif (err.code === 'auth/email-already-in-use') {\n\t\t\t\treturn response.status(400).json({ email: 'Email already in use' });\n\t\t\t} else {\n\t\t\t\treturn response.status(500).json({ general: 'Something went wrong, please try again' });\n\t\t\t}\n\t\t});\n}\n\ndeleteImage = (imageName) => {\n    const bucket = admin.storage().bucket();\n    const path = `${imageName}`\n    return bucket.file(path).delete()\n    .then(() => {\n        return\n    })\n    .catch((error) => {\n        return\n    })\n}\n\n// Upload profile picture\nexports.uploadProfilePhoto = (request, response) => {\n    const BusBoy = require('busboy');\n\tconst path = require('path');\n\tconst os = require('os');\n\tconst fs = require('fs');\n\tconst busboy = new BusBoy({ headers: request.headers });\n\n\tlet imageFileName;\n\tlet imageToBeUploaded = {};\n\n\tbusboy.on('file', (fieldname, file, filename, encoding, mimetype) => {\n\t\tif (mimetype !== 'image/png' && mimetype !== 'image/jpeg') {\n\t\t\treturn response.status(400).json({ error: 'Wrong file type submited' });\n\t\t}\n\t\tconst imageExtension = filename.split('.')[filename.split('.').length - 1];\n        imageFileName = `${request.user.username}.${imageExtension}`;\n\t\tconst filePath = path.join(os.tmpdir(), imageFileName);\n\t\timageToBeUploaded = { filePath, mimetype };\n\t\tfile.pipe(fs.createWriteStream(filePath));\n    });\n    deleteImage(imageFileName);\n\tbusboy.on('finish', () => {\n\t\tadmin\n\t\t\t.storage()\n\t\t\t.bucket()\n\t\t\t.upload(imageToBeUploaded.filePath, {\n\t\t\t\tresumable: false,\n\t\t\t\tmetadata: {\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tcontentType: imageToBeUploaded.mimetype\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t\t.then(() => {\n\t\t\t\tconst imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`;\n\t\t\t\treturn db.doc(`/users/${request.user.username}`).update({\n\t\t\t\t\timageUrl\n\t\t\t\t});\n\t\t\t})\n\t\t\t.then(() => {\n\t\t\t\treturn response.json({ message: 'Image uploaded successfully' });\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tconsole.error(error);\n\t\t\t\treturn response.status(500).json({ error: error.code });\n\t\t\t});\n\t});\n\tbusboy.end(request.rawBody);\n};\n\nexports.getUserDetail = (request, response) => {\n    let userData = {};\n\tdb\n\t\t.doc(`/users/${request.user.username}`)\n\t\t.get()\n\t\t.then((doc) => {\n\t\t\tif (doc.exists) {\n                userData.userCredentials = doc.data();\n                return response.json(userData);\n\t\t\t}\t\n\t\t})\n\t\t.catch((error) => {\n\t\t\tconsole.error(error);\n\t\t\treturn response.status(500).json({ error: error.code });\n\t\t});\n}\n\nexports.updateUserDetails = (request, response) => {\n    let document = db.collection('users').doc(`${request.user.username}`);\n    document.update(request.body)\n    .then(()=> {\n        response.json({message: 'Updated successfully'});\n    })\n    .catch((error) => {\n        console.error(error);\n        return response.status(500).json({ \n            message: \"Cannot Update the value\"\n        });\n    });\n}"
  },
  {
    "path": "functions/index.js",
    "content": "const functions = require('firebase-functions');\nconst app = require('express')();\nconst auth = require('./util/auth');\n \nconst {\n    getAllTodos,\n    getOneTodo,\n    postOneTodo,\n    deleteTodo,\n    editTodo\n} = require('./APIs/todos')\n\nconst { \n    loginUser,\n    signUpUser,\n    uploadProfilePhoto,\n    getUserDetail,\n    updateUserDetails\n} = require('./APIs/users')\n\n// Todos\napp.get('/todos', auth, getAllTodos);\napp.get('/todo/:todoId', auth, getOneTodo);\napp.post('/todo',auth, postOneTodo);\napp.delete('/todo/:todoId',auth, deleteTodo);\napp.put('/todo/:todoId',auth, editTodo);\n\n// Users\napp.post('/login', loginUser);\napp.post('/signup', signUpUser);\napp.post('/user/image', auth ,uploadProfilePhoto);\napp.post('/user', auth ,updateUserDetails);\napp.get('/user', auth, getUserDetail);\n\nexports.api = functions.https.onRequest(app);"
  },
  {
    "path": "functions/package.json",
    "content": "{\n  \"name\": \"functions\",\n  \"description\": \"Cloud Functions for Firebase\",\n  \"scripts\": {\n    \"serve\": \"firebase emulators:start --only functions\",\n    \"shell\": \"firebase functions:shell\",\n    \"start\": \"npm run shell\",\n    \"deploy\": \"firebase deploy --only functions\",\n    \"logs\": \"firebase functions:log\"\n  },\n  \"engines\": {\n    \"node\": \"8\"\n  },\n  \"dependencies\": {\n    \"busboy\": \"^0.3.1\",\n    \"express\": \"^4.17.1\",\n    \"firebase\": \"^7.13.1\",\n    \"firebase-admin\": \"^8.10.0\",\n    \"firebase-functions\": \"^3.3.0\"\n  },\n  \"devDependencies\": {\n    \"firebase-functions-test\": \"^0.1.6\"\n  },\n  \"private\": true\n}\n"
  },
  {
    "path": "functions/util/admin.js",
    "content": "const admin = require('firebase-admin');\n\nadmin.initializeApp();\n\nconst db = admin.firestore();\n\nmodule.exports = { admin, db };"
  },
  {
    "path": "functions/util/auth.js",
    "content": "const { admin, db } = require('./admin');\n\nmodule.exports = (request, response, next) => {\n\tlet idToken;\n\tif (request.headers.authorization && request.headers.authorization.startsWith('Bearer ')) {\n\t\tidToken = request.headers.authorization.split('Bearer ')[1];\n\t} else {\n\t\tconsole.error('No token found');\n\t\treturn response.status(403).json({ error: 'Unauthorized' });\n\t}\n\tadmin\n\t\t.auth()\n\t\t.verifyIdToken(idToken)\n\t\t.then((decodedToken) => {\n\t\t\trequest.user = decodedToken;\n\t\t\treturn db.collection('users').where('userId', '==', request.user.uid).limit(1).get();\n\t\t})\n\t\t.then((data) => {\n\t\t\trequest.user.username = data.docs[0].data().username;\n\t\t\trequest.user.imageUrl = data.docs[0].data().imageUrl;\n\t\t\treturn next();\n\t\t})\n\t\t.catch((err) => {\n\t\t\tconsole.error('Error while verifying token', err);\n\t\t\treturn response.status(403).json(err);\n\t\t});\n};\n"
  },
  {
    "path": "functions/util/validators.js",
    "content": "const isEmpty = (string) => {\n\tif (string.trim() === '') return true;\n\telse return false;\n};\n\nexports.validateLoginData = (data) => {\n\tlet errors = {};\n\n\tif (isEmpty(data.email)) errors.email = 'Must not be empty';\n\tif (isEmpty(data.password)) errors.password = 'Must not be empty';\n\n\treturn {\n\t\terrors,\n\t\tvalid: Object.keys(errors).length === 0 ? true : false\n\t};\n};\n\nconst isEmail = (email) => {\n\tconst emailRegEx = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n\tif (email.match(emailRegEx)) return true;\n\telse return false;\n};\n\nexports.validateSignUpData = (data) => {\n\tlet errors = {};\n\n\tif (isEmpty(data.email)) {\n\t\terrors.email = 'Must not be empty';\n\t} else if (!isEmail(data.email)) {\n\t\terrors.email = 'Must be valid email address';\n\t}\n\n\tif (isEmpty(data.firstName)) errors.firstName = 'Must not be empty';\n\tif (isEmpty(data.lastName)) errors.lastName = 'Must not be empty';\n\tif (isEmpty(data.phoneNumber)) errors.phoneNumber = 'Must not be empty';\n\tif (isEmpty(data.country)) errors.country = 'Must not be empty';\n\n\tif (isEmpty(data.password)) errors.password = 'Must not be empty';\n\tif (data.password !== data.confirmPassword) errors.confirmPassword = 'Passowrds must be the same';\n\tif (isEmpty(data.username)) errors.username = 'Must not be empty';\n\n\treturn {\n\t\terrors,\n\t\tvalid: Object.keys(errors).length === 0 ? true : false\n\t};\n};"
  },
  {
    "path": "view/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "view/README.md",
    "content": ""
  },
  {
    "path": "view/package.json",
    "content": "{\n  \"name\": \"view\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@material-ui/core\": \"^4.9.8\",\n    \"@testing-library/jest-dom\": \"^4.2.4\",\n    \"@testing-library/react\": \"^9.5.0\",\n    \"@testing-library/user-event\": \"^7.2.1\",\n    \"dayjs\": \"^1.8.23\",\n    \"react\": \"^16.13.1\",\n    \"react-dom\": \"^16.13.1\",\n    \"react-scripts\": \"3.4.1\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"eslintConfig\": {\n    \"extends\": \"react-app\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"proxy\": \"https://us-central1-todoapp-655c1.cloudfunctions.net/api\"\n}\n"
  },
  {
    "path": "view/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <meta\n      name=\"description\"\n      content=\"Web site created using create-react-app\"\n    />\n\n    <!--\n      manifest.json provides metadata used when your web app is installed on a\n      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <title>React App</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "view/public/manifest.json",
    "content": "{\n  \"short_name\": \"React App\",\n  \"name\": \"Create React App Sample\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    },\n    {\n      \"src\": \"logo192.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"192x192\"\n    },\n    {\n      \"src\": \"logo512.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"512x512\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "view/public/robots.txt",
    "content": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n"
  },
  {
    "path": "view/src/App.css",
    "content": "html,\nbody {\n    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n    sans-serif;\n    background-color: rgb(245, 245,245);\n}"
  },
  {
    "path": "view/src/App.js",
    "content": "import React from 'react';\nimport { BrowserRouter as Router, Route, Switch } from 'react-router-dom';\nimport { ThemeProvider as MuiThemeProvider } from '@material-ui/core/styles';\nimport createMuiTheme from '@material-ui/core/styles/createMuiTheme';\nimport login from './pages/login';\nimport signup from './pages/signup';\nimport home from './pages/home';\n\nconst theme = createMuiTheme({\n\tpalette: {\n\t\tprimary: {\n\t\t\tlight: '#33c9dc',\n\t\t\tmain: '#FF5722',\n\t\t\tdark: '#d50000',\n\t\t\tcontrastText: '#fff'\n\t\t}\n  }\n});\n\nfunction App() {\n\treturn (\n\t\t<MuiThemeProvider theme={theme}>\n\t\t\t<Router>\n\t\t\t\t<div>\n\t\t\t\t\t<Switch>\n\t\t\t\t\t\t<Route exact path=\"/\" component={home} />\n\t\t\t\t\t\t<Route exact path=\"/login\" component={login} />\n\t\t\t\t\t\t<Route exact path=\"/signup\" component={signup} />\n\t\t\t\t\t</Switch>\n\t\t\t\t</div>\n\t\t\t</Router>\n\t\t</MuiThemeProvider>\n\t);\n}\n\nexport default App;\n"
  },
  {
    "path": "view/src/App.test.js",
    "content": "import React from 'react';\nimport { render } from '@testing-library/react';\nimport App from './App';\n\ntest('renders learn react link', () => {\n  const { getByText } = render(<App />);\n  const linkElement = getByText(/learn react/i);\n  expect(linkElement).toBeInTheDocument();\n});\n"
  },
  {
    "path": "view/src/components/account.js",
    "content": "import React, { Component } from 'react';\n\nimport withStyles from '@material-ui/core/styles/withStyles';\nimport Typography from '@material-ui/core/Typography';\nimport CircularProgress from '@material-ui/core/CircularProgress';\nimport CloudUploadIcon from '@material-ui/icons/CloudUpload';\nimport { Card, CardActions, CardContent, Divider, Button, Grid, TextField } from '@material-ui/core';\n\nimport clsx from 'clsx';\n\nimport axios from 'axios';\nimport { authMiddleWare } from '../util/auth';\n\nconst styles = (theme) => ({\n\tcontent: {\n\t\tflexGrow: 1,\n\t\tpadding: theme.spacing(3)\n\t},\n\ttoolbar: theme.mixins.toolbar,\n\troot: {},\n\tdetails: {\n\t\tdisplay: 'flex'\n\t},\n\tavatar: {\n\t\theight: 110,\n\t\twidth: 100,\n\t\tflexShrink: 0,\n\t\tflexGrow: 0\n\t},\n\tlocationText: {\n\t\tpaddingLeft: '15px'\n\t},\n\tbuttonProperty: {\n\t\tposition: 'absolute',\n\t\ttop: '50%'\n\t},\n\tuiProgess: {\n\t\tposition: 'fixed',\n\t\tzIndex: '1000',\n\t\theight: '31px',\n\t\twidth: '31px',\n\t\tleft: '50%',\n\t\ttop: '35%'\n\t},\n\tprogess: {\n\t\tposition: 'absolute'\n\t},\n\tuploadButton: {\n\t\tmarginLeft: '8px',\n\t\tmargin: theme.spacing(1)\n\t},\n\tcustomError: {\n\t\tcolor: 'red',\n\t\tfontSize: '0.8rem',\n\t\tmarginTop: 10\n\t},\n\tsubmitButton: {\n\t\tmarginTop: '10px'\n\t}\n});\n\nclass account extends Component {\n\tconstructor(props) {\n\t\tsuper(props);\n\n\t\tthis.state = {\n\t\t\tfirstName: '',\n\t\t\tlastName: '',\n\t\t\temail: '',\n\t\t\tphoneNumber: '',\n\t\t\tusername: '',\n\t\t\tcountry: '',\n\t\t\tprofilePicture: '',\n\t\t\tuiLoading: true,\n\t\t\tbuttonLoading: false,\n\t\t\timageError: ''\n\t\t};\n\t}\n\n\tcomponentWillMount = () => {\n\t\tauthMiddleWare(this.props.history);\n\t\tconst authToken = localStorage.getItem('AuthToken');\n\t\taxios.defaults.headers.common = { Authorization: `${authToken}` };\n\t\taxios\n\t\t\t.get('/user')\n\t\t\t.then((response) => {\n\t\t\t\tconsole.log(response.data);\n\t\t\t\tthis.setState({\n\t\t\t\t\tfirstName: response.data.userCredentials.firstName,\n\t\t\t\t\tlastName: response.data.userCredentials.lastName,\n\t\t\t\t\temail: response.data.userCredentials.email,\n\t\t\t\t\tphoneNumber: response.data.userCredentials.phoneNumber,\n\t\t\t\t\tcountry: response.data.userCredentials.country,\n\t\t\t\t\tusername: response.data.userCredentials.username,\n\t\t\t\t\tuiLoading: false\n\t\t\t\t});\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tif (error.response.status === 403) {\n\t\t\t\t\tthis.props.history.push('/login');\n\t\t\t\t}\n\t\t\t\tconsole.log(error);\n\t\t\t\tthis.setState({ errorMsg: 'Error in retrieving the data' });\n\t\t\t});\n\t};\n\n\thandleChange = (event) => {\n\t\tthis.setState({\n\t\t\t[event.target.name]: event.target.value\n\t\t});\n\t};\n\n\thandleImageChange = (event) => {\n\t\tthis.setState({\n\t\t\timage: event.target.files[0]\n\t\t});\n\t};\n\n\tprofilePictureHandler = (event) => {\n\t\tevent.preventDefault();\n\t\tthis.setState({\n\t\t\tuiLoading: true\n\t\t});\n\t\tauthMiddleWare(this.props.history);\n\t\tconst authToken = localStorage.getItem('AuthToken');\n\t\tlet form_data = new FormData();\n\t\tform_data.append('image', this.state.image);\n\t\tform_data.append('content', this.state.content);\n\t\taxios.defaults.headers.common = { Authorization: `${authToken}` };\n\t\taxios\n\t\t\t.post('/user/image', form_data, {\n\t\t\t\theaders: {\n\t\t\t\t\t'content-type': 'multipart/form-data'\n\t\t\t\t}\n\t\t\t})\n\t\t\t.then(() => {\n\t\t\t\twindow.location.reload();\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tif (error.response.status === 403) {\n\t\t\t\t\tthis.props.history.push('/login');\n\t\t\t\t}\n\t\t\t\tconsole.log(error);\n\t\t\t\tthis.setState({\n\t\t\t\t\tuiLoading: false,\n\t\t\t\t\timageError: 'Error in posting the data'\n\t\t\t\t});\n\t\t\t});\n\t};\n\n\tupdateFormValues = (event) => {\n\t\tevent.preventDefault();\n\t\tthis.setState({ buttonLoading: true });\n\t\tauthMiddleWare(this.props.history);\n\t\tconst authToken = localStorage.getItem('AuthToken');\n\t\taxios.defaults.headers.common = { Authorization: `${authToken}` };\n\t\tconst formRequest = {\n\t\t\tfirstName: this.state.firstName,\n\t\t\tlastName: this.state.lastName,\n\t\t\tcountry: this.state.country\n\t\t};\n\t\taxios\n\t\t\t.post('/user', formRequest)\n\t\t\t.then(() => {\n\t\t\t\tthis.setState({ buttonLoading: false });\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tif (error.response.status === 403) {\n\t\t\t\t\tthis.props.history.push('/login');\n\t\t\t\t}\n\t\t\t\tconsole.log(error);\n\t\t\t\tthis.setState({\n\t\t\t\t\tbuttonLoading: false\n\t\t\t\t});\n\t\t\t});\n\t};\n\n\trender() {\n\t\tconst { classes, ...rest } = this.props;\n\t\tif (this.state.uiLoading === true) {\n\t\t\treturn (\n\t\t\t\t<main className={classes.content}>\n\t\t\t\t\t<div className={classes.toolbar} />\n\t\t\t\t\t{this.state.uiLoading && <CircularProgress size={150} className={classes.uiProgess} />}\n\t\t\t\t</main>\n\t\t\t);\n\t\t} else {\n\t\t\treturn (\n\t\t\t\t<main className={classes.content}>\n\t\t\t\t\t<div className={classes.toolbar} />\n\t\t\t\t\t<Card {...rest} className={clsx(classes.root, classes)}>\n\t\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t\t<div className={classes.details}>\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<Typography className={classes.locationText} gutterBottom variant=\"h4\">\n\t\t\t\t\t\t\t\t\t\t{this.state.firstName} {this.state.lastName}\n\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\tstartIcon={<CloudUploadIcon />}\n\t\t\t\t\t\t\t\t\t\tclassName={classes.uploadButton}\n\t\t\t\t\t\t\t\t\t\tonClick={this.profilePictureHandler}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tUpload Photo\n\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t<input type=\"file\" onChange={this.handleImageChange} />\n\n\t\t\t\t\t\t\t\t\t{this.state.imageError ? (\n\t\t\t\t\t\t\t\t\t\t<div className={classes.customError}>\n\t\t\t\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t\t\t\tWrong Image Format || Supported Format are PNG and JPG\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\tfalse\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className={classes.progress} />\n\t\t\t\t\t\t</CardContent>\n\t\t\t\t\t\t<Divider />\n\t\t\t\t\t</Card>\n\n\t\t\t\t\t<br />\n\t\t\t\t\t<Card {...rest} className={clsx(classes.root, classes)}>\n\t\t\t\t\t\t<form autoComplete=\"off\" noValidate>\n\t\t\t\t\t\t\t<Divider />\n\t\t\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t\t\t<Grid container spacing={3}>\n\t\t\t\t\t\t\t\t\t<Grid item md={6} xs={12}>\n\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\t\tlabel=\"First name\"\n\t\t\t\t\t\t\t\t\t\t\tmargin=\"dense\"\n\t\t\t\t\t\t\t\t\t\t\tname=\"firstName\"\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\t\t\tvalue={this.state.firstName}\n\t\t\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t\t<Grid item md={6} xs={12}>\n\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\t\tlabel=\"Last name\"\n\t\t\t\t\t\t\t\t\t\t\tmargin=\"dense\"\n\t\t\t\t\t\t\t\t\t\t\tname=\"lastName\"\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\t\t\tvalue={this.state.lastName}\n\t\t\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t\t<Grid item md={6} xs={12}>\n\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\t\tlabel=\"Email\"\n\t\t\t\t\t\t\t\t\t\t\tmargin=\"dense\"\n\t\t\t\t\t\t\t\t\t\t\tname=\"email\"\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={true}\n\t\t\t\t\t\t\t\t\t\t\tvalue={this.state.email}\n\t\t\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t\t<Grid item md={6} xs={12}>\n\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\t\tlabel=\"Phone Number\"\n\t\t\t\t\t\t\t\t\t\t\tmargin=\"dense\"\n\t\t\t\t\t\t\t\t\t\t\tname=\"phone\"\n\t\t\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={true}\n\t\t\t\t\t\t\t\t\t\t\tvalue={this.state.phoneNumber}\n\t\t\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t\t<Grid item md={6} xs={12}>\n\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\t\tlabel=\"User Name\"\n\t\t\t\t\t\t\t\t\t\t\tmargin=\"dense\"\n\t\t\t\t\t\t\t\t\t\t\tname=\"userHandle\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={true}\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\t\t\tvalue={this.state.username}\n\t\t\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t\t<Grid item md={6} xs={12}>\n\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\t\tlabel=\"Country\"\n\t\t\t\t\t\t\t\t\t\t\tmargin=\"dense\"\n\t\t\t\t\t\t\t\t\t\t\tname=\"country\"\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\t\t\tvalue={this.state.country}\n\t\t\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t</CardContent>\n\t\t\t\t\t\t\t<Divider />\n\t\t\t\t\t\t\t<CardActions />\n\t\t\t\t\t\t</form>\n\t\t\t\t\t</Card>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tclassName={classes.submitButton}\n\t\t\t\t\t\tonClick={this.updateFormValues}\n\t\t\t\t\t\tdisabled={\n\t\t\t\t\t\t\tthis.state.buttonLoading ||\n\t\t\t\t\t\t\t!this.state.firstName ||\n\t\t\t\t\t\t\t!this.state.lastName ||\n\t\t\t\t\t\t\t!this.state.country\n\t\t\t\t\t\t}\n\t\t\t\t\t>\n\t\t\t\t\t\tSave details\n\t\t\t\t\t\t{this.state.buttonLoading && <CircularProgress size={30} className={classes.progess} />}\n\t\t\t\t\t</Button>\n\t\t\t\t</main>\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport default withStyles(styles)(account);\n"
  },
  {
    "path": "view/src/components/todo.js",
    "content": "import React, { Component } from 'react';\n\nimport withStyles from '@material-ui/core/styles/withStyles';\nimport Typography from '@material-ui/core/Typography';\nimport Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport AddCircleIcon from '@material-ui/icons/AddCircle';\nimport AppBar from '@material-ui/core/AppBar';\nimport Toolbar from '@material-ui/core/Toolbar';\nimport IconButton from '@material-ui/core/IconButton';\nimport CloseIcon from '@material-ui/icons/Close';\nimport Slide from '@material-ui/core/Slide';\nimport TextField from '@material-ui/core/TextField';\nimport Grid from '@material-ui/core/Grid';\nimport Card from '@material-ui/core/Card';\nimport CardActions from '@material-ui/core/CardActions';\nimport CircularProgress from '@material-ui/core/CircularProgress';\nimport CardContent from '@material-ui/core/CardContent';\nimport MuiDialogTitle from '@material-ui/core/DialogTitle';\nimport MuiDialogContent from '@material-ui/core/DialogContent';\n\nimport axios from 'axios';\nimport dayjs from 'dayjs';\nimport relativeTime from 'dayjs/plugin/relativeTime';\nimport { authMiddleWare } from '../util/auth';\n\nconst styles = (theme) => ({\n\tcontent: {\n\t\tflexGrow: 1,\n\t\tpadding: theme.spacing(3)\n\t},\n\tappBar: {\n\t\tposition: 'relative'\n\t},\n\ttitle: {\n\t\tmarginLeft: theme.spacing(2),\n\t\tflex: 1\n\t},\n\tsubmitButton: {\n\t\tdisplay: 'block',\n\t\tcolor: 'white',\n\t\ttextAlign: 'center',\n\t\tposition: 'absolute',\n\t\ttop: 14,\n\t\tright: 10\n\t},\n\tfloatingButton: {\n\t\tposition: 'fixed',\n\t\tbottom: 0,\n\t\tright: 0\n\t},\n\tform: {\n\t\twidth: '98%',\n\t\tmarginLeft: 13,\n\t\tmarginTop: theme.spacing(3)\n\t},\n\ttoolbar: theme.mixins.toolbar,\n\troot: {\n\t\tminWidth: 470\n\t},\n\tbullet: {\n\t\tdisplay: 'inline-block',\n\t\tmargin: '0 2px',\n\t\ttransform: 'scale(0.8)'\n\t},\n\tpos: {\n\t\tmarginBottom: 12\n\t},\n\tuiProgess: {\n\t\tposition: 'fixed',\n\t\tzIndex: '1000',\n\t\theight: '31px',\n\t\twidth: '31px',\n\t\tleft: '50%',\n\t\ttop: '35%'\n\t},\n\tdialogeStyle: {\n\t\tmaxWidth: '50%'\n\t},\n\tviewRoot: {\n\t\tmargin: 0,\n\t\tpadding: theme.spacing(2)\n\t},\n\tcloseButton: {\n\t\tposition: 'absolute',\n\t\tright: theme.spacing(1),\n\t\ttop: theme.spacing(1),\n\t\tcolor: theme.palette.grey[500]\n\t}\n});\n\nconst Transition = React.forwardRef(function Transition(props, ref) {\n\treturn <Slide direction=\"up\" ref={ref} {...props} />;\n});\n\nclass todo extends Component {\n\tconstructor(props) {\n\t\tsuper(props);\n\n\t\tthis.state = {\n\t\t\ttodos: '',\n\t\t\ttitle: '',\n\t\t\tbody: '',\n\t\t\ttodoId: '',\n\t\t\terrors: [],\n\t\t\topen: false,\n\t\t\tuiLoading: true,\n\t\t\tbuttonType: '',\n\t\t\tviewOpen: false\n\t\t};\n\n\t\tthis.deleteTodoHandler = this.deleteTodoHandler.bind(this);\n\t\tthis.handleEditClickOpen = this.handleEditClickOpen.bind(this);\n\t\tthis.handleViewOpen = this.handleViewOpen.bind(this);\n\t}\n\n\thandleChange = (event) => {\n\t\tthis.setState({\n\t\t\t[event.target.name]: event.target.value\n\t\t});\n\t};\n\n\tcomponentWillMount = () => {\n\t\tauthMiddleWare(this.props.history);\n\t\tconst authToken = localStorage.getItem('AuthToken');\n\t\taxios.defaults.headers.common = { Authorization: `${authToken}` };\n\t\taxios\n\t\t\t.get('/todos')\n\t\t\t.then((response) => {\n\t\t\t\tthis.setState({\n\t\t\t\t\ttodos: response.data,\n\t\t\t\t\tuiLoading: false\n\t\t\t\t});\n\t\t\t})\n\t\t\t.catch((err) => {\n\t\t\t\tconsole.log(err);\n\t\t\t});\n\t};\n\n\tdeleteTodoHandler(data) {\n\t\tauthMiddleWare(this.props.history);\n\t\tconst authToken = localStorage.getItem('AuthToken');\n\t\taxios.defaults.headers.common = { Authorization: `${authToken}` };\n\t\tlet todoId = data.todo.todoId;\n\t\taxios\n\t\t\t.delete(`todo/${todoId}`)\n\t\t\t.then(() => {\n\t\t\t\twindow.location.reload();\n\t\t\t})\n\t\t\t.catch((err) => {\n\t\t\t\tconsole.log(err);\n\t\t\t});\n\t}\n\n\thandleEditClickOpen(data) {\n\t\tthis.setState({\n\t\t\ttitle: data.todo.title,\n\t\t\tbody: data.todo.body,\n\t\t\ttodoId: data.todo.todoId,\n\t\t\tbuttonType: 'Edit',\n\t\t\topen: true\n\t\t});\n\t}\n\n\thandleViewOpen(data) {\n\t\tthis.setState({\n\t\t\ttitle: data.todo.title,\n\t\t\tbody: data.todo.body,\n\t\t\tviewOpen: true\n\t\t});\n\t}\n\n\trender() {\n\t\tconst DialogTitle = withStyles(styles)((props) => {\n\t\t\tconst { children, classes, onClose, ...other } = props;\n\t\t\treturn (\n\t\t\t\t<MuiDialogTitle disableTypography className={classes.root} {...other}>\n\t\t\t\t\t<Typography variant=\"h6\">{children}</Typography>\n\t\t\t\t\t{onClose ? (\n\t\t\t\t\t\t<IconButton aria-label=\"close\" className={classes.closeButton} onClick={onClose}>\n\t\t\t\t\t\t\t<CloseIcon />\n\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t) : null}\n\t\t\t\t</MuiDialogTitle>\n\t\t\t);\n\t\t});\n\n\t\tconst DialogContent = withStyles((theme) => ({\n\t\t\tviewRoot: {\n\t\t\t\tpadding: theme.spacing(2)\n\t\t\t}\n\t\t}))(MuiDialogContent);\n\n\t\tdayjs.extend(relativeTime);\n\t\tconst { classes } = this.props;\n\t\tconst { open, errors, viewOpen } = this.state;\n\n\t\tconst handleClickOpen = () => {\n\t\t\tthis.setState({\n\t\t\t\ttodoId: '',\n\t\t\t\ttitle: '',\n\t\t\t\tbody: '',\n\t\t\t\tbuttonType: '',\n\t\t\t\topen: true\n\t\t\t});\n\t\t};\n\n\t\tconst handleSubmit = (event) => {\n\t\t\tauthMiddleWare(this.props.history);\n\t\t\tevent.preventDefault();\n\t\t\tconst userTodo = {\n\t\t\t\ttitle: this.state.title,\n\t\t\t\tbody: this.state.body\n\t\t\t};\n\t\t\tlet options = {};\n\t\t\tif (this.state.buttonType === 'Edit') {\n\t\t\t\toptions = {\n\t\t\t\t\turl: `/todo/${this.state.todoId}`,\n\t\t\t\t\tmethod: 'put',\n\t\t\t\t\tdata: userTodo\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\toptions = {\n\t\t\t\t\turl: '/todo',\n\t\t\t\t\tmethod: 'post',\n\t\t\t\t\tdata: userTodo\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst authToken = localStorage.getItem('AuthToken');\n\t\t\taxios.defaults.headers.common = { Authorization: `${authToken}` };\n\t\t\taxios(options)\n\t\t\t\t.then(() => {\n\t\t\t\t\tthis.setState({ open: false });\n\t\t\t\t\twindow.location.reload();\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tthis.setState({ open: true, errors: error.response.data });\n\t\t\t\t\tconsole.log(error);\n\t\t\t\t});\n\t\t};\n\n\t\tconst handleViewClose = () => {\n\t\t\tthis.setState({ viewOpen: false });\n\t\t};\n\n\t\tconst handleClose = (event) => {\n\t\t\tthis.setState({ open: false });\n\t\t};\n\n\t\tif (this.state.uiLoading === true) {\n\t\t\treturn (\n\t\t\t\t<main className={classes.content}>\n\t\t\t\t\t<div className={classes.toolbar} />\n\t\t\t\t\t{this.state.uiLoading && <CircularProgress size={150} className={classes.uiProgess} />}\n\t\t\t\t</main>\n\t\t\t);\n\t\t} else {\n\t\t\treturn (\n\t\t\t\t<main className={classes.content}>\n\t\t\t\t\t<div className={classes.toolbar} />\n\n\t\t\t\t\t<IconButton\n\t\t\t\t\t\tclassName={classes.floatingButton}\n\t\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\t\taria-label=\"Add Todo\"\n\t\t\t\t\t\tonClick={handleClickOpen}\n\t\t\t\t\t>\n\t\t\t\t\t\t<AddCircleIcon style={{ fontSize: 60 }} />\n\t\t\t\t\t</IconButton>\n\t\t\t\t\t<Dialog fullScreen open={open} onClose={handleClose} TransitionComponent={Transition}>\n\t\t\t\t\t\t<AppBar className={classes.appBar}>\n\t\t\t\t\t\t\t<Toolbar>\n\t\t\t\t\t\t\t\t<IconButton edge=\"start\" color=\"inherit\" onClick={handleClose} aria-label=\"close\">\n\t\t\t\t\t\t\t\t\t<CloseIcon />\n\t\t\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t\t\t\t<Typography variant=\"h6\" className={classes.title}>\n\t\t\t\t\t\t\t\t\t{this.state.buttonType === 'Edit' ? 'Edit Todo' : 'Create a new Todo'}\n\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\t\t\t\tcolor=\"inherit\"\n\t\t\t\t\t\t\t\t\tonClick={handleSubmit}\n\t\t\t\t\t\t\t\t\tclassName={classes.submitButton}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{this.state.buttonType === 'Edit' ? 'Save' : 'Submit'}\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</Toolbar>\n\t\t\t\t\t\t</AppBar>\n\n\t\t\t\t\t\t<form className={classes.form} noValidate>\n\t\t\t\t\t\t\t<Grid container spacing={2}>\n\t\t\t\t\t\t\t\t<Grid item xs={12}>\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\tid=\"todoTitle\"\n\t\t\t\t\t\t\t\t\t\tlabel=\"Todo Title\"\n\t\t\t\t\t\t\t\t\t\tname=\"title\"\n\t\t\t\t\t\t\t\t\t\tautoComplete=\"todoTitle\"\n\t\t\t\t\t\t\t\t\t\thelperText={errors.title}\n\t\t\t\t\t\t\t\t\t\tvalue={this.state.title}\n\t\t\t\t\t\t\t\t\t\terror={errors.title ? true : false}\n\t\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t<Grid item xs={12}>\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\tid=\"todoDetails\"\n\t\t\t\t\t\t\t\t\t\tlabel=\"Todo Details\"\n\t\t\t\t\t\t\t\t\t\tname=\"body\"\n\t\t\t\t\t\t\t\t\t\tautoComplete=\"todoDetails\"\n\t\t\t\t\t\t\t\t\t\tmultiline\n\t\t\t\t\t\t\t\t\t\trows={25}\n\t\t\t\t\t\t\t\t\t\trowsMax={25}\n\t\t\t\t\t\t\t\t\t\thelperText={errors.body}\n\t\t\t\t\t\t\t\t\t\terror={errors.body ? true : false}\n\t\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t\t\tvalue={this.state.body}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t</form>\n\t\t\t\t\t</Dialog>\n\n\t\t\t\t\t<Grid container spacing={2}>\n\t\t\t\t\t\t{this.state.todos.map((todo) => (\n\t\t\t\t\t\t\t<Grid item xs={12} sm={6}>\n\t\t\t\t\t\t\t\t<Card className={classes.root} variant=\"outlined\">\n\t\t\t\t\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t\t\t\t\t<Typography variant=\"h5\" component=\"h2\">\n\t\t\t\t\t\t\t\t\t\t\t{todo.title}\n\t\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t\t<Typography className={classes.pos} color=\"textSecondary\">\n\t\t\t\t\t\t\t\t\t\t\t{dayjs(todo.createdAt).fromNow()}\n\t\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t\t<Typography variant=\"body2\" component=\"p\">\n\t\t\t\t\t\t\t\t\t\t\t{`${todo.body.substring(0, 65)}`}\n\t\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t</CardContent>\n\t\t\t\t\t\t\t\t\t<CardActions>\n\t\t\t\t\t\t\t\t\t\t<Button size=\"small\" color=\"primary\" onClick={() => this.handleViewOpen({ todo })}>\n\t\t\t\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t\t\t\tView{' '}\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t\t<Button size=\"small\" color=\"primary\" onClick={() => this.handleEditClickOpen({ todo })}>\n\t\t\t\t\t\t\t\t\t\t\tEdit\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t\t<Button size=\"small\" color=\"primary\" onClick={() => this.deleteTodoHandler({ todo })}>\n\t\t\t\t\t\t\t\t\t\t\tDelete\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t</CardActions>\n\t\t\t\t\t\t\t\t</Card>\n\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Grid>\n\n\t\t\t\t\t<Dialog\n\t\t\t\t\t\tonClose={handleViewClose}\n\t\t\t\t\t\taria-labelledby=\"customized-dialog-title\"\n\t\t\t\t\t\topen={viewOpen}\n\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\tclasses={{ paperFullWidth: classes.dialogeStyle }}\n\t\t\t\t\t>\n\t\t\t\t\t\t<DialogTitle id=\"customized-dialog-title\" onClose={handleViewClose}>\n\t\t\t\t\t\t\t{this.state.title}\n\t\t\t\t\t\t</DialogTitle>\n\t\t\t\t\t\t<DialogContent dividers>\n\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\tid=\"todoDetails\"\n\t\t\t\t\t\t\t\tname=\"body\"\n\t\t\t\t\t\t\t\tmultiline\n\t\t\t\t\t\t\t\treadonly\n\t\t\t\t\t\t\t\trows={1}\n\t\t\t\t\t\t\t\trowsMax={25}\n\t\t\t\t\t\t\t\tvalue={this.state.body}\n\t\t\t\t\t\t\t\tInputProps={{\n\t\t\t\t\t\t\t\t\tdisableUnderline: true\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</DialogContent>\n\t\t\t\t\t</Dialog>\n\t\t\t\t</main>\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport default withStyles(styles)(todo);\n"
  },
  {
    "path": "view/src/index.js",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\n\nimport App from './App';\nimport * as serviceWorker from './serviceWorker';\n\n\nReactDOM.render(\n  <React.StrictMode>\n    <App />\n  </React.StrictMode>,\n  document.getElementById('root')\n);\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://bit.ly/CRA-PWA\nserviceWorker.unregister();\n"
  },
  {
    "path": "view/src/pages/home.js",
    "content": "import React, { Component } from 'react';\nimport axios from 'axios';\n\nimport Account from '../components/account';\nimport Todo from '../components/todo';\n\nimport Drawer from '@material-ui/core/Drawer';\nimport AppBar from '@material-ui/core/AppBar';\nimport CssBaseline from '@material-ui/core/CssBaseline';\nimport Toolbar from '@material-ui/core/Toolbar';\nimport List from '@material-ui/core/List';\nimport Typography from '@material-ui/core/Typography';\nimport Divider from '@material-ui/core/Divider';\nimport ListItem from '@material-ui/core/ListItem';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport withStyles from '@material-ui/core/styles/withStyles';\nimport AccountBoxIcon from '@material-ui/icons/AccountBox';\nimport NotesIcon from '@material-ui/icons/Notes';\nimport Avatar from '@material-ui/core/avatar';\nimport ExitToAppIcon from '@material-ui/icons/ExitToApp';\nimport CircularProgress from '@material-ui/core/CircularProgress';\n\nimport { authMiddleWare } from '../util/auth';\n\nconst drawerWidth = 240;\n\nconst styles = (theme) => ({\n\troot: {\n\t\tdisplay: 'flex'\n\t},\n\tappBar: {\n\t\tzIndex: theme.zIndex.drawer + 1\n\t},\n\tdrawer: {\n\t\twidth: drawerWidth,\n\t\tflexShrink: 0\n\t},\n\tdrawerPaper: {\n\t\twidth: drawerWidth\n\t},\n\tcontent: {\n\t\tflexGrow: 1,\n\t\tpadding: theme.spacing(3)\n\t},\n\tavatar: {\n\t\theight: 110,\n\t\twidth: 100,\n\t\tflexShrink: 0,\n\t\tflexGrow: 0,\n\t\tmarginTop: 20\n\t},\n\tuiProgess: {\n\t\tposition: 'fixed',\n\t\tzIndex: '1000',\n\t\theight: '31px',\n\t\twidth: '31px',\n\t\tleft: '45%',\n\t\ttop: '35%'\n\t},\n\ttoolbar: theme.mixins.toolbar\n});\n\nclass home extends Component {\n\tstate = {\n\t\trender: false\n\t};\n\n\tloadAccountPage = (event) => {\n\t\tthis.setState({ render: true });\n\t};\n\n\tloadTodoPage = (event) => {\n\t\tthis.setState({ render: false });\n\t};\n\n\tlogoutHandler = (event) => {\n\t\tlocalStorage.removeItem('AuthToken');\n\t\tthis.props.history.push('/login');\n\t};\n\n\tconstructor(props) {\n\t\tsuper(props);\n\n\t\tthis.state = {\n\t\t\tfirstName: '',\n\t\t\tlastName: '',\n\t\t\tprofilePicture: '',\n\t\t\tuiLoading: true,\n\t\t\timageLoading: false\n\t\t};\n\t}\n\n\tcomponentWillMount = () => {\n\t\tauthMiddleWare(this.props.history);\n\t\tconst authToken = localStorage.getItem('AuthToken');\n\t\taxios.defaults.headers.common = { Authorization: `${authToken}` };\n\t\taxios\n\t\t\t.get('/user')\n\t\t\t.then((response) => {\n\t\t\t\tconsole.log(response.data);\n\t\t\t\tthis.setState({\n\t\t\t\t\tfirstName: response.data.userCredentials.firstName,\n\t\t\t\t\tlastName: response.data.userCredentials.lastName,\n\t\t\t\t\temail: response.data.userCredentials.email,\n\t\t\t\t\tphoneNumber: response.data.userCredentials.phoneNumber,\n\t\t\t\t\tcountry: response.data.userCredentials.country,\n\t\t\t\t\tusername: response.data.userCredentials.username,\n\t\t\t\t\tuiLoading: false,\n\t\t\t\t\tprofilePicture: response.data.userCredentials.imageUrl\n\t\t\t\t});\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tif (error.response.status === 403) {\n\t\t\t\t\tthis.props.history.push('/login');\n\t\t\t\t}\n\t\t\t\tconsole.log(error);\n\t\t\t\tthis.setState({ errorMsg: 'Error in retrieving the data' });\n\t\t\t});\n\t};\n\n\trender() {\n\t\tconst { classes } = this.props;\n\t\tif (this.state.uiLoading === true) {\n\t\t\treturn (\n\t\t\t\t<div className={classes.root}>\n\t\t\t\t\t{this.state.uiLoading && <CircularProgress size={150} className={classes.uiProgess} />}\n\t\t\t\t</div>\n\t\t\t);\n\t\t} else {\n\t\t\treturn (\n\t\t\t\t<div className={classes.root}>\n\t\t\t\t\t<CssBaseline />\n\t\t\t\t\t<AppBar position=\"fixed\" className={classes.appBar}>\n\t\t\t\t\t\t<Toolbar>\n\t\t\t\t\t\t\t<Typography variant=\"h6\" noWrap>\n\t\t\t\t\t\t\t\tTodoApp\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t</Toolbar>\n\t\t\t\t\t</AppBar>\n\t\t\t\t\t<Drawer\n\t\t\t\t\t\tclassName={classes.drawer}\n\t\t\t\t\t\tvariant=\"permanent\"\n\t\t\t\t\t\tclasses={{\n\t\t\t\t\t\t\tpaper: classes.drawerPaper\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className={classes.toolbar} />\n\t\t\t\t\t\t<Divider />\n\t\t\t\t\t\t<center>\n\t\t\t\t\t\t\t<Avatar src={this.state.profilePicture} className={classes.avatar} />\n\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t{this.state.firstName} {this.state.lastName}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</center>\n\t\t\t\t\t\t<Divider />\n\t\t\t\t\t\t<List>\n\t\t\t\t\t\t\t<ListItem button key=\"Todo\" onClick={this.loadTodoPage}>\n\t\t\t\t\t\t\t\t<ListItemIcon>\n\t\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t\t<NotesIcon />{' '}\n\t\t\t\t\t\t\t\t</ListItemIcon>\n\t\t\t\t\t\t\t\t<ListItemText primary=\"Todo\" />\n\t\t\t\t\t\t\t</ListItem>\n\n\t\t\t\t\t\t\t<ListItem button key=\"Account\" onClick={this.loadAccountPage}>\n\t\t\t\t\t\t\t\t<ListItemIcon>\n\t\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t\t<AccountBoxIcon />{' '}\n\t\t\t\t\t\t\t\t</ListItemIcon>\n\t\t\t\t\t\t\t\t<ListItemText primary=\"Account\" />\n\t\t\t\t\t\t\t</ListItem>\n\n\t\t\t\t\t\t\t<ListItem button key=\"Logout\" onClick={this.logoutHandler}>\n\t\t\t\t\t\t\t\t<ListItemIcon>\n\t\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t\t<ExitToAppIcon />{' '}\n\t\t\t\t\t\t\t\t</ListItemIcon>\n\t\t\t\t\t\t\t\t<ListItemText primary=\"Logout\" />\n\t\t\t\t\t\t\t</ListItem>\n\t\t\t\t\t\t</List>\n\t\t\t\t\t</Drawer>\n\n\t\t\t\t\t<div>{this.state.render ? <Account /> : <Todo />}</div>\n\t\t\t\t</div>\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport default withStyles(styles)(home);\n"
  },
  {
    "path": "view/src/pages/login.js",
    "content": "// Material UI components\nimport React, { Component } from 'react';\nimport Avatar from '@material-ui/core/Avatar';\nimport Button from '@material-ui/core/Button';\nimport CssBaseline from '@material-ui/core/CssBaseline';\nimport TextField from '@material-ui/core/TextField';\nimport Link from '@material-ui/core/Link';\nimport Grid from '@material-ui/core/Grid';\nimport LockOutlinedIcon from '@material-ui/icons/LockOutlined';\nimport Typography from '@material-ui/core/Typography';\nimport withStyles from '@material-ui/core/styles/withStyles';\nimport Container from '@material-ui/core/Container';\nimport CircularProgress from '@material-ui/core/CircularProgress';\n\nimport axios from 'axios';\n\nconst styles = (theme) => ({\n\tpaper: {\n\t\tmarginTop: theme.spacing(8),\n\t\tdisplay: 'flex',\n\t\tflexDirection: 'column',\n\t\talignItems: 'center'\n\t},\n\tavatar: {\n\t\tmargin: theme.spacing(1),\n\t\tbackgroundColor: theme.palette.secondary.main\n\t},\n\tform: {\n\t\twidth: '100%',\n\t\tmarginTop: theme.spacing(1)\n\t},\n\tsubmit: {\n\t\tmargin: theme.spacing(3, 0, 2)\n\t},\n\tcustomError: {\n\t\tcolor: 'red',\n\t\tfontSize: '0.8rem',\n\t\tmarginTop: 10\n\t},\n\tprogess: {\n\t\tposition: 'absolute'\n\t}\n});\n\nclass login extends Component {\n\tconstructor(props) {\n\t\tsuper(props);\n\n\t\tthis.state = {\n\t\t\temail: '',\n\t\t\tpassword: '',\n\t\t\terrors: [],\n\t\t\tloading: false\n\t\t};\n\t}\n\n\tcomponentWillReceiveProps(nextProps) {\n\t\tif(\"errors\" in nextProps.UI){\n\t\t\tif (nextProps.UI.errors) {\n\t\t\tthis.setState({\n\t\t\t\terrors: nextProps.UI.errors\n\t\t\t});\n\t\t}\n\t\t}\n\t\t\n\t}\n\n\thandleChange = (event) => {\n\t\tthis.setState({\n\t\t\t[event.target.name]: event.target.value\n\t\t});\n\t};\n\n\thandleSubmit = (event) => {\n\t\tevent.preventDefault();\n\t\tthis.setState({ loading: true });\n\t\tconst userData = {\n\t\t\temail: this.state.email,\n\t\t\tpassword: this.state.password\n\t\t};\n\t\taxios\n\t\t\t.post('/login', userData)\n\t\t\t.then((response) => {\n\t\t\t\tlocalStorage.setItem('AuthToken', `Bearer ${response.data.token}`);\n\t\t\t\tthis.setState({\n\t\t\t\t\tloading: false\n\t\t\t\t});\n\t\t\t\tthis.props.history.push('/');\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.setState({\n\t\t\t\t\terrors: error.response.data,\n\t\t\t\t\tloading: false\n\t\t\t\t});\n\t\t\t});\n\t};\n\n\trender() {\n\t\tconst { classes } = this.props;\n\t\tconst { errors, loading } = this.state;\n\t\treturn (\n\t\t\t<Container component=\"main\" maxWidth=\"xs\">\n\t\t\t\t<CssBaseline />\n\t\t\t\t<div className={classes.paper}>\n\t\t\t\t\t<Avatar className={classes.avatar}>\n\t\t\t\t\t\t<LockOutlinedIcon />\n\t\t\t\t\t</Avatar>\n\t\t\t\t\t<Typography component=\"h1\" variant=\"h5\">\n\t\t\t\t\t\tLogin\n\t\t\t\t\t</Typography>\n\t\t\t\t\t<form className={classes.form} noValidate>\n\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\tmargin=\"normal\"\n\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\tid=\"email\"\n\t\t\t\t\t\t\tlabel=\"Email Address\"\n\t\t\t\t\t\t\tname=\"email\"\n\t\t\t\t\t\t\tautoComplete=\"email\"\n\t\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\t\thelperText={errors.email}\n\t\t\t\t\t\t\terror={errors.email ? true : false}\n\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\tmargin=\"normal\"\n\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\tname=\"password\"\n\t\t\t\t\t\t\tlabel=\"Password\"\n\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\tid=\"password\"\n\t\t\t\t\t\t\tautoComplete=\"current-password\"\n\t\t\t\t\t\t\thelperText={errors.password}\n\t\t\t\t\t\t\terror={errors.password ? true : false}\n\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\t\t\tclassName={classes.submit}\n\t\t\t\t\t\t\tonClick={this.handleSubmit}\n\t\t\t\t\t\t\tdisabled={loading || !this.state.email || !this.state.password}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tSign In\n\t\t\t\t\t\t\t{loading && <CircularProgress size={30} className={classes.progess} />}\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t<Grid container>\n\t\t\t\t\t\t\t<Grid item>\n\t\t\t\t\t\t\t\t<Link href=\"signup\" variant=\"body2\">\n\t\t\t\t\t\t\t\t\t{\"Don't have an account? Sign Up\"}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t{errors.general && (\n\t\t\t\t\t\t\t<Typography variant=\"body2\" className={classes.customError}>\n\t\t\t\t\t\t\t\t{errors.general}\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</form>\n\t\t\t\t</div>\n\t\t\t</Container>\n\t\t);\n\t}\n}\n\nexport default withStyles(styles)(login);\n"
  },
  {
    "path": "view/src/pages/signup.js",
    "content": "import React, { Component } from 'react';\nimport Avatar from '@material-ui/core/Avatar';\nimport Button from '@material-ui/core/Button';\nimport CssBaseline from '@material-ui/core/CssBaseline';\nimport TextField from '@material-ui/core/TextField';\nimport Link from '@material-ui/core/Link';\nimport Grid from '@material-ui/core/Grid';\nimport LockOutlinedIcon from '@material-ui/icons/LockOutlined';\nimport Typography from '@material-ui/core/Typography';\nimport Container from '@material-ui/core/Container';\nimport withStyles from '@material-ui/core/styles/withStyles';\nimport CircularProgress from '@material-ui/core/CircularProgress';\n\nimport axios from 'axios';\n\nconst styles = (theme) => ({\n\tpaper: {\n\t\tmarginTop: theme.spacing(8),\n\t\tdisplay: 'flex',\n\t\tflexDirection: 'column',\n\t\talignItems: 'center'\n\t},\n\tavatar: {\n\t\tmargin: theme.spacing(1),\n\t\tbackgroundColor: theme.palette.secondary.main\n\t},\n\tform: {\n\t\twidth: '100%', // Fix IE 11 issue.\n\t\tmarginTop: theme.spacing(3)\n\t},\n\tsubmit: {\n\t\tmargin: theme.spacing(3, 0, 2)\n\t},\n\tprogess: {\n\t\tposition: 'absolute'\n\t}\n});\n\nclass signup extends Component {\n\tconstructor(props) {\n\t\tsuper(props);\n\n\t\tthis.state = {\n\t\t\tfirstName: '',\n\t\t\tlastName: '',\n\t\t\tphoneNumber: '',\n\t\t\tcountry: '',\n\t\t\tusername: '',\n\t\t\temail: '',\n\t\t\tpassword: '',\n\t\t\tconfirmPassword: '',\n\t\t\terrors: [],\n\t\t\tloading: false\n\t\t};\n\t}\n\n\tcomponentWillReceiveProps(nextProps) {\n\t\tif (nextProps.UI.errors) {\n\t\t\tthis.setState({\n\t\t\t\terrors: nextProps.UI.errors\n\t\t\t});\n\t\t}\n\t}\n\n\thandleChange = (event) => {\n\t\tthis.setState({\n\t\t\t[event.target.name]: event.target.value\n\t\t});\n\t};\n\n\thandleSubmit = (event) => {\n\t\tevent.preventDefault();\n\t\tthis.setState({ loading: true });\n\t\tconst newUserData = {\n\t\t\tfirstName: this.state.firstName,\n\t\t\tlastName: this.state.lastName,\n\t\t\tphoneNumber: this.state.phoneNumber,\n\t\t\tcountry: this.state.country,\n\t\t\tusername: this.state.username,\n\t\t\temail: this.state.email,\n\t\t\tpassword: this.state.password,\n\t\t\tconfirmPassword: this.state.confirmPassword\n\t\t};\n\t\taxios\n\t\t\t.post('/signup', newUserData)\n\t\t\t.then((response) => {\n\t\t\t\tlocalStorage.setItem('AuthToken', `Bearer ${response.data.token}`);\n\t\t\t\tthis.setState({ \n\t\t\t\t\tloading: false,\n\t\t\t\t});\t\n\t\t\t\tthis.props.history.push('/');\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.setState({\n\t\t\t\t\terrors: error.response.data,\n\t\t\t\t\tloading: false\n\t\t\t\t});\n\t\t\t});\n\t};\n\n\trender() {\n\t\tconst { classes } = this.props;\n\t\tconst { errors, loading } = this.state;\n\t\treturn (\n\t\t\t<Container component=\"main\" maxWidth=\"xs\">\n\t\t\t\t<CssBaseline />\n\t\t\t\t<div className={classes.paper}>\n\t\t\t\t\t<Avatar className={classes.avatar}>\n\t\t\t\t\t\t<LockOutlinedIcon />\n\t\t\t\t\t</Avatar>\n\t\t\t\t\t<Typography component=\"h1\" variant=\"h5\">\n\t\t\t\t\t\tSign up\n\t\t\t\t\t</Typography>\n\t\t\t\t\t<form className={classes.form} noValidate>\n\t\t\t\t\t\t<Grid container spacing={2}>\n\t\t\t\t\t\t\t<Grid item xs={12} sm={6}>\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\tid=\"firstName\"\n\t\t\t\t\t\t\t\t\tlabel=\"First Name\"\n\t\t\t\t\t\t\t\t\tname=\"firstName\"\n\t\t\t\t\t\t\t\t\tautoComplete=\"firstName\"\n\t\t\t\t\t\t\t\t\thelperText={errors.firstName}\n\t\t\t\t\t\t\t\t\terror={errors.firstName ? true : false}\n\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t<Grid item xs={12} sm={6}>\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\tid=\"lastName\"\n\t\t\t\t\t\t\t\t\tlabel=\"Last Name\"\n\t\t\t\t\t\t\t\t\tname=\"lastName\"\n\t\t\t\t\t\t\t\t\tautoComplete=\"lastName\"\n\t\t\t\t\t\t\t\t\thelperText={errors.lastName}\n\t\t\t\t\t\t\t\t\terror={errors.lastName ? true : false}\n\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Grid>\n\n\t\t\t\t\t\t\t<Grid item xs={12} sm={6}>\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\tid=\"username\"\n\t\t\t\t\t\t\t\t\tlabel=\"User Name\"\n\t\t\t\t\t\t\t\t\tname=\"username\"\n\t\t\t\t\t\t\t\t\tautoComplete=\"username\"\n\t\t\t\t\t\t\t\t\thelperText={errors.username}\n\t\t\t\t\t\t\t\t\terror={errors.username ? true : false}\n\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Grid>\n\n\t\t\t\t\t\t\t<Grid item xs={12} sm={6}>\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\tid=\"phoneNumber\"\n\t\t\t\t\t\t\t\t\tlabel=\"Phone Number\"\n\t\t\t\t\t\t\t\t\tname=\"phoneNumber\"\n\t\t\t\t\t\t\t\t\tautoComplete=\"phoneNumber\"\n\t\t\t\t\t\t\t\t\tpattern=\"[7-9]{1}[0-9]{9}\"\n\t\t\t\t\t\t\t\t\thelperText={errors.phoneNumber}\n\t\t\t\t\t\t\t\t\terror={errors.phoneNumber ? true : false}\n\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Grid>\n\n\t\t\t\t\t\t\t<Grid item xs={12}>\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\tid=\"email\"\n\t\t\t\t\t\t\t\t\tlabel=\"Email Address\"\n\t\t\t\t\t\t\t\t\tname=\"email\"\n\t\t\t\t\t\t\t\t\tautoComplete=\"email\"\n\t\t\t\t\t\t\t\t\thelperText={errors.email}\n\t\t\t\t\t\t\t\t\terror={errors.email ? true : false}\n\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Grid>\n\n\t\t\t\t\t\t\t<Grid item xs={12}>\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\tid=\"country\"\n\t\t\t\t\t\t\t\t\tlabel=\"Country\"\n\t\t\t\t\t\t\t\t\tname=\"country\"\n\t\t\t\t\t\t\t\t\tautoComplete=\"country\"\n\t\t\t\t\t\t\t\t\thelperText={errors.country}\n\t\t\t\t\t\t\t\t\terror={errors.country ? true : false}\n\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Grid>\n\n\t\t\t\t\t\t\t<Grid item xs={12}>\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\tname=\"password\"\n\t\t\t\t\t\t\t\t\tlabel=\"Password\"\n\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\tid=\"password\"\n\t\t\t\t\t\t\t\t\tautoComplete=\"current-password\"\n\t\t\t\t\t\t\t\t\thelperText={errors.password}\n\t\t\t\t\t\t\t\t\terror={errors.password ? true : false}\n\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t<Grid item xs={12}>\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\t\t\t\trequired\n\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\tname=\"confirmPassword\"\n\t\t\t\t\t\t\t\t\tlabel=\"Confirm Password\"\n\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\tid=\"confirmPassword\"\n\t\t\t\t\t\t\t\t\tautoComplete=\"current-password\"\n\t\t\t\t\t\t\t\t\tonChange={this.handleChange}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\t\t\tclassName={classes.submit}\n\t\t\t\t\t\t\tonClick={this.handleSubmit}\n                            disabled={loading || \n                                !this.state.email || \n                                !this.state.password ||\n                                !this.state.firstName || \n                                !this.state.lastName ||\n                                !this.state.country || \n                                !this.state.username || \n                                !this.state.phoneNumber}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tSign Up\n\t\t\t\t\t\t\t{loading && <CircularProgress size={30} className={classes.progess} />}\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t<Grid container justify=\"flex-end\">\n\t\t\t\t\t\t\t<Grid item>\n\t\t\t\t\t\t\t\t<Link href=\"login\" variant=\"body2\">\n\t\t\t\t\t\t\t\t\tAlready have an account? Sign in\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t</form>\n\t\t\t\t</div>\n\t\t\t</Container>\n\t\t);\n\t}\n}\n\nexport default withStyles(styles)(signup);\n"
  },
  {
    "path": "view/src/serviceWorker.js",
    "content": "// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read https://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n  window.location.hostname === 'localhost' ||\n    // [::1] is the IPv6 localhost address.\n    window.location.hostname === '[::1]' ||\n    // 127.0.0.0/8 are considered localhost for IPv4.\n    window.location.hostname.match(\n      /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n    )\n);\n\nexport function register(config) {\n  if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n    // The URL constructor is available in all browsers that support SW.\n    const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\n    if (publicUrl.origin !== window.location.origin) {\n      // Our service worker won't work if PUBLIC_URL is on a different origin\n      // from what our page is served on. This might happen if a CDN is used to\n      // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n      return;\n    }\n\n    window.addEventListener('load', () => {\n      const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n      if (isLocalhost) {\n        // This is running on localhost. Let's check if a service worker still exists or not.\n        checkValidServiceWorker(swUrl, config);\n\n        // Add some additional logging to localhost, pointing developers to the\n        // service worker/PWA documentation.\n        navigator.serviceWorker.ready.then(() => {\n          console.log(\n            'This web app is being served cache-first by a service ' +\n              'worker. To learn more, visit https://bit.ly/CRA-PWA'\n          );\n        });\n      } else {\n        // Is not localhost. Just register service worker\n        registerValidSW(swUrl, config);\n      }\n    });\n  }\n}\n\nfunction registerValidSW(swUrl, config) {\n  navigator.serviceWorker\n    .register(swUrl)\n    .then(registration => {\n      registration.onupdatefound = () => {\n        const installingWorker = registration.installing;\n        if (installingWorker == null) {\n          return;\n        }\n        installingWorker.onstatechange = () => {\n          if (installingWorker.state === 'installed') {\n            if (navigator.serviceWorker.controller) {\n              // At this point, the updated precached content has been fetched,\n              // but the previous service worker will still serve the older\n              // content until all client tabs are closed.\n              console.log(\n                'New content is available and will be used when all ' +\n                  'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\n              );\n\n              // Execute callback\n              if (config && config.onUpdate) {\n                config.onUpdate(registration);\n              }\n            } else {\n              // At this point, everything has been precached.\n              // It's the perfect time to display a\n              // \"Content is cached for offline use.\" message.\n              console.log('Content is cached for offline use.');\n\n              // Execute callback\n              if (config && config.onSuccess) {\n                config.onSuccess(registration);\n              }\n            }\n          }\n        };\n      };\n    })\n    .catch(error => {\n      console.error('Error during service worker registration:', error);\n    });\n}\n\nfunction checkValidServiceWorker(swUrl, config) {\n  // Check if the service worker can be found. If it can't reload the page.\n  fetch(swUrl, {\n    headers: { 'Service-Worker': 'script' },\n  })\n    .then(response => {\n      // Ensure service worker exists, and that we really are getting a JS file.\n      const contentType = response.headers.get('content-type');\n      if (\n        response.status === 404 ||\n        (contentType != null && contentType.indexOf('javascript') === -1)\n      ) {\n        // No service worker found. Probably a different app. Reload the page.\n        navigator.serviceWorker.ready.then(registration => {\n          registration.unregister().then(() => {\n            window.location.reload();\n          });\n        });\n      } else {\n        // Service worker found. Proceed as normal.\n        registerValidSW(swUrl, config);\n      }\n    })\n    .catch(() => {\n      console.log(\n        'No internet connection found. App is running in offline mode.'\n      );\n    });\n}\n\nexport function unregister() {\n  if ('serviceWorker' in navigator) {\n    navigator.serviceWorker.ready\n      .then(registration => {\n        registration.unregister();\n      })\n      .catch(error => {\n        console.error(error.message);\n      });\n  }\n}\n"
  },
  {
    "path": "view/src/setupTests.js",
    "content": "// jest-dom adds custom jest matchers for asserting on DOM nodes.\n// allows you to do things like:\n// expect(element).toHaveTextContent(/react/i)\n// learn more: https://github.com/testing-library/jest-dom\nimport '@testing-library/jest-dom/extend-expect';\n"
  },
  {
    "path": "view/src/util/auth.js",
    "content": "export const authMiddleWare = (history) => {\n    const authToken = localStorage.getItem('AuthToken');\n    if(authToken === null){\n        history.push('/login')\n    }\n}"
  }
]