Skip to content

Commit

Permalink
add redeemPoints logic b00tc4mp#431; improve delayTask logic b00tc4mp…
Browse files Browse the repository at this point in the history
  • Loading branch information
pankelix committed Mar 2, 2024
1 parent 1853a6f commit becc2ba
Show file tree
Hide file tree
Showing 15 changed files with 194 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import jwt from 'jsonwebtoken'
const {JsonWebTokenError} = jwt

import { errors } from 'com'
const { NotFoundError, ContentError, TokenError } = errors
Expand Down
2 changes: 2 additions & 0 deletions staff/miguel-arias/project/api/handlers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import deleteTaskHandler from './deleteTaskHandler.js'
import completeTaskHandler from './completeTaskHandler.js'
import retrieveRoomsHandler from './retrieveRoomsHandler.js'
import createTemplateHandler from './createTemplateHandler.js'
import redeemPointsHandler from './redeemPointsHandler.js'

export {
registerHomeHandler,
Expand All @@ -30,4 +31,5 @@ export {
completeTaskHandler,
retrieveRoomsHandler,
createTemplateHandler,
redeemPointsHandler,
}
38 changes: 38 additions & 0 deletions staff/miguel-arias/project/api/handlers/redeemPointsHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import jwt from 'jsonwebtoken'
const {JsonWebTokenError} = jwt

import { errors } from 'com'
const { NotFoundError, ContentError, TokenError } = errors

import logic from '../logic/index.js'

export default async (req, res) => {
const token = req.headers.authorization.substring(7)
const payload = jwt.verify(token, process.env.JWT_SECRET)
const sessionProfileId = payload.sub

const { points } = req.body

const { profileId } = req.params

try {
await logic.redeemPoints(sessionProfileId, profileId, points)
} catch (error) {
let status = 500

if (error instanceof JsonWebTokenError) {
status = 401
error = new TokenError(error.message)
}

if (error instanceof NotFoundError)
status = 404

if (error instanceof ContentError || error instanceof TypeError)
status = 406

res.status(status).json({ error: error.constructor.name, message: error.message })
}

res.status(204).send()
}
3 changes: 3 additions & 0 deletions staff/miguel-arias/project/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
retrieveTemplatesHandler,
retrieveRoomsHandler,
createTemplateHandler,
redeemPointsHandler,
} from './handlers/index.js'

mongoose.connect(process.env.MONGODB_URL)
Expand Down Expand Up @@ -60,6 +61,8 @@ mongoose.connect(process.env.MONGODB_URL)

server.get('/rooms', retrieveRoomsHandler)

server.patch('/stats/:profileId/redeem', jsonBodyParser, redeemPointsHandler)

const date = new Date()
server.listen(process.env.PORT, () => console.log(`Server is online at ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()} in port ${process.env.PORT}`))
})
Expand Down
2 changes: 1 addition & 1 deletion staff/miguel-arias/project/api/logic/delayTask.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { validate, errors } from 'com'
const { SystemError, NotFoundError } = errors

import { Task } from '../data/models.js'
import { Task, Profile } from '../data/models.js'

