Skip to content

Assessment: Send automatic reminders to students once assessment deadline has passed#1177

Open
rappm wants to merge 28 commits intomainfrom
618-send-automatic-reminders-to-assessors-once-assessment-deadline-has-passed
Open

Assessment: Send automatic reminders to students once assessment deadline has passed#1177
rappm wants to merge 28 commits intomainfrom
618-send-automatic-reminders-to-assessors-once-assessment-deadline-has-passed

Conversation

@rappm
Copy link
Copy Markdown
Contributor

@rappm rappm commented Feb 14, 2026

📝 Pull Request Template

✨ What is the change?

This PR adds lecturer-triggered assessment reminder mails for incomplete evaluations after the configured deadline has passed.

  • Adds an Evaluation Reminder Mailing card to the assessment settings page where lecturers can save a shared reminder subject/body, review per-evaluation deadlines, and trigger reminder sends for self, peer, or tutor evaluations.
  • Adds assessment service endpoints to compute incomplete reminder recipients and send reminders only when the selected evaluation type is enabled and its deadline has passed.
  • Adds core mailing support for sending manual mails to a selected set of course participations, including placeholder replacement and delivery reporting.
  • Updates Swagger docs and adds backend test coverage for recipient resolution, reminder sending, and manual mailing.

📌 Reason for the change / Link to issue

Implements #618.

Assessment phases need a way to follow up with assessors who still have incomplete self, peer, or tutor evaluations once the configured deadline has passed. This branch adds the missing recipient calculation and mailing flow so lecturers can send targeted reminders instead of handling follow-up manually.

🧪 How to Test

  1. Start the local PROMPT stack you use for assessment development, including the core and assessment services.
  2. Open an assessment course phase as a lecturer and go to the settings page.
  3. Configure a reminder subject and content in Evaluation Reminder Mailing, making sure course mailing is configured as well.
  4. Use a course phase where a self, peer, or tutor evaluation deadline is already in the past and at least one participant still has incomplete evaluations.
  5. Trigger a reminder for that evaluation type and verify the success or failure toast together with the updated last-sent timestamp.
  6. Confirm the guards: reminder sending stays disabled when the template is incomplete, course mailing is not configured, the evaluation type is disabled, or the deadline has not passed.
  7. Run go test ./coursePhaseConfig in servers/assessment.
  8. Run go test ./mailing in servers/core.

🖼️ Screenshots (if UI changes are included)

N/A - the branch includes a small settings-page UI addition, but no screenshots were captured while preparing this PR description.

Before After
N/A N/A

✅ PR Checklist

  • Tested locally or on the dev environment
  • Code is clean, readable, and documented
  • Tests added or updated (if needed)
  • Screenshots attached for UI changes (if any)
  • Documentation updated (if relevant)

Summary by CodeRabbit

  • New Features

    • Evaluation reminder system (self/peer/tutor) with editable templates, per-type last-sent tracking, recipient counts, deadline-aware controls, and confirmation dialog for manual sends
    • Manual reminder sending with send reports (requested/successful/failed)
    • Manual mail tool to send custom templated emails to selected participants with placeholders and delivery reports
  • Documentation

    • API docs updated to include reminder and manual-mail endpoints and schemas
  • Chore

    • Added global ignore rule to exclude any .cache directories

- Introduced `AssessmentReminderCard` component to manage evaluation reminder templates.
- Integrated reminder card into the `SettingsPage`.
- Implemented functionality to save reminder templates and send evaluation reminders for self, peer, and tutor evaluations.
- Added backend support for fetching incomplete reminder recipients and sending reminder emails.
- Created new DTOs and SQL queries for managing evaluation reminder data.
- Enhanced mailing service to handle evaluation reminder sending with detailed reports on success and failure.
- Implemented SendManualMailToParticipants function to send custom emails to specified recipients.
- Created new DTOs for manual mail requests and reports.
- Added SQL scripts for testing manual mail functionality.
- Removed deprecated evaluation reminder functionality.
- Updated mailing router to handle manual mail requests.
- Added unit tests for manual mail sending, including success and error scenarios.
@rappm rappm linked an issue Feb 14, 2026 that may be closed by this pull request
2 tasks
@rappm rappm marked this pull request as draft February 14, 2026 12:30
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 14, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an evaluation reminder feature: frontend UI and network call, assessment service endpoints and DTOs for computing recipients and triggering sends, core mailing endpoint and mailer implementation, DB schema/queries, and tests across assessment and core services.

