Skip to content

Commit

Permalink
Merge pull request #76 from 4GeeksAcademy/YuneDev
Browse files Browse the repository at this point in the history
Merge Yunedev into dev
  • Loading branch information
yjchf authored Dec 17, 2024
2 parents 4321cc9 + bae64f8 commit e66b0ab
Show file tree
Hide file tree
Showing 21 changed files with 622 additions and 96 deletions.
15 changes: 14 additions & 1 deletion src/api/routes/admin_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from api.schemas.schemas import TeacherSchema, UserSchema, AuthorizedEmailSchema, StudentSchema, MateriasSchema, DocenteMateriaSchema, GradoSchema, RoleSchema
from datetime import datetime
from api.services.generic_services import create_instance, delete_instance, get_all_instances, update_instance, get_instance_by_id
from api.services.external_services import get_image


app = Flask(__name__)
Expand Down Expand Up @@ -84,7 +85,19 @@ def get_users():

@admin_routes.route('/info', methods=['GET'])
def get_user_info():
return get_instance_by_id(User, user_schema, get_jwt_identity())
user = User.query.get(get_jwt_identity())

if not user:
return jsonify({"msg": "User not found"}),401

user_data = user_schema.dump(user)
user_data.pop("id")
user_data.pop("is_active")
user_data.pop("role_id")
user_data["foto"] = get_image(user.foto) if user.foto else ""


return jsonify(user_data),200