function delayTask(profileId, taskId, date) {
validate.id(profileId, 'profile id')
Expand Down
2 changes: 2 additions & 0 deletions staff/miguel-arias/project/api/logic/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import deleteTask from './deleteTask.js'
import retrieveRooms from './retrieveRooms.js'
import createTemplate from './createTemplate.js'
import completeTask from './completeTask.js'
import redeemPoints from './redeemPoints.js'

const logic = {
registerHome,
Expand All @@ -30,6 +31,7 @@ const logic = {
retrieveRooms,
createTemplate,
completeTask,
redeemPoints,
}

export default logic
45 changes: 45 additions & 0 deletions staff/miguel-arias/project/api/logic/redeemPoints.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { validate, errors } from 'com'
const { SystemError, NotFoundError, PermissionError } = errors

import { Task, Profile } from '../data/models.js'

function delayTask(sessionProfileId, profileId, points) {
validate.id(sessionProfileId, 'session profile id')
validate.id(profileId, 'profile id')
validate.number(points, 'points')

return (async () => {
let sessionProfile
try {
sessionProfile = await Profile.findById(sessionProfileId).lean()
} catch (error) {
throw new SystemError(error.message)
}

if (!sessionProfile)
throw new NotFoundError('session profile not found')

if (sessionProfile.role !== 'admin')
throw new PermissionError('session profile is not admin')

let profile
try {
profile = await Profile.findById(profileId)
} catch (error) {
throw new SystemError(error.message)
}

if (!profile)
throw new NotFoundError('profile not found')

profile.points -= points

try {
await profile.save()
} catch (error) {
throw new SystemError(error.message)
}
})()
}

export default delayTask
16 changes: 16 additions & 0 deletions staff/miguel-arias/project/api/logic/redeemPoints.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import mongoose from 'mongoose'
import redeemPoints from './redeemPoints.js'

(async () => {
try {
await mongoose.connect('mongodb://127.0.0.1:27017/test')

await redeemPoints('65d79ed43377222a97582a1a', '65d79ed33377222a97582a18', 15)

console.log('points redeemed')

await mongoose.disconnect()
} catch (error) {
console.log(error)
}
})()
4 changes: 1 addition & 3 deletions staff/miguel-arias/project/app/src/components/Calendar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,8 @@ function Calendar(props) {
event.preventDefault()
const date = event.target.delayDate.value
const dateObject = date ? new Date(date) : null

const taskId = event.nativeEvent.submitter.value
try {
await logic.delayTask(taskId, dateObject)
await logic.delayTask(task.id, dateObject)
refreshTasks()
setView(null)
} catch (error) {
Expand Down
31 changes: 28 additions & 3 deletions staff/miguel-arias/project/app/src/components/Stats.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { useEffect, useState } from 'react'
import { useContext } from '../hooks'
import { Button, Container } from '../library'
import { Button, Container, Input, Form } from '../library'

import logic from '../logic'

function Stats(props) {
const context = useContext()

const [profiles, setProfiles] = useState([])
const [profile, setProfile] = useState(null)
const [view, setView] = useState(null)

const refreshProfiles = async () => {
try {
Expand All @@ -19,6 +21,23 @@ function Stats(props) {
}
}

const handleRedeemPointsClick = (profileId) => {
setProfile(profileId)
setView('redeem-points-view')
}

const handleRedeemPointsSubmit = async (event) => {
event.preventDefault()
const points = Number(event.target.points.value)
try {
await logic.redeemPoints(profile, points)
refreshProfiles()
setView(null)
} catch (error) {
context.handleError(error)
}
}

useEffect(() => {
console.log('Profiles effect')

Expand All @@ -28,9 +47,15 @@ function Stats(props) {
return <Container>
<h1>Statistics</h1>

{profiles.map(profile => <Container> <p>{profile.name} {profile.points ? profile.points : '0'}</p> {profile.points &&<Button>Redeem points</Button>}</Container>)}
{profiles.map(profile => <Container> <p>{profile.name} {profile.points ? profile.points : '0'}</p> {props.role === 'admin' &&profile.points && <Button key={profile.id} onClick={() => handleRedeemPointsClick(profile.id)}>Redeem points</Button>}</Container>)}

{/* user, puntos y botón de redeem points */}
{view === 'redeem-points-view' && <Container>
<Form onSubmit={handleRedeemPointsSubmit}>
<Input id='points' type='number' placeholder={'Points to redeem'} required={true}></Input>
<Button type='submit'>Redeem!</Button>
<Button type='button'>Cancel</Button>
</Form>
</Container>}

</Container>
}
Expand Down
18 changes: 11 additions & 7 deletions staff/miguel-arias/project/app/src/components/Template.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import { Button } from '../library'

import logic from '../logic'
import helper from '../logic/helpers'

function Template(props) {
const template = props.template

const arrangeText = (text) => {
let capital = text[0].toUpperCase()
let newText = capital + text.slice(1)
return newText.replace("-", " ")
const handleDeleteClick = async () => {
try {
await logic.deleteTemplate(template.id)
} catch (error) {

}
}

return <article>
<h3>{arrangeText(template.name)}</h3>
<h3>{helper.arrangeText(template.name)}</h3>

{props.role === 'admin' && <aside>
<Button>Edit task</Button>
<Button>Store task</Button>
<Button>Delete task</Button>
<Button onClick={handleDeleteClick}>Delete template</Button>
</aside>}
</article>
}
Expand Down
2 changes: 1 addition & 1 deletion staff/miguel-arias/project/app/src/logic/delayTask.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { SystemError } = errors

import session from './session'

const delayTask = (date) => {
const delayTask = (taskId, date) => {
validate.id(taskId, 'task id')
validate.date(date)

Expand Down
2 changes: 2 additions & 0 deletions staff/miguel-arias/project/app/src/logic/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import deleteTask from './deleteTask.js'
import completeTask from './completeTask.js'
import retrieveRooms from './retrieveRooms.js'
import createTemplate from './createTemplate.js'
import redeemPoints from './redeemPoints.js'

const logic = {
registerHome,
Expand All @@ -34,6 +35,7 @@ const logic = {
completeTask,
retrieveRooms,
createTemplate,
redeemPoints,
}

export default logic
41 changes: 41 additions & 0 deletions staff/miguel-arias/project/app/src/logic/redeemPoints.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { validate, errors } from 'com'
const { SystemError } = errors

import session from './session'

const redeemPoints = (profileId, points) => {
validate.id(profileId, 'profile id')
validate.number(points, 'points')

const req = {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${session.profileToken}`
},
body: JSON.stringify({ points })
}

return (async () => {
let res
try {
res = await fetch(`${import.meta.env.VITE_API_URL}/stats/${profileId}/redeem`, req)
} catch (error) {
throw new SystemError(error.message)
}

if (!res.ok) {
let body

try {
body = await res.json()
} catch (error) {
throw new SystemError(error.message)
}

throw new errors[body.error](body.message)
}
})()
}

export default redeemPoints
2 changes: 2 additions & 0 deletions staff/miguel-arias/project/doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ Order

## Future versions will include:

##### Store tasks (instead of deletion)

##### Alternatives to pincode (version 2)

* Fingerprint
Expand Down

0 comments on commit becc2ba

Please sign in to comment.