Changes

Cohort / File(s) Summary
Repo config & Frontend types
/.gitignore, clients/assessment_component/src/assessment/interfaces/evaluationReminder.ts
Add global **/.cache/ ignore and TypeScript types for reminder types, metadata, send request, and send report.
Frontend: network + Settings UI
clients/assessment_component/src/assessment/network/mutations/sendEvaluationReminder.ts, clients/assessment_component/src/assessment/pages/SettingsPage/SettingsPage.tsx, clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx, clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/*
Add sendEvaluationReminder API call; integrate and implement AssessmentReminderCard with template editor, manual-sending UI, confirmation dialog, utils, subcomponents, and tests.
Frontend: reminder config types & utils
clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/interfaces/ReminderTypeConfig.ts, .../utils.ts, .../utils.test.ts
New ReminderTypeConfig, parsing/formatting utilities, recipient-count computation, and unit tests for getReminderTypes.
Assessment: DTOs
servers/assessment/coursePhaseConfig/coursePhaseConfigDTO/evaluationReminderRecipients.go, .../evaluationReminderSend.go
Add DTOs: EvaluationReminderRecipients, SendEvaluationReminderRequest, EvaluationReminderSendReport.
Assessment: recipient discovery & sending logic
servers/assessment/coursePhaseConfig/reminderRecipients.go, servers/assessment/coursePhaseConfig/evaluationReminderSend.go
Implement recipient computation and SendEvaluationReminderManualTrigger including deadline checks, template resolution, mail orchestration, and restricted_data updates; add helpers and testable function hooks.
Assessment: router & tests
servers/assessment/coursePhaseConfig/router.go, servers/assessment/coursePhaseConfig/router_test.go, servers/assessment/coursePhaseConfig/reminderRecipients_service_test.go, servers/assessment/coursePhaseConfig/evaluationReminderSend_test.go
Expose GET /reminders/incomplete and POST /reminders/send handlers; add comprehensive tests for validation, disabled/deadline cases, and send flow.
Assessment DB test schema
servers/assessment/database_dumps/reminder_recipients_test.sql
Add enum assessment_type, course_phase_config, evaluation_completion tables and seed data for tests.
Core mailing: DTOs & mailer
servers/core/mailing/mailingDTO/manualMail.go, servers/core/mailing/manualMail.go, servers/core/mailing/manualMail_test.go
Add manual mail DTOs and SendManualMailToParticipants with placeholder rendering, per-recipient sends, deduplication, test hooks, and tests.
Core mailing: router & tests
servers/core/mailing/router.go, servers/core/mailing/router_test.go
Register POST /mailing/{coursePhaseID}/manual and handler; add tests for validation, success, and error paths.
Core DB queries & sqlc bindings
servers/core/db/query/mailing.sql, servers/core/db/sqlc/mailing.sql.go
Add GetParticipantMailingInformationByIDs and UpdateAssessmentReminderLastSentAt queries and generated Go bindings.
Core DB test data
servers/core/database_dumps/manual_mail_test.sql
Add test schema and seed data (course, phase, students, participations, mailingSettings).
API docs
servers/assessment/docs/docs.go, servers/assessment/docs/swagger.*, servers/core/docs/docs.go, servers/core/docs/swagger.*
Add OpenAPI definitions and paths for reminder endpoints and manual mailing endpoint; wire new DTOs into docs.
Misc tests & scaffolding
multiple *_test.go files across assessment and core modules
Add unit/integration tests covering recipient discovery, send flows, error cases, and utilities (deduplication, time handling).

Sequence Diagram(s)

sequenceDiagram
    participant User as Browser
    participant Frontend as Assessment UI
    participant AssessmentAPI as Assessment Service
    participant CoreAPI as Core Service
    participant DB as Database

    User->>Frontend: Open Settings → view reminder card
    Frontend->>AssessmentAPI: GET /course_phase/{id}/config/reminders/incomplete?type=...
    AssessmentAPI->>DB: Query course_phase_config & evaluation_completion
    DB-->>AssessmentAPI: Incomplete participant IDs & metadata
    AssessmentAPI-->>Frontend: EvaluationReminderRecipients
    User->>Frontend: Confirm "Send Reminder"
    Frontend->>AssessmentAPI: POST /course_phase/{id}/config/reminders/send (type=...)
    AssessmentAPI->>DB: Resolve recipients & template
    AssessmentAPI->>CoreAPI: POST /mailing/{coursePhaseID}/manual (subject, content, recipient IDs)
    CoreAPI->>DB: Get participant contact info
    DB-->>CoreAPI: Participant emails
    CoreAPI->>CoreAPI: Render templates & send emails
    CoreAPI->>DB: Update lastSentAt in course_phase.restricted_data
    CoreAPI-->>AssessmentAPI: ManualMailReport
    AssessmentAPI->>DB: Persist lastSentAtByType
    AssessmentAPI-->>Frontend: EvaluationReminderSendReport
    Frontend->>User: Show send report (success/fail)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

schau mi o

Suggested reviewers

  • Mtze
  • JGStyle
  • mathildeshagl

Poem

🐰 I nibble subject lines and stitch each mail,

I hop through deadlines down the reminder trail.
Peers, tutors, self — I call each quiet name,
Count sent and failed and tidy up the frame.
A carrot for tests — reminders sent, huzzah!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.91% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title accurately and concisely summarizes the main change: adding automatic assessment reminder capabilities to send to students after deadline passes.
Description check ✅ Passed The pull request description is comprehensive and well-structured. It follows the template with all required sections filled: change summary, reason/issue link, testing instructions, checklist completion, and includes concrete details about implementation scope and validation steps.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 618-send-automatic-reminders-to-assessors-once-assessment-deadline-has-passed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx`:
- Around line 192-212: handleSaveTemplate is calling updateCoursePhase with only
id and restrictedData, which causes the backend to receive missing name and
studentReadableData and overwrite them; fix by including the full current course
phase fields in the payload: read coursePhase.name and
coursePhase.studentReadableData (or fetch the full CoursePhase if coursePhase is
partial) and pass them along in the updateCoursePhase call along with id and
restrictedData, ensuring you send name, studentReadableData, and restrictedData
(mailingSettings.assessmentReminder) so the UpdateCoursePhase DTO is fully
populated; alternatively, if you prefer a backend change, refactor
updateCoursePhase to support true partial updates, but for this frontend fix
updateCoursePhase from handleSaveTemplate to include coursePhase.name and
coursePhase.studentReadableData.

In
`@clients/assessment_component/src/assessment/pages/SettingsPage/SettingsPage.tsx`:
- Line 104: The SettingsPage renders AssessmentReminderCard unconditionally;
gate it with the same permission check used for other admin features by wrapping
the AssessmentReminderCard in the existing isPromptAdmin || isLecturer
conditional (the boolean/props used in SettingsPage). Locate the
AssessmentReminderCard usage in SettingsPage (component SettingsPage) and only
render it when isPromptAdmin || isLecturer evaluates to true so
non-admin/lecturer users cannot access reminder-template editing or send-email
actions.

In `@servers/assessment/coursePhaseConfig/evaluationReminderSend.go`:
- Around line 113-128: The updateCoreCoursePhaseFn call can fail after emails
were sent, so enhance handling by logging the failure as a warning (including
the error and coursePhase.ID/evaluationType) while still returning the populated
report and the error; specifically, around the updateCoreCoursePhaseFn
invocation in evaluationReminderSend.go, keep the existing setLastSentAt(...)
and the return of report, err, but add a warning log (using the module's logger)
when updateCoreCoursePhaseFn returns an error so callers can see that mails
succeeded but persistence failed.

In `@servers/core/db/sqlc/mailing.sql.go`:
- Around line 231-298: GetParticipantMailingInformationByIDsRow.Email is a
nullable pgtype.Text but the mailing code calls sendMailFn with
participant.Email.String without checking validity; fix by checking
participant.Email.Valid before using participant.Email.String in the participant
mailing loop (where sendMailFn is invoked in manualMail.go) and skip or log
participants with invalid/NULL emails instead of calling sendMailFn with an
empty address so no malformed sends or bad logs occur.

In `@servers/core/mailing/manualMail_test.go`:
- Around line 91-140: The test TestSendManualMailHappyPath can panic when
accessing sentMails[0]/[1] because assert.Len is non-fatal; change the length
assertion to a fatal check (use suite.Require().Len(sentMails, 2)) before
accessing sentMails, or add a guard that returns/fails if len(sentMails) < 2;
update the assertion in this test (and any similar checks) so sentMails is
verified with suite.Require() prior to indexing after calling
SendManualMailToParticipants.

In `@servers/core/mailing/router.go`:
- Around line 84-95: The handler currently maps all errors from sendManualMailFn
to HTTP 500; change it to distinguish validation errors from internal errors by
checking the error returned by sendManualMailFn/SendManualMailToParticipants
(use errors.Is(err, ErrValidation) if you add a sentinel ErrValidation, or
type-assert/assert interface for a ValidationError struct returned by
SendManualMailToParticipants). If the error is a validation error, call
handleError(c, http.StatusBadRequest, err); otherwise keep the
http.StatusInternalServerError path; update SendManualMailToParticipants to
return the sentinel or typed validation error if not already.
🧹 Nitpick comments (9)
clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx (1)

141-148: Consider narrowing the error: any type.

Using any makes it easy to miss actual error shapes. If the project uses axios, typing as AxiosError (or a custom error type) would be more robust. This is a minor readability improvement.

servers/assessment/coursePhaseConfig/reminderRecipients.go (1)

226-237: Minor: deduplicateUUIDs duplicates logic from mailing.deduplicateUUIDList.

Both deduplicateUUIDs (here) and deduplicateUUIDList in servers/core/mailing/manualMail.go implement identical UUID deduplication. They're in different services (assessment vs core), so sharing isn't straightforward. Noting for awareness — not actionable now.

servers/assessment/docs/docs.go (1)

5190-5223: Role-based access control is properly enforced; consider returning anonymized feedback instead of email addresses.

The /reminders/send endpoint correctly restricts access to PromptAdmin and CourseLecturer roles via authMiddleware, so unauthorized users cannot access these email addresses. However, for a reminder-sending endpoint, returning the list of successful/failed email addresses may be unnecessary—consider whether sending counts or anonymized identifiers would suffice for admin feedback while reducing PII surface area.

servers/core/docs/swagger.json (2)

2660-2712: New manual mailing endpoint looks consistent with existing patterns.

The endpoint structure, parameters, and response codes follow the conventions established by the existing PUT /mailing/{coursePhaseID} endpoint. No structural issues.

One minor note: neither this endpoint nor the existing mailing endpoint documents 401/403 responses, even though these are privileged operations. If auth middleware handles these before reaching the handler, this is fine, but it may be worth documenting for API consumers.


4326-4371: Consider adding format: "date-time" to sentAt and documenting required fields.

The sentAt field (Line 4338) is typed as plain string. Adding "format": "date-time" would help API consumers and code generators produce correct types. Similarly, none of the properties on SendManualMailRequest are marked as required in the spec — subject, content, and recipientCourseParticipationIDs likely should be. If validation is enforced at the handler level this isn't a bug, but it weakens the API contract documentation.

servers/core/mailing/manualMail.go (2)

56-84: Consider adding a warning log for individual send failures.

When sendMailFn returns an error (line 79), the failure is silently added to report.FailedEmails without any log output. Adding a log.Warn (or log.WithError(err).Warn) would help operators diagnose delivery issues in production without needing to inspect the HTTP response.

As per coding guidelines, "Use sirupsen/logrus for logging (Debug, Info, Warn, Error levels) in Go services".

Proposed logging addition
+	log "github.com/sirupsen/logrus"
 		if err := sendMailFn(courseMailingSettings, participant.Email.String, finalSubject, finalContent); err != nil {
+			log.WithError(err).WithField("email", participant.Email.String).Warn("Failed to send manual mail to participant")
 			report.FailedEmails = append(report.FailedEmails, participant.Email.String)
 			continue
 		}

72-74: Additional placeholders can override built-in participant placeholders.

The loop at lines 72-74 merges request.AdditionalPlaceholders into the same map that already contains built-in keys like firstName, lastName, email, etc. A caller could inadvertently (or intentionally) override these values. If this is by design, it's fine — just worth noting. If not, consider applying additional placeholders first and then overlaying the built-in ones, or skipping keys that already exist.

servers/assessment/coursePhaseConfig/evaluationReminderSend.go (1)

131-172: HTTP clients are created per-call; consider reusing a shared client.

Each of getCoreCoursePhase, sendManualReminderMail, and updateCoreCoursePhase instantiates a new http.Client{Timeout: ...}. For a manual trigger that runs infrequently this is fine, but a shared package-level client would enable connection reuse and reduce allocation overhead if call frequency increases.

Example: shared client
+var coreHTTPClient = &http.Client{Timeout: 20 * time.Second}
+
 func getCoreCoursePhase(ctx context.Context, authHeader string, coursePhaseID uuid.UUID) (coreCoursePhaseResponse, error) {
     // ...
-    client := &http.Client{Timeout: 15 * time.Second}
-    resp, err := client.Do(req)
+    resp, err := coreHTTPClient.Do(req)

Also applies to: 174-219, 221-261

servers/assessment/docs/swagger.yaml (1)

2042-2046: Consider adding enum constraint for the type query parameter.

The type query parameter is documented as a plain string, but it should only accept self, peer, or tutor. Adding an Enums annotation in the Go source (e.g., // @param type query string true "Evaluation type" Enums(self, peer, tutor)) would produce a more self-documenting API spec and enable client-side validation.

Comment thread clients/assessment_component/src/assessment/pages/SettingsPage/SettingsPage.tsx Outdated
Comment thread servers/assessment/coursePhaseConfig/evaluationReminderSend.go
Comment thread servers/core/db/sqlc/mailing.sql.go
Comment thread servers/core/mailing/manualMail_test.go
Comment thread servers/core/mailing/router.go
@rappm rappm self-assigned this Feb 22, 2026
rappm and others added 6 commits March 17, 2026 11:02
…minders-to-assessors-once-assessment-deadline-has-passed

# Conflicts:
#	.gitignore
#	servers/assessment/coursePhaseConfig/router.go
#	servers/assessment/coursePhaseConfig/router_test.go
- Conditionally render AssessmentReminderCard for admins and lecturers
- Improve error handling in SendEvaluationReminderManualTrigger function
- Add logging for manual mail validation errors and recipient email checks
- Update tests to validate error handling for manual mail sending
…nt-deadline-has-passed' of github.com:prompt-edu/prompt into 618-send-automatic-reminders-to-assessors-once-assessment-deadline-has-passed
…minders-to-assessors-once-assessment-deadline-has-passed
@rappm rappm marked this pull request as ready for review March 20, 2026 17:23
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx (2)

49-54: Prefer interface over type for object structures.

Per coding guidelines, use interface for defining object structures. This also enables declaration merging if needed later.

♻️ Suggested change
-type ReminderTypeConfig = {
+interface ReminderTypeConfig {
   type: EvaluationReminderType
   label: string
   enabled: boolean
   deadline?: Date
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx`
around lines 49 - 54, Replace the type alias ReminderTypeConfig with an
equivalent interface to follow project conventions; define interface
ReminderTypeConfig { type: EvaluationReminderType; label: string; enabled:
boolean; deadline?: Date } so the shape stays identical but enables declaration
merging later and matches the guideline referenced in AssessmentReminderCard.tsx
where ReminderTypeConfig is used.

374-378: Consider using the friendly label in the confirmation dialog.

The dialog displays the raw evaluation type (self, peer, tutor) instead of the user-friendly label (Self Evaluation, etc.) defined in reminderTypes.

♻️ Suggested improvement
+          {confirmationType && (() => {
+            const config = reminderTypes.find(r => r.type === confirmationType)
+            return `Send reminder emails for ${config?.label ?? confirmationType} to all currently incomplete students?`
+          })()}
-          {confirmationType &&
-            `Send reminder emails for ${confirmationType} evaluations to all currently incomplete students?`}

Alternatively, extract the label lookup into a helper:

const getConfirmationLabel = () => {
  if (!confirmationType) return ''
  const config = reminderTypes.find(r => r.type === confirmationType)
  return config?.label ?? confirmationType
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx`
around lines 374 - 378, The confirmation dialog currently interpolates the raw
confirmationType value; update it to display the user-friendly label from
reminderTypes instead. In AssessmentReminderCard (where confirmationType is used
in the DialogDescription), look up the matching reminderTypes entry (e.g., find
by r.type === confirmationType) and use its .label (falling back to
confirmationType if not found). You can inline the lookup or add a small helper
like getConfirmationLabel() and reference that in the DialogDescription so the
dialog shows "Self Evaluation"/"Peer Evaluation"/etc. instead of
"self"/"peer"/"tutor".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx`:
- Around line 208-218: The updateCoursePhase call is overwriting
coursePhase.restrictedData by supplying only mailingSettings and thus deleting
other fields; update the payload to spread the existing restrictedData and merge
mailingSettings so other restricted fields are preserved (e.g., include
...coursePhase.restrictedData and for mailingSettings merge existing mailing
settings with the new assessmentReminder), referencing updateCoursePhase,
coursePhase, restrictedData, mailingSettings, and updatedReminder to locate the
change.

---

Nitpick comments:
In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx`:
- Around line 49-54: Replace the type alias ReminderTypeConfig with an
equivalent interface to follow project conventions; define interface
ReminderTypeConfig { type: EvaluationReminderType; label: string; enabled:
boolean; deadline?: Date } so the shape stays identical but enables declaration
merging later and matches the guideline referenced in AssessmentReminderCard.tsx
where ReminderTypeConfig is used.
- Around line 374-378: The confirmation dialog currently interpolates the raw
confirmationType value; update it to display the user-friendly label from
reminderTypes instead. In AssessmentReminderCard (where confirmationType is used
in the DialogDescription), look up the matching reminderTypes entry (e.g., find
by r.type === confirmationType) and use its .label (falling back to
confirmationType if not found). You can inline the lookup or add a small helper
like getConfirmationLabel() and reference that in the DialogDescription so the
dialog shows "Self Evaluation"/"Peer Evaluation"/etc. instead of
"self"/"peer"/"tutor".

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 00fcde7d-9d74-48be-95cc-2ec31035eada

📥 Commits

Reviewing files that changed from the base of the PR and between 5c201ff and 101fddb.

📒 Files selected for processing (3)
  • .gitignore
  • clients/assessment_component/src/assessment/pages/SettingsPage/SettingsPage.tsx
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx
✅ Files skipped from review due to trivial changes (2)
  • .gitignore
  • clients/assessment_component/src/assessment/pages/SettingsPage/SettingsPage.tsx

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx (1)

49-54: Consider using interface instead of type for object structures.

Per coding guidelines, prefer interface over type for defining object structures in TypeScript.

♻️ Suggested change
-type ReminderTypeConfig = {
+interface ReminderTypeConfig {
   type: EvaluationReminderType
   label: string
   enabled: boolean
   deadline?: Date
 }

As per coding guidelines: "Prefer interface over type for defining object structures in TypeScript"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx`
around lines 49 - 54, The declaration ReminderTypeConfig is currently a
TypeScript type alias for an object shape; per project guidelines replace it
with an interface declaration (interface ReminderTypeConfig) preserving the same
members (type: EvaluationReminderType, label: string, enabled: boolean,
deadline?: Date) so other usages of ReminderTypeConfig continue to work; update
any imports/exports if necessary to reflect the interface export.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx`:
- Around line 49-54: The declaration ReminderTypeConfig is currently a
TypeScript type alias for an object shape; per project guidelines replace it
with an interface declaration (interface ReminderTypeConfig) preserving the same
members (type: EvaluationReminderType, label: string, enabled: boolean,
deadline?: Date) so other usages of ReminderTypeConfig continue to work; update
any imports/exports if necessary to reflect the interface export.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 86610ed8-a0d1-4a68-a7ea-b1d91baa50c0

📥 Commits

Reviewing files that changed from the base of the PR and between 101fddb and 09b59e3.

📒 Files selected for processing (1)
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx

@rappm rappm temporarily deployed to prompt-dev-vm March 20, 2026 18:20 — with GitHub Actions Inactive
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/utils.ts (1)

136-195: Please add unit coverage around getReminderTypes.

This helper now owns most of the client-side eligibility rules, and edge cases like single-member teams, no tutors, and partially completed peer reviews are easy to regress. A small table-driven test matrix here would make the confirmation counts much safer to change later.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx`:
- Around line 196-203: getDisableReason currently allows opening confirmation
while recipient counts are still loading; update getDisableReason in
AssessmentReminderCard to return a disable reason when
isEvaluationCompletionsPending is true (e.g., "Recipient counts are still
loading; try again shortly.") so the UI won't confirm against inflated counts;
reference the isEvaluationCompletionsPending flag and ensure this check occurs
before checks that assume evaluationCompletions (for example before the
deadline/recipient checks and consistent with how getReminderTypes uses
evaluationCompletions).
- Around line 126-132: The effect currently overwrites subject/content on every
coursePhase refetch; change it so parseReminderMetaData and the setters
(setInitialMetaData, setSubject, setContent) only run on initial load or when
the phase identity changes: include phaseId in the dependency list (or track a
mounted/initialized phase id with a useRef) and, inside the useEffect, return
early unless coursePhase exists and either initial meta is not yet set or the
current phaseId differs from the last-initialized phaseId; call
parseReminderMetaData(coursePhase) and setInitialMetaData/setSubject/setContent
only in that case so unsaved edits are not clobbered by refetches.

In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/components/ReminderSendConfirmationDialog.tsx`:
- Around line 36-47: The dialog currently renders two DialogDescription
components (in ReminderSendConfirmationDialog) which produce duplicate ids;
change the JSX to render a single DialogDescription that conditionally composes
both messages: the primary confirmation string built from
confirmationReminderType (using confirmationReminderType.label and
recipientCount) and, if previousSentAt exists, append the "already sent on
{formatSentAt(previousSentAt)}..." sentence (separated by punctuation or a block
element) so only one DialogDescription is present for accessibility.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 78af6f49-a206-4f58-bc41-f4ead210b8d1

📥 Commits

Reviewing files that changed from the base of the PR and between 09b59e3 and 6405aeb.

📒 Files selected for processing (6)
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/components/ManualReminderSendingSection.tsx
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/components/ReminderSendConfirmationDialog.tsx
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/components/ReminderTemplateEditor.tsx
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/interfaces/ReminderTypeConfig.ts
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/utils.ts
✅ Files skipped from review due to trivial changes (1)
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/interfaces/ReminderTypeConfig.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/utils.test.ts (3)

33-40: Consider using a test framework instead of custom assertions.

The custom assertDeepEqual using JSON.stringify works for the current tests but has limitations: no meaningful diff output on failure, order-sensitivity for object keys, and doesn't handle edge cases like undefined properties. A test framework like Vitest (commonly used with React/TypeScript projects) would provide better assertion utilities, test isolation, and CI reporting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/utils.test.ts`
around lines 33 - 40, Replace the custom assertDeepEqual helper in utils.test.ts
with your test framework's assertion utilities: remove the assertDeepEqual
function and replace its usages with Vitest/Jest style assertions (e.g., use
expect(actual).toEqual(expected) or expect(actual).toStrictEqual(expected));
import the framework's expect where needed and update tests to rely on the
framework for deep equality so you get better diffs, stable key-order handling,
and edge-case coverage instead of JSON.stringify-based comparisons.

176-178: Tests execute at module load without framework integration.

While this approach works for basic validation, it lacks test isolation, descriptive failure output, and CI reporting integration. Also, self-evaluation scenarios are not covered.

Consider migrating to Vitest (already common in React/TypeScript projects) for better tooling:

♻️ Example migration to Vitest
import { describe, expect, it } from 'vitest'

describe('getReminderTypes', () => {
  it('returns zero recipients for single-member peer team', () => {
    const reminderTypes = getReminderTypes(/* ... */)
    expect(reminderTypes).toEqual([/* ... */])
  })

  it('returns zero recipients when team has no tutors', () => {
    // ...
  })

  it('counts incomplete peer evaluations correctly', () => {
    // ...
  })

  it('handles self evaluation type', () => {
    // Add missing coverage
  })
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/utils.test.ts`
around lines 176 - 178, The current tests run at module load via bare calls to
testSingleMemberPeerTeam(), testNoTutorRecipients(), and
testPartiallyCompletedPeerEvaluations(), which bypasses a test runner and lack
isolation and CI reporting; refactor these into a Vitest suite by importing
describe/it/expect and wrapping assertions for getReminderTypes (and any helper
functions) into descriptive it blocks, add a new it case to cover the missing
self-evaluation scenario, and replace the top-level function calls with
expect-based assertions inside the it blocks so tests run under Vitest and
produce proper failure output and reporting.

42-61: Type assertion bypasses interface validation.

The as unknown as AssessmentParticipationWithStudent cast prevents TypeScript from validating that the fixture matches the interface. If AssessmentParticipationWithStudent adds required fields later, these tests would still compile but may produce incorrect results.

Consider using a partial type approach or satisfies operator:

♻️ Alternative using Partial type
 const buildParticipation = (
   courseParticipationID: string,
   teamID: string,
-): AssessmentParticipationWithStudent =>
-  ({
+): Partial<AssessmentParticipationWithStudent> => ({
     coursePhaseID: 'phase-1',
     courseParticipationID,
     passStatus: 'NOT_ASSESSED',
     restrictedData: {},
     studentReadableData: {},
     prevData: {},
     student: {
       id: courseParticipationID,
       firstName: 'Test',
       lastName: 'Student',
       email: `${courseParticipationID}@example.com`,
       hasUniversityAccount: true,
     },
     teamID,
-  }) as unknown as AssessmentParticipationWithStudent
+  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/utils.test.ts`
around lines 42 - 61, The test fixture uses a double type cast "as unknown as
AssessmentParticipationWithStudent" which bypasses compile-time validation;
update buildParticipation to return a safer typed fixture by either signing its
literal with the satisfies operator (e.g. the object literal ... satisfies
AssessmentParticipationWithStudent) or change the function's return type to
Partial<AssessmentParticipationWithStudent> (or Partial with required overrides)
so TypeScript will validate fields; locate the buildParticipation function and
replace the double-cast with one of these approaches and adjust the fixture
fields if the compiler reports missing properties.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/utils.test.ts`:
- Around line 33-40: Replace the custom assertDeepEqual helper in utils.test.ts
with your test framework's assertion utilities: remove the assertDeepEqual
function and replace its usages with Vitest/Jest style assertions (e.g., use
expect(actual).toEqual(expected) or expect(actual).toStrictEqual(expected));
import the framework's expect where needed and update tests to rely on the
framework for deep equality so you get better diffs, stable key-order handling,
and edge-case coverage instead of JSON.stringify-based comparisons.
- Around line 176-178: The current tests run at module load via bare calls to
testSingleMemberPeerTeam(), testNoTutorRecipients(), and
testPartiallyCompletedPeerEvaluations(), which bypasses a test runner and lack
isolation and CI reporting; refactor these into a Vitest suite by importing
describe/it/expect and wrapping assertions for getReminderTypes (and any helper
functions) into descriptive it blocks, add a new it case to cover the missing
self-evaluation scenario, and replace the top-level function calls with
expect-based assertions inside the it blocks so tests run under Vitest and
produce proper failure output and reporting.
- Around line 42-61: The test fixture uses a double type cast "as unknown as
AssessmentParticipationWithStudent" which bypasses compile-time validation;
update buildParticipation to return a safer typed fixture by either signing its
literal with the satisfies operator (e.g. the object literal ... satisfies
AssessmentParticipationWithStudent) or change the function's return type to
Partial<AssessmentParticipationWithStudent> (or Partial with required overrides)
so TypeScript will validate fields; locate the buildParticipation function and
replace the double-cast with one of these approaches and adjust the fixture
fields if the compiler reports missing properties.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 74196505-b9ac-4ab0-8c4a-89964dfef4c8

📥 Commits

Reviewing files that changed from the base of the PR and between 6405aeb and ea52167.

📒 Files selected for processing (4)
  • clients/assessment_component/package.json
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/components/ReminderSendConfirmationDialog.tsx
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/utils.test.ts
✅ Files skipped from review due to trivial changes (1)
  • clients/assessment_component/package.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard/components/ReminderSendConfirmationDialog.tsx
  • clients/assessment_component/src/assessment/pages/SettingsPage/components/AssessmentReminderCard.tsx

@rappm rappm temporarily deployed to prompt-dev-vm March 23, 2026 12:15 — with GitHub Actions Inactive
@rappm rappm added this to the v2.11.0 milestone Mar 25, 2026
rappm added 3 commits March 25, 2026 15:19
…minders-to-assessors-once-assessment-deadline-has-passed
- Refactor AssessmentReminderCard for improved layout and accessibility.
- Update ManualReminderSendingSection and ReminderTemplateEditor for better UI consistency.
- Adjust evaluation reminder sending logic to handle deadline checks more robustly.
- Implement tests for evaluation reminder functionality, ensuring correct behavior on deadline boundaries.
- Improve error handling in manual mail sending process.
@rappm rappm temporarily deployed to prompt-dev-vm March 25, 2026 15:04 — with GitHub Actions Inactive
rappm and others added 2 commits March 25, 2026 18:25
…minders-to-assessors-once-assessment-deadline-has-passed
@rappm rappm temporarily deployed to prompt-dev-vm March 31, 2026 12:50 — with GitHub Actions Inactive
@rappm rappm temporarily deployed to prompt-dev-vm April 7, 2026 10:03 — with GitHub Actions Inactive
@rappm rappm requested a review from a team April 13, 2026 08:15
@rappm rappm temporarily deployed to prompt-dev-vm April 15, 2026 20:36 — with GitHub Actions Inactive
@rappm rappm added the schau mi o Translation: Ready to review label Apr 16, 2026
@rappm rappm temporarily deployed to prompt-dev-vm April 16, 2026 11:50 — with GitHub Actions Inactive
@mathildeshagl mathildeshagl modified the milestones: v2.11.0, v2.11.2 Apr 21, 2026
@rappm rappm temporarily deployed to prompt-dev-vm April 22, 2026 10:59 — with GitHub Actions Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

schau mi o Translation: Ready to review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Send automatic reminders to Assessors once assessment deadline has passed.

2 participants