Skip to content

Commit

Permalink
ability to add goals and view existing goals
Browse files Browse the repository at this point in the history
  • Loading branch information
sdevalapurkar committed Oct 13, 2021
1 parent 614c760 commit 92aa623
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 8 deletions.
25 changes: 24 additions & 1 deletion api/src/helpers/authenticationHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,29 @@ function generateAccessToken(payload) {
return jwt.sign(payload, process.env.API_SECRET, { expiresIn: "1h" });
}

function getAuthenticatedUser(headers) {
let currentUser = null;

if (!headers || !headers.authorization) {
return currentUser;
}

const token = headers.authorization.split(" ")[1];

if (!token) {
return currentUser;
}

jwt.verify(token, process.env.API_SECRET, (err, decoded) => {
if (!err && decoded) {
currentUser = decoded;
}
});

return currentUser;
}

module.exports = {
generateAccessToken
generateAccessToken,
getAuthenticatedUser
};
41 changes: 41 additions & 0 deletions api/src/paths/goal/add.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const { getCustomError } = require("../../helpers/errorHandler");
const { getAuthenticatedUser } = require("../../helpers/authenticationHelpers");

async function addGoal(req, res, db) {
if (
!req.body ||
!req.body.data ||
!req.body.data.goal
) {
return res.status(400).json(getCustomError(400));
}

const authenticatedUser = getAuthenticatedUser(req.headers);

if (!authenticatedUser) {
return res.status(401).json(getCustomError(401));
}

const { name, time, startDate, endDate } = req.body.data.goal;

const record = await db('goals').insert({
user_email: authenticatedUser.email,
goal_name: name,
goal_times: time,
goal_start_date: startDate,
goal_end_date: endDate
}, ['id']);

if (!record || !record[0] || !record[0].id) {
return res.status(400).json(getCustomError(400));
}

return res.json({
type: "Goal created",
attributes: {
value: record[0].id,
}
});
}

module.exports = addGoal;
27 changes: 27 additions & 0 deletions api/src/paths/goal/get.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { getCustomError } = require("../../helpers/errorHandler");
const { getAuthenticatedUser } = require("../../helpers/authenticationHelpers");

async function getGoals(req, res, db) {
const authenticatedUser = getAuthenticatedUser(req.headers);

if (!authenticatedUser) {
return res.status(401).json(getCustomError(401));
}

const records = await db('goals').where({
user_email: authenticatedUser.email
});

if (!records) {
return res.status(400).json(getCustomError(400));
}

return res.json({
type: "Goals fetched",
attributes: {
value: records,
}
});
}

module.exports = getGoals;
11 changes: 11 additions & 0 deletions api/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const morgan = require("morgan");
const knex = require("knex");
const registerUser = require("./paths/register");
const loginUser = require("./paths/login");
const addGoal = require("./paths/goal/add");
const getGoals = require("./paths/goal/get");

