From 5f2e1fdb1bb979f863422ebdaab5aa7667b041d3 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 3 Mar 2026 09:17:50 +0100 Subject: [PATCH] Add 'opmerking' column to assessments and implement related functionality - Updated the database migration to include an 'opmerking' column in the assessments table. - Modified the Assessment model to include the new 'opmerking' field. - Enhanced the API to handle saving and retrieving remarks associated with assessments. - Updated the frontend to display and edit remarks in the assessments table. --- .../versions/0002_assessment_opmerking.py | 2 +- backend/models.py | 2 + backend/routes/api.py | 60 ++- backend/templates/directeur.html | 352 ++++++++++++++---- backend/templates/leerkracht.html | 79 +++- 5 files changed, 409 insertions(+), 86 deletions(-) diff --git a/backend/migrations/versions/0002_assessment_opmerking.py b/backend/migrations/versions/0002_assessment_opmerking.py index cdb8016..73fa0cb 100644 --- a/backend/migrations/versions/0002_assessment_opmerking.py +++ b/backend/migrations/versions/0002_assessment_opmerking.py @@ -1,4 +1,4 @@ -"""assessment: voeg opmerking kolom toe +"""assessment: voeg opmerking kolom toe Revision ID: 0002 Revises: 0001 diff --git a/backend/models.py b/backend/models.py index 6600c6e..424fa09 100644 --- a/backend/models.py +++ b/backend/models.py @@ -151,6 +151,7 @@ class Assessment(db.Model): vak_id = db.Column(db.String(50), nullable=False) goal_id = db.Column(db.String(50), nullable=False) status = db.Column(db.String(10), nullable=False) + opmerking = db.Column(db.String(500), nullable=True) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) user = db.relationship('User') @@ -167,6 +168,7 @@ class Assessment(db.Model): 'vak_id': self.vak_id, 'goal_id': self.goal_id, 'status': self.status, + 'opmerking': self.opmerking, 'updated_at': self.updated_at.isoformat() if self.updated_at else None, } diff --git a/backend/routes/api.py b/backend/routes/api.py index 3246280..4b5336d 100644 --- a/backend/routes/api.py +++ b/backend/routes/api.py @@ -70,10 +70,11 @@ def get_assessments(): @login_required @limiter.limit('120 per minute') # max 2 per seconde per gebruiker def save_assessment(): - data = request.get_json() or {} - vak_id = (data.get('vak_id') or '').strip() - goal_id = (data.get('goal_id') or '').strip() - status = (data.get('status') or '').strip() + data = request.get_json() or {} + vak_id = (data.get('vak_id') or '').strip() + goal_id = (data.get('goal_id') or '').strip() + status = (data.get('status') or '').strip() + opmerking = (data.get('opmerking') or '').strip()[:500] if not vak_id or not goal_id: return jsonify({'error': 'vak_id en goal_id zijn verplicht'}), 400 @@ -104,6 +105,7 @@ def save_assessment(): if assessment: assessment.status = status + assessment.opmerking = opmerking or None assessment.updated_at = datetime.utcnow() else: assessment = Assessment( @@ -113,6 +115,7 @@ def save_assessment(): vak_id=vak_id, goal_id=goal_id, status=status, + opmerking=opmerking or None, ) db.session.add(assessment) @@ -124,6 +127,55 @@ def save_assessment(): return jsonify({'assessment': assessment.to_dict()}) + + +@api_bp.route('/assessments/opmerking', methods=['POST']) +@login_required +@limiter.limit('120 per minute') +def save_opmerking(): + """Sla enkel een opmerking op bij een bestaand of nieuw assessment record.""" + data = request.get_json() or {} + vak_id = (data.get('vak_id') or '').strip() + goal_id = (data.get('goal_id') or '').strip() + opmerking = (data.get('opmerking') or '').strip()[:500] + + if not vak_id or not goal_id: + return jsonify({'error': 'vak_id en goal_id zijn verplicht'}), 400 + if len(vak_id) > 100 or len(goal_id) > 50: + return jsonify({'error': 'Ongeldige invoer'}), 400 + if not current_user.school_id: + return jsonify({'error': 'Account niet gekoppeld aan een school'}), 400 + + school_year = get_active_year(current_user.school_id) + if not school_year: + return jsonify({'error': 'Geen actief schooljaar'}), 400 + + assessment = Assessment.query.filter_by( + user_id=current_user.id, + school_year_id=school_year.id, + vak_id=vak_id, + goal_id=goal_id, + ).first() + + if assessment: + assessment.opmerking = opmerking or None + assessment.updated_at = datetime.utcnow() + else: + # Maak een record aan zonder status voor de opmerking + assessment = Assessment( + user_id=current_user.id, + school_id=current_user.school_id, + school_year_id=school_year.id, + vak_id=vak_id, + goal_id=goal_id, + status='', + opmerking=opmerking or None, + ) + db.session.add(assessment) + + db.session.commit() + return jsonify({'ok': True}) + @api_bp.route('/assessments/bulk-import', methods=['POST']) @login_required @limiter.limit('5 per minute') diff --git a/backend/templates/directeur.html b/backend/templates/directeur.html index 47dce0b..c2c3771 100644 --- a/backend/templates/directeur.html +++ b/backend/templates/directeur.html @@ -82,6 +82,36 @@ /* Leerkrachten beheer */ .teacher-list { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem; } .teacher-chip { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.75rem; background: var(--gray-100); border-radius: 9999px; font-size: 0.85rem; } + .teacher-chip .name { font-weight: 500; } + .teacher-chip .klas { color: var(--gray-500); } + .teacher-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; } + + /* Leerkrachten sectie */ + .teachers-section { background: white; border-radius: 12px; padding: 1.5rem; margin-bottom: 1rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); } + .teachers-section h2 { font-size: 1.1rem; color: var(--gray-700); margin-bottom: 1rem; display: flex; align-items: center; gap: 0.5rem; } + .action-bar { display: flex; gap: 0.5rem; flex-wrap: wrap; } + + /* Statistieken */ + .stats-overview { background: white; border-radius: 12px; padding: 1.5rem; margin-bottom: 1rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); } + .stats-overview h2 { font-size: 1.1rem; color: var(--gray-700); margin-bottom: 1rem; } + + /* Vak statistieken */ + .vak-stats h2 { font-size: 1.1rem; color: var(--gray-700); margin-bottom: 1rem; } + .vak-card { background: var(--gray-50); border-radius: 8px; padding: 1rem; margin-bottom: 0.75rem; } + .vak-card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem; } + .vak-card-header h3 { font-size: 1rem; color: var(--gray-800); } + .vak-card-header .percentage { font-weight: 600; color: var(--primary); } + .vak-card-stats { display: flex; gap: 1rem; font-size: 0.8rem; color: var(--gray-600); } + .vak-card-stats span { display: flex; align-items: center; gap: 0.25rem; } + .dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; } + .dot-groen { background: var(--status-groen); } + .dot-oranje { background: var(--status-oranje); } + .dot-roze { background: var(--status-roze); } + + /* Progress bars vak stats */ + .progress-groen { background: var(--status-groen); } + .progress-oranje { background: var(--status-oranje); } + .progress-roze { background: var(--status-roze); } .modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center; } .modal-overlay.active { display: flex; } .modal { background: white; border-radius: 12px; padding: 1.5rem; max-width: 450px; width: 90%; } @@ -198,6 +228,14 @@ /* Vak indicator */ .vak-indicator { /* gradient blijft, ziet er goed uit */ } + /* Nieuwe layout blokken */ + .teachers-section { background: #1e293b !important; } + .stats-overview { background: #1e293b !important; } + .teacher-chip { background: #334155 !important; color: #e2e8f0 !important; } + .teacher-chip .klas { color: #94a3b8 !important; } + .vak-card-header h3 { color: #e2e8f0 !important; } + .vak-card-stats { color: #94a3b8 !important; } + /* Progress bars achtergrond */ .progress-bar { background: #334155 !important; } @@ -245,10 +283,12 @@
+ +
-

