-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial implementation of guidance records
- Loading branch information
Showing
9 changed files
with
532 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
const { PrismaClient, user_type, user_approval_type } = require("@prisma/client"); | ||
const prisma = new PrismaClient(); | ||
const express = require('express'); | ||
const { isAuthenticated } = require("../middlewares"); | ||
const { findUserIdByAccessToken } = require("../routes/users.services"); | ||
|
||
const router = express.Router(); | ||
|
||
router.get("/records", async (req, res, next) => { | ||
try { | ||
const authorizationheader = req.headers.authorization; | ||
|
||
const token = authorizationheader.replace('Bearer ', ''); | ||
const userId = findUserIdByAccessToken(token) | ||
const medRecordsToGet = await prisma.guidanceRecord.findMany({ | ||
where: { | ||
userId: userId | ||
} | ||
}) | ||
res.json(medRecordsToGet) | ||
} catch (err) { | ||
console.error(err); | ||
res.status(500).json({ error: "an error occurred!" }); | ||
} | ||
}); | ||
|
||
router.get("/records-by/:id", isAuthenticated, async (req, res, next) => { | ||
try { | ||
const { id } = req.params | ||
const authorizationheader = req.headers.authorization | ||
|
||
const token = authorizationheader.replace('Bearer ', '') | ||
const userId = findUserIdByAccessToken(token) | ||
|
||
const user = await prisma.user.findUnique({ | ||
where: { | ||
id: userId, | ||
approved: { not: user_approval_type.Archived } | ||
}, | ||
select: { | ||
type: true | ||
} | ||
}); | ||
if (user.type == user_type.Student) { | ||
res.sendStatus(401) | ||
return | ||
} | ||
|
||
const medRecordsToGet = await prisma.guidanceRecord.findMany({ | ||
where: { | ||
userId: id | ||
} | ||
}) | ||
res.json(medRecordsToGet) | ||
} catch (err) { | ||
console.error(err); | ||
res.json({ error: err.message }); | ||
} | ||
}); | ||
|
||
router.get("/users", async (req, res, next) => { | ||
try { | ||
const users = await prisma.user.findMany({ | ||
where: { | ||
approved: { not: user_approval_type.Archived } | ||
}, | ||
select: { | ||
id: true, | ||
fname: true, | ||
mname: true, | ||
lname: true, | ||
type: true | ||
} | ||
}) | ||
res.json(users) | ||
} catch (err) { | ||
console.error(err); | ||
res.status(500).json({ error: "an error occurred!" }); | ||
} | ||
}); | ||
|
||
router.post("/record", async (req, res, next) => { | ||
try { | ||
const data = req.body | ||
|
||
const record = await prisma.guidanceRecord.create({ | ||
data: data, | ||
include: { | ||
user: true, | ||
} | ||
}); | ||
const authorizationheader = req.headers.authorization; | ||
const token = authorizationheader.replace('Bearer ', ''); | ||
const userId = findUserIdByAccessToken(token) | ||
const user = await prisma.user.findUnique({ | ||
where: { | ||
id: userId | ||
} | ||
}) | ||
createNotification({ | ||
title: `Guidance Record Added`, | ||
message: `Guidance Record created by ${user.login_username} for ${record.user.login_username}`, | ||
users: [record.user] | ||
}) | ||
getSocketInstance().to(record.userId).emit("notify", { | ||
title: `Guidance Record Added`, | ||
message: `Guidance Record created by ${user.login_username} for ${record.user.login_username}`, | ||
}) | ||
getSocketInstance().emit("update guidance records") | ||
res.json(record); | ||
} catch (error) { | ||
console.error(error); | ||
res | ||
.status(500) | ||
.json({ error: "An error occurred while creating a guidance record" }); | ||
|
||
} | ||
}) | ||
|
||
module.exports = router |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
149 changes: 149 additions & 0 deletions
149
src-frontend-react/src/components/GuidanceRecords/GuidanceRecordsForm/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import { useEffect, useState } from 'react'; | ||
import { Form, Button, Stack } from 'react-bootstrap'; | ||
import Select from 'react-select' | ||
|
||
import LoadingOverlay from 'react-loading-overlay-ts'; | ||
import { customFetch } from '../../../utils'; | ||
import { toast } from 'react-toastify'; | ||
|
||
const DEFAULT_FORM_VALUES = { | ||
userId: '', | ||
content: '', | ||
} | ||
|
||
const DEFAULT_SELECT_VALUE = { value: 0, label: "Please pick a user" } | ||
|
||
export const GuidanceRecordsForm = () => { | ||
const [usersList, setUsersList] = useState([]) | ||
|
||
const [usersListOptions, setUsersListOptions] = useState([]) | ||
const [selectedUser, setSelectedUser] = useState({ ...DEFAULT_SELECT_VALUE }) | ||
|
||
const [formData, setFormData] = useState({ ...DEFAULT_FORM_VALUES }); | ||
const [formErrors, setFormErrors] = useState({ ...DEFAULT_FORM_VALUES }); | ||
|
||
const [isLoading, setIsLoading] = useState(true) | ||
|
||
const resetToDefault = () => { | ||
setFormData({ ...DEFAULT_FORM_VALUES }) | ||
setFormErrors({ ...DEFAULT_FORM_VALUES }) | ||
setSelectedUser({ ...DEFAULT_SELECT_VALUE }) | ||
} | ||
|
||
const fetchAll = () => { | ||
setIsLoading(true) | ||
customFetch(`${global.server_backend_url}/backend/guidancerecords/users`) | ||
.then((response) => { | ||
if (response.ok) return response.json(); | ||
else throw response; | ||
}) | ||
.then((data) => { | ||
setUsersList(data) | ||
setIsLoading(false) | ||
return data; | ||
}) | ||
} | ||
|
||
const validateForm = () => { | ||
let isValid = true; | ||
const newFormErrors = { ...formErrors }; | ||
console.log(selectedUser.value) | ||
|
||
if (!selectedUser.value) { | ||
newFormErrors.userId = 'Select user first' | ||
isValid = false; | ||
} else newFormErrors.userId = ''; | ||
|
||
|
||
if (formData.content.trim() === '') { | ||
newFormErrors.content = 'Content is required'; | ||
isValid = false; | ||
} else newFormErrors.content = ''; | ||
|
||
setFormErrors(newFormErrors); | ||
return isValid; | ||
|
||
} | ||
|
||
const handleUserSelectionChange = (e) => { | ||
setSelectedUser({ value: e.value, label: e.label }) | ||
} | ||
|
||
const handleChange = (e) => { | ||
const { name, value } = e.target; | ||
setFormData({ | ||
...formData, | ||
[name]: value, | ||
}); | ||
}; | ||
|
||
const handleSubmit = (e) => { | ||
e.preventDefault(); | ||
|
||
if (validateForm()) { | ||
|
||
const formatted = { | ||
content: formData.content, | ||
userId: selectedUser.value.id | ||
} | ||
|
||
customFetch(`${global.server_backend_url}/backend/guidancerecords/record`, { | ||
method: 'POST', | ||
body: JSON.stringify(formatted) | ||
}).then((response) => { | ||
fetchAll() | ||
resetToDefault() | ||
if (response.ok) { | ||
return response.json(); | ||
} else throw response; | ||
}).then((data) => { | ||
toast(`Successfully added guidance records for ${data.user.lname}`) | ||
}).catch((err) => { | ||
console.log(err) | ||
}).finally(() => { | ||
fetchAll() | ||
}) | ||
} | ||
} | ||
|
||
useEffect(() => { | ||
fetchAll() | ||
}, []) | ||
|
||
useEffect(() => { | ||
setUsersListOptions([...usersList.map((user) => { | ||
return { value: user, label: `[${user.type}] ${user.lname}, ${user.fname} ${user.mname ? user.mname[0] + "." : ""}` } | ||
})]) | ||
console.log(usersList) | ||
}, [usersList]) | ||
|
||
return ( | ||
<LoadingOverlay active={isLoading} spinner text="Waiting for update"> | ||
<Form onSubmit={handleSubmit}> | ||
<Select className='fs-5' options={usersListOptions} value={selectedUser} onChange={handleUserSelectionChange} /> | ||
<div className="text-danger mb-3">{formErrors.userId}</div> | ||
<Form.Group controlId="content" className="mb-3"> | ||
<Form.Label>Guidance Record Contents</Form.Label> | ||
<Form.Control | ||
type="text" | ||
as={'textarea'} | ||
rows={5} | ||
name="content" | ||
value={formData.content} | ||
onChange={handleChange} | ||
required | ||
/> | ||
<div className="text-danger">{formErrors.content}</div> | ||
</Form.Group> | ||
<Stack direction="horizontal" className="gap-3 justify-content-between"> | ||
<Button className="mt-2" variant="primary" type="submit"> | ||
Create Guidance Record | ||
</Button> | ||
<Button variant="danger" className={`${formData.id ? '' : 'invisible'}`}> | ||
Delete | ||
</Button> | ||
</Stack> | ||
</Form> | ||
</LoadingOverlay> | ||
) | ||
} |
Oops, something went wrong.