const db = knex({
client: "postgres",
Expand Down Expand Up @@ -52,5 +54,14 @@ app.post("/v1/login", async (req, res) => {
return loginUser(req, res, db);
});

// Adds a record to the goals table
app.post("/v1/goals", async (req, res) => {
return addGoal(req, res, db);
});

app.get("/v1/goals", async (req, res) => {
return getGoals(req, res, db);
});

// API is listening and server is up
app.listen(PORT, () => console.log(`Server up at http:https://localhost:${PORT}`));
3 changes: 2 additions & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"react-scripts": "4.0.3",
"web-vitals": "^1.0.1",
"@mdi/js": "^6.2.95",
"@mdi/react": "^1.5.0"
"@mdi/react": "^1.5.0",
"moment": "^2.29.1"
},
"scripts": {
"start": "react-scripts start",
Expand Down
150 changes: 147 additions & 3 deletions app/src/components/Homepage.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import { Box, Button, Typography, AppBar, Toolbar, Divider } from '@material-ui/core';
import {
Box,
Button,
Typography,
AppBar,
Toolbar,
Divider,
TableContainer,
Table,
TableHead,
TableCell,
TableBody,
TableRow,
Paper
} from '@material-ui/core';
import Icon from '@mdi/react';
import { isAuthenticated } from '../helpers/authenticationHelper';
import jwt from "jsonwebtoken";
import makeStyles from '@material-ui/core/styles/makeStyles';
import { mdiAccountCircle, mdiLogoutVariant } from '@mdi/js';
import parakeetImage from '../images/parakeet-pic.png';
import { useState } from 'react';
import { useState, useEffect } from 'react';
import axios from "axios";
import moment from "moment";
import NewGoalDialog from './NewGoalDialog';

const useStyles = makeStyles((theme) => ({
Expand Down Expand Up @@ -55,16 +71,134 @@ const useStyles = makeStyles((theme) => ({
}));

function Homepage(props) {
const apiHost = process.env.REACT_APP_API_HOST || 'localhost';
const apiPort = process.env.REACT_APP_API_PORT || '5000';

const classes = useStyles();

const [existingGoals, setExistingGoals] = useState([]);
const [openNewGoalDialog, setOpenNewGoalDialog] = useState(false);
const [goalName, setGoalName] = useState('');
const [goalTimes, setGoalTimes] = useState(null);
const [goalStartDate, setGoalStartDate] = useState(null);
const [goalEndDate, setGoalEndDate] = useState(null);
const [goalDialogError, setGoalDialogError] = useState('');

useEffect(() => {
if (openNewGoalDialog) {
return;
}

getExistingGoals();
}, [openNewGoalDialog]);

const getExistingGoals = async () => {
const response = await axios.get(
`http:https://${apiHost}:${apiPort}/v1/goals`, {
headers: {
Authorization: `Bearer ${sessionStorage.getItem("jwt")}`
}
}
);

if (!response || !response.data || !response.data.attributes || !response.data.attributes.value) {
return;
}

const { value } = response.data.attributes;

setExistingGoals(value);
};

const logoutUser = () => {
sessionStorage.removeItem('jwt');
props.setIsAuthed(isAuthenticated());
};

const handleSubmitNewGoal = async () => {
if (!goalName || !goalTimes || !goalStartDate || !goalEndDate) {
setGoalDialogError('All fields of the form are required. Please fill them out.');
return;
}

const response = await axios.post(
`http:https://${apiHost}:${apiPort}/v1/goals`, {
data: {
goal: {
name: goalName,
time: goalTimes,
startDate: moment(goalStartDate, 'YYYY-MM-DD').format(),
endDate: moment(goalEndDate, 'YYYY-MM-DD').format()
}
}
}, {
headers: {
Authorization: `Bearer ${sessionStorage.getItem("jwt")}`
}
}
);

if (!response || !response.data) {
setGoalDialogError('There was an error adding your goal. Please try again later.');
return;
}

setOpenNewGoalDialog(false);
};

const getExistingGoalsTable = () => {
if (!existingGoals.length) {
return (
<Table>
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Times</TableCell>
<TableCell>Start Time</TableCell>
<TableCell>End Date</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell colSpan={4}>
<Box display="flex" justifyContent="center">
No Results
</Box>
</TableCell>
</TableRow>
</TableBody>
</Table>
);
}

return (
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Times</TableCell>
<TableCell>Start Date</TableCell>
<TableCell>End Date</TableCell>
</TableRow>
</TableHead>
<TableBody data-testid="goals-table">
{existingGoals?.map((row) => (
<TableRow key={row.id}>
<TableCell component="th" scope="row">
{row.goal_name}
</TableCell>
<TableCell>{row.goal_times}</TableCell>
<TableCell>{moment(row.goal_start_date).format('MMM D, YYYY')}</TableCell>
<TableCell>{moment(row.goal_end_date).format('MMM D, YYYY')}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
};

return (
<>
<AppBar position="sticky" style={{ boxShadow: 'none' }}>
Expand Down Expand Up @@ -118,14 +252,24 @@ function Homepage(props) {
Add New Goal
</Button>
</Box>
<Paper>
{getExistingGoalsTable()}
</Paper>
</Box>

<NewGoalDialog
isOpen={openNewGoalDialog}
handleClose={() => setOpenNewGoalDialog(false)}
handleSubmit={() => console.log('submit')}
handleSubmit={() => handleSubmitNewGoal()}
goalName={goalName}
setGoalName={setGoalName}
goalTimes={goalTimes}
setGoalTimes={setGoalTimes}
goalStartDate={goalStartDate}
setGoalStartDate={setGoalStartDate}
goalEndDate={goalEndDate}
setGoalEndDate={setGoalEndDate}
goalDialogError={goalDialogError}
/>
</>
);
Expand Down
Loading

0 comments on commit 92aa623

Please sign in to comment.