# ////////////////////////////// Teachers Endpoints CRUD ////////////////////
@admin_routes.route('/teachers', methods=['POST'])
Expand Down
4 changes: 2 additions & 2 deletions src/api/routes/parent_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
"""
from flask import Flask, request, jsonify, Blueprint

from api.models import User,db, Role, Estudiante
from api.models import User, Role
from flask_cors import CORS
from flask_jwt_extended import get_jwt, verify_jwt_in_request, get_jwt_identity
from api.services.parent_services import get_students_info
from api.services.generic_services import get_feriadosAPI, get_schedule
from api.services.generic_services import get_schedule
from api.services.external_services import get_image
from api.schemas.schemas import UserSchema

Expand Down
1 change: 0 additions & 1 deletion src/api/routes/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ def handle_logout():
@jwt_required()
def handle_profile_pic():
user = User.query.get(get_jwt_identity())
print(request.files)
body = request.files["profilePicture"]

if not user:
Expand Down
2 changes: 2 additions & 0 deletions src/api/routes/teacher_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from api.schemas.schemas import TeacherSchema, MateriasSchema, EvaluacionSchema, GradoSchema, StudentSchema, CalificacionSchema
from api.services.generic_services import create_instance, update_instance, delete_instance
from api.services.teacher_services import get_califications, post_update_califications
from api.services.external_services import get_image

app = Flask(__name__)

Expand Down Expand Up @@ -55,6 +56,7 @@ def get_personal_info():
docente_info = teacher_schema.dump(docente)
docente_info["materias"] = materias_schema.dump(materias)
docente_info["grados"] = grados_schema.dump(grados)
docente_info["foto"] = get_image(docente.foto) if docente.foto else ""

return jsonify(docente_info),200

Expand Down
54 changes: 52 additions & 2 deletions src/api/services/parent_services.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from flask import jsonify
from sqlalchemy.exc import SQLAlchemyError
from api.models import User, Estudiante
from api.models import Docente, DocenteMaterias, User, Estudiante, Materias
from marshmallow import ValidationError


Expand Down Expand Up @@ -35,6 +35,54 @@ def get_student_resume(parent_id):
return data


def get_student_review(student_id,materia):

student = Estudiante.query.get(student_id, materia)

student = Estudiante.query.get(student_id)
materia = Materias.query.filter(Materias.nombre.ilike(materia)).first()

if not (student and materia):
return jsonify({"msg": "Not Found"}),404

evaluaciones = [
{
"evaluacion": calificacion.evaluacion.nombre,
"descripcion": calificacion.evaluacion.descripcion,
"nota": calificacion.nota,
"fecha": calificacion.evaluacion.fecha,
"profesor": f"{calificacion.evaluacion.profesor.nombre} {calificacion.evaluacion.profesor.apellido}"
}
for calificacion in student.calificaciones if calificacion.evaluacion.materia_id == materia.id
]

data = []
try:
for child in student:
student_info = {
"nombre": f"{child.nombre} {child.apellido}",
"grado": child.grado.nombre,
"materias": [materia.nombre for materia in child.grado.materias],
"evaluaciones": [
{
"evaluacion": calificacion.evaluacion.nombre,
"descripcion": calificacion.evaluacion.descripcion,
"nota": calificacion.nota,
"fecha": calificacion.evaluacion.fecha,
"profesor": f"{calificacion.evaluacion.profesor.nombre} {calificacion.evaluacion.profesor.apellido}"
}
for calificacion in child.calificaciones
]
}
data.append(student_info)
except Exception as e:
print(str(e))
return jsonify({"msg": "Error collecting student data"}), 500

return evaluaciones





def get_students_info(parent_id):
Expand All @@ -50,11 +98,13 @@ def get_students_info(parent_id):
"nombre": f"{child.nombre} {child.apellido}",
"fecha_nacimiento": child.fecha_nacimiento,
"grado": child.grado.nombre,
"materias": [materia.nombre for materia in child.grado.materias],
"materias": [[materia.nombre, materia.id] for materia in child.grado.materias],
"calificaciones": [
{
"evaluacion": calificacion.evaluacion.nombre,
"materia": calificacion.evaluacion.materia.nombre,
"id_materia":calificacion.evaluacion.materia.id,
"descripcion": calificacion.evaluacion.descripcion,
"nota": calificacion.nota,
"fecha": calificacion.evaluacion.fecha,
"profesor": f"{calificacion.evaluacion.profesor.nombre} {calificacion.evaluacion.profesor.apellido}"
Expand Down
4 changes: 2 additions & 2 deletions src/front/js/component/Navbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Context } from "../store/appContext";
const NavBar = () => {
const { store, actions } = useContext(Context);
const navigate = useNavigate();
const { token, unreadCount, role, personalInfo } = store;
const { token, unreadCount, role, personalInfo, profesorPersonalInfo } = store;

useEffect(() => {
actions.getMessages();
Expand Down Expand Up @@ -64,7 +64,7 @@ const NavBar = () => {
<Dropdown align="end">
<Dropdown.Toggle as="div" className={`${styles.Toggle}`}>
<Avatar
src={personalInfo?.foto || defaultAvatar}
src={personalInfo?.foto || profesorPersonalInfo?.foto || defaultAvatar}
alt="User Avatar"
size={40}
className={`${styles["navbar-avatar"]}`}
Expand Down
10 changes: 8 additions & 2 deletions src/front/js/component/ProfileForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Spinner } from "react-bootstrap";
import { useContext } from "react";
import { Context } from "../store/appContext.js";

const Container = styled.div`
export const Container = styled.div`
display: flex;
flex-direction: column;
width: 95%;
Expand Down Expand Up @@ -183,7 +183,13 @@ const ProfileForm = ({ user }) => {
delete newData.estudiantes;
delete newData.calendario;
delete newData.statusResume;
setIsTeacher(store.role == "docente" ? true : false);
if (store.role == "docente") {
setIsTeacher(true);
delete newData.msg;
delete newData.materias;
delete newData.grados;
delete newData.id;
}
setUserData(newData);
}
}, [user]);
Expand Down
71 changes: 71 additions & 0 deletions src/front/js/component/ShowSubject.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { useState, useEffect } from 'react'
import styled from 'styled-components'
import ProgressBar from 'react-bootstrap/ProgressBar'
import Collapse from 'react-bootstrap/Collapse';

const StyledProgresBar = styled(ProgressBar)`
height: 45%;
width: 40%;
margin: 0 auto;
border: 1px solid grey;
`



export const Progress = (value = 5, min = 0, max = 20) => {
let variant = "success"

if (value < 10) {
variant = "danger"
} else if (value < 15) {
variant = "warning"
} else if (value < 18) {
variant = 'info'
}



return <StyledProgresBar min={min} max={max} now={value} variant={variant} />

}



const ShowSubjectTests = ({ name, grade, description, date }) => {
const [isOpen, setIsOpen] = useState(false)





return (
<div className="container-fluid ">
<div className="row mb-2 mt-2">
<div className="col-4 d-flex justify-content-start align-items-center text-truncate" onClick={() => setIsOpen(!isOpen)}>
<i className={`bi bi-caret-${isOpen ? "up" : "down"}-fill me-1 d-none d-md-block`}></i> {name}
</div>
<div className='col-4 d-flex justify-content-center align-items-center'>
{Progress(grade)}
</div>
<div className='col-4 d-flex justify-content-end align-items-center'>
{grade.toFixed(2)}
</div>
</div>
<Collapse in={isOpen}>
<div className='row'>
<div className='col-8'>
<p className="text-light">
{description}
</p>
</div>
<div className="col-4 text-end">
{date.split(" ").slice(0, 4).join(" ")}
</div>
</div>
</Collapse>

</div>
)
}

export default ShowSubjectTests
2 changes: 1 addition & 1 deletion src/front/js/component/chatComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Context } from "../store/appContext";
import "bootstrap/dist/css/bootstrap.min.css";
import styles from "../../styles/Navbar.module.css";
import Swal from "sweetalert2";
import { height } from "@fortawesome/free-solid-svg-icons/fa0";


const ChatComponent = ({ userRole, userName, userAvatar }) => {
const { store, actions } = useContext(Context);
Expand Down
49 changes: 43 additions & 6 deletions src/front/js/component/leftMenuAdmin.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import React, { useState, useContext, useEffect, useRef } from "react";
import { Context } from "../store/appContext";
import { Link, useNavigate, useLocation } from "react-router-dom";
import { Link, useLocation, useNavigate, Route, Routes } from "react-router-dom";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import backgroundForViews from "../../img/background.jpg";
import imgWelcome from "../../img/wellcomeicon.png"
import "../../styles/components.css";
import Swal from 'sweetalert2';
import ChatComponent from "../component/chatComponent";
import ProfileForm from "./ProfileForm.jsx";

const FormCommon = ({ type }) => {
const navigate = useNavigate()
const location = useLocation()
const { store, actions } = useContext(Context)
const [startDate, setStartDate] = useState(new Date());
const [formBody, setFormBody] = useState({
Expand All @@ -28,6 +30,8 @@ const FormCommon = ({ type }) => {
});

useEffect(() => {


if (type === 'student') {
actions.getCourses();
}
Expand Down Expand Up @@ -411,9 +415,10 @@ const FormCommon = ({ type }) => {
};

export const LeftMenuAdmin = () => {
const navigate = useNavigate()
const location = useLocation()
const [activeContent, setActiveContent] = useState(null);
const { store } = useContext(Context)
const location = useLocation();
const { store, actions } = useContext(Context)
const messagingDivRef = useRef(null);
useEffect(() => {
if (location.state?.scrollTo === "Mensajería" && messagingDivRef.current) {
Expand Down Expand Up @@ -454,6 +459,13 @@ export const LeftMenuAdmin = () => {
}

const renderContent = () => {
if (location.pathname.includes("profile")) {
return (<Routes>
<Route path={"/profile"} element={<ProfileForm user={store.personalInfo} />} />
</Routes>
)
}

switch (activeContent) {
case "estudiantes":
return <FormCommon type="student" />;
Expand Down Expand Up @@ -486,6 +498,29 @@ export const LeftMenuAdmin = () => {
}
};


useEffect(() => {
const fetchPersonalData = async () => {
await actions.getAdminInfo()

}

if (!store.personalInfo) {
fetchPersonalData()
}

}, [store.personalInfo])


useEffect(() => {

if (location.pathname != "/dashboard/admin/") {
navigate("/dashboard/admin/")
}


}, [activeContent])

return (
<div className="mt-0">
<div className="row flex-nowrap mt-5" >
Expand Down Expand Up @@ -574,9 +609,11 @@ export const LeftMenuAdmin = () => {
<div className="render-content col mt-3 py-3 "
style={{ backgroundImage: `url(${backgroundForViews})`, backgroundSize: "cover" }}>
<div>
<div className="welcome-message mt-5 ms-auto me-auto">
{renderContent()}
</div>
{location.pathname.includes("profile") ? renderContent() :
<div className="welcome-message mt-5 ms-auto me-auto">
{renderContent()}
</div>
}
<div id="Mensajería" ref={messagingDivRef}>
{store.isChatVisible && <ChatComponent />}
</div>
Expand Down
Loading

0 comments on commit e66b0ab

Please sign in to comment.