🏫 Directeur Dashboard

-
+

🏫 Directeur Dashboard v4.0

+
Schooloverzicht van alle leerdoelen en leerkrachten
@@ -263,23 +303,48 @@
- -
-
-
Leerkrachten
-
-
Vakken
-
-
Beoordelingen
-
-
Groen
-
-
Oranje
-
-
Roze
+ +
+

πŸ“Š Schoolbrede statistieken

+
+
-
Leerkrachten
+
-
Vakken
+
-
Beoordelingen
+
-
Groen
+
-
Oranje
+
-
Roze
+
- -
-
-

πŸ‘©β€πŸ« Leerkrachten

+ +
+

+ + + + + + + Leerkrachten +

+
+
+ +
-
Laden...
+
+ + + @@ -289,40 +354,41 @@
- +
- -
-
Legenda
-
-
-
-
- Doen we al + +
+
Legenda
+
+
+
+
+ Doen we al +
+
+
+ Doen we ongeveer +
+
+
+ Nieuw (doen we nog niet) +
+
+
+ Niet beoordeeld +
-
-
- Doen we ongeveer +
+
+
Groen = consensus
+
Oranje = gedeeltelijk
+
Roze = nog te doen
-
-
- Nieuw (doen we nog niet) -
-
-
- Niet beoordeeld -
-
-
-
-
Groen = consensus
-
Oranje = gedeeltelijk
-
Roze = nog te doen
-
+
@@ -346,9 +412,17 @@ +
+
+ +
@@ -371,6 +445,7 @@
+
@@ -381,7 +456,15 @@
-
+ + +
+
βœ“
Doen we al
+
~
Doen we ongeveer
+
!
Nieuw
+
β—‹
Niet beoordeeld
+
+
@@ -412,24 +495,22 @@
+ + + +
πŸ’‘ Gegevens worden automatisch geladen van de server.
+ +
+ - -
-