Added persistent prompt to student progress report

This commit is contained in:
ivan-pelly
2026-04-10 15:31:56 -07:00
parent d4a580ffae
commit b287276ec0
21 changed files with 606 additions and 11 deletions
@@ -0,0 +1,191 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WinStudentGoalTracker.Models;
using WinStudentGoalTracker.Models.ResponseTypes;
using WinStudentGoalTracker.BaseClasses;
using WinStudentGoalTracker.DataAccess;
namespace WinStudentGoalTracker.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ReportPromptController : BaseController
{
// ************************** Constructor **************************
private readonly ReportPromptRepository _reportPromptRepository;
public ReportPromptController()
{
_reportPromptRepository = new();
}
// ************************ Public Methods *************************
[HttpGet]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<IEnumerable<ReportPromptResponse>>), StatusCodes.Status200OK)]
public async Task<ActionResult<ResponseResult<IEnumerable<ReportPromptResponse>>>> GetAll()
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
var prompts = await _reportPromptRepository.GetAllAsync();
return Ok(new ResponseResult<IEnumerable<ReportPromptResponse>>
{
Success = true,
Message = "Report prompts retrieved successfully.",
Data = prompts
});
}
[HttpGet("{idReportPrompt:guid}")]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult<ReportPromptResponse>>> GetById(Guid idReportPrompt)
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
var prompt = await _reportPromptRepository.GetByIdAsync(idReportPrompt);
if (prompt is null)
{
return NotFound(new ResponseResult<ReportPromptResponse>
{
Success = false,
Message = "Report prompt not found."
});
}
return Ok(new ResponseResult<ReportPromptResponse>
{
Success = true,
Message = "Report prompt retrieved successfully.",
Data = prompt
});
}
// *****************************************************************
// Returns the report prompt for the given reportname scoped to
// the authenticated user's program.
// *****************************************************************
[HttpGet("by-name/{reportname}")]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult<ReportPromptResponse>>> GetByReportname(string reportname)
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
var prompt = await _reportPromptRepository.GetByReportnameAsync(reportname, programId);
if (prompt is null)
{
return NotFound(new ResponseResult<ReportPromptResponse>
{
Success = false,
Message = "Report prompt not found."
});
}
return Ok(new ResponseResult<ReportPromptResponse>
{
Success = true,
Message = "Report prompt retrieved successfully.",
Data = prompt
});
}
[HttpPost]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status201Created)]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status400BadRequest)]
public async Task<ActionResult<ResponseResult<ReportPromptResponse>>> Create([FromBody] CreateReportPromptDto dto)
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
// Scope the new prompt to the authenticated user's program.
dto.ProgramId = programId.ToString();
var created = await _reportPromptRepository.InsertAsync(dto);
if (created is null)
{
return BadRequest(new ResponseResult<ReportPromptResponse>
{
Success = false,
Message = "Unable to create report prompt."
});
}
return StatusCode(StatusCodes.Status201Created, new ResponseResult<ReportPromptResponse>
{
Success = true,
Message = "Report prompt created successfully.",
Data = created
});
}
[HttpPut("{idReportPrompt:guid}")]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<object>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult<object>), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult<object>>> Update(Guid idReportPrompt, [FromBody] UpdateReportPromptDto dto)
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
var updated = await _reportPromptRepository.UpdateAsync(idReportPrompt, dto);
return Ok(new ResponseResult<object>
{
Success = true,
Message = updated ? "Report prompt updated successfully." : "No changes were applied."
});
}
[HttpDelete("{idReportPrompt:guid}")]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<object>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult<object>), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult<object>>> Delete(Guid idReportPrompt)
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
var deleted = await _reportPromptRepository.DeleteAsync(idReportPrompt);
if (!deleted)
{
return NotFound(new ResponseResult<object>
{
Success = false,
Message = "Report prompt not found."
});
}
return Ok(new ResponseResult<object>
{
Success = true,
Message = "Report prompt deleted."
});
}
}
@@ -0,0 +1,8 @@
namespace WinStudentGoalTracker.DataAccess;
public class CreateReportPromptDto
{
public string? ProgramId { get; set; }
public string? Prompt { get; set; }
public string? Reportname { get; set; }
}
@@ -0,0 +1,7 @@
namespace WinStudentGoalTracker.DataAccess;
public class UpdateReportPromptDto
{
public string? Prompt { get; set; }
public string? Reportname { get; set; }
}
@@ -0,0 +1,9 @@
namespace WinStudentGoalTracker.DataAccess;
public class dbReportPrompt
{
public required Guid IdReportPrompt { get; set; }
public Guid? IdProgram { get; set; }
public string? Prompt { get; set; }
public string? Reportname { get; set; }
}
@@ -0,0 +1,105 @@
using System.Data;
using Dapper;
using MySql.Data.MySqlClient;
using WinStudentGoalTracker.Models;
namespace WinStudentGoalTracker.DataAccess;
public class ReportPromptRepository
{
private IDbConnection Connection => new MySqlConnection(DatabaseManager.ConnectionString);
// *****************************************************************
// Returns all report prompts.
// *****************************************************************
public async Task<IEnumerable<ReportPromptResponse>> GetAllAsync()
{
using var db = Connection;
return await db.QueryAsync<ReportPromptResponse>(
"sp_ReportPrompt_GetAll",
commandType: CommandType.StoredProcedure);
}
// *****************************************************************
// Returns a single report prompt by its ID, or null if not found.
// *****************************************************************
public async Task<ReportPromptResponse?> GetByIdAsync(Guid idReportPrompt)
{
using var db = Connection;
return await db.QuerySingleOrDefaultAsync<ReportPromptResponse>(
"sp_ReportPrompt_GetById",
new { p_id_report_prompt = idReportPrompt.ToString() },
commandType: CommandType.StoredProcedure);
}
// *****************************************************************
// Returns a single report prompt by its reportname and program,
// or null if not found.
// *****************************************************************
public async Task<ReportPromptResponse?> GetByReportnameAsync(string reportname, Guid programId)
{
using var db = Connection;
return await db.QuerySingleOrDefaultAsync<ReportPromptResponse>(
"sp_ReportPrompt_GetByReportname",
new
{
p_reportname = reportname,
p_id_program = programId.ToString()
},
commandType: CommandType.StoredProcedure);
}
// *****************************************************************
// Inserts a new report prompt and returns the created record.
// *****************************************************************
public async Task<ReportPromptResponse?> InsertAsync(CreateReportPromptDto dto)
{
var newId = Guid.NewGuid();
using var db = Connection;
await db.ExecuteAsync(
"sp_ReportPrompt_Insert",
new
{
p_id_report_prompt = newId.ToString(),
p_id_program = dto.ProgramId,
p_prompt = dto.Prompt,
p_reportname = dto.Reportname
},
commandType: CommandType.StoredProcedure);
return await GetByIdAsync(newId);
}
// *****************************************************************
// Updates an existing report prompt. Returns true if a row was
// affected, false otherwise.
// *****************************************************************
public async Task<bool> UpdateAsync(Guid idReportPrompt, UpdateReportPromptDto dto)
{
using var db = Connection;
var rowsAffected = await db.ExecuteScalarAsync<int>(
"sp_ReportPrompt_Update",
new
{
p_id_report_prompt = idReportPrompt.ToString(),
p_prompt = dto.Prompt,
p_reportname = dto.Reportname
},
commandType: CommandType.StoredProcedure);
return rowsAffected > 0;
}
// *****************************************************************
// Deletes a report prompt by its ID. Returns true if a row was
// affected, false otherwise.
// *****************************************************************
public async Task<bool> DeleteAsync(Guid idReportPrompt)
{
using var db = Connection;
var rowsAffected = await db.ExecuteScalarAsync<int>(
"sp_ReportPrompt_Delete",
new { p_id_report_prompt = idReportPrompt.ToString() },
commandType: CommandType.StoredProcedure);
return rowsAffected > 0;
}
}
@@ -0,0 +1,9 @@
namespace WinStudentGoalTracker.Models;
public class ReportPromptResponse
{
public Guid ReportPromptId { get; set; }
public Guid? ProgramId { get; set; }
public string? Prompt { get; set; }
public string? Reportname { get; set; }
}
@@ -21,7 +21,6 @@ BEGIN
AND DATE(pe.`created_at`) <= p_to_date AND DATE(pe.`created_at`) <= p_to_date
) )
ORDER BY g.`category`; ORDER BY g.`category`;
-- Result set 2: Progress events within the date range, with benchmark names -- Result set 2: Progress events within the date range, with benchmark names
SELECT SELECT
pe.`id_goal` AS `goalId`, pe.`id_goal` AS `goalId`,
@@ -0,0 +1,10 @@
DELIMITER ;;
CREATE DEFINER=`root`@`%` PROCEDURE `sp_ReportPrompt_Delete`(
IN p_id_report_prompt CHAR(36)
)
BEGIN
DELETE FROM `ReportPrompt`
WHERE `id_report_prompt` = p_id_report_prompt;
SELECT ROW_COUNT() AS rowsAffected;
END;;
DELIMITER ;
@@ -0,0 +1,12 @@
DELIMITER ;;
CREATE DEFINER=`root`@`%` PROCEDURE `sp_ReportPrompt_GetAll`()
BEGIN
SELECT
`id_report_prompt` AS `reportPromptId`,
`id_program` AS `programId`,
`prompt` AS `prompt`,
`reportname` AS `reportname`
FROM `ReportPrompt`
ORDER BY `reportname`;
END;;
DELIMITER ;
@@ -0,0 +1,15 @@
DELIMITER ;;
CREATE DEFINER=`root`@`%` PROCEDURE `sp_ReportPrompt_GetById`(
IN p_id_report_prompt CHAR(36)
)
BEGIN
SELECT
`id_report_prompt` AS `reportPromptId`,
`id_program` AS `programId`,
`prompt` AS `prompt`,
`reportname` AS `reportname`
FROM `ReportPrompt`
WHERE `id_report_prompt` = p_id_report_prompt
LIMIT 1;
END;;
DELIMITER ;
@@ -0,0 +1,17 @@
DELIMITER ;;
CREATE DEFINER=`root`@`%` PROCEDURE `sp_ReportPrompt_GetByReportname`(
IN p_reportname CHAR(100),
IN p_id_program CHAR(36)
)
BEGIN
SELECT
`id_report_prompt` AS `reportPromptId`,
`id_program` AS `programId`,
`prompt` AS `prompt`,
`reportname` AS `reportname`
FROM `ReportPrompt`
WHERE `reportname` = p_reportname
AND `id_program` = p_id_program
LIMIT 1;
END;;
DELIMITER ;
@@ -0,0 +1,32 @@
DELIMITER ;;
CREATE DEFINER=`root`@`%` PROCEDURE `sp_ReportPrompt_Insert`(
IN p_id_report_prompt CHAR(36),
IN p_id_program CHAR(36),
IN p_prompt TEXT,
IN p_reportname CHAR(100)
)
BEGIN
INSERT INTO `ReportPrompt`
(
`id_report_prompt`,
`id_program`,
`prompt`,
`reportname`
)
VALUES
(
p_id_report_prompt,
p_id_program,
p_prompt,
p_reportname
);
SELECT
`id_report_prompt` AS `reportPromptId`,
`id_program` AS `programId`,
`prompt` AS `prompt`,
`reportname` AS `reportname`
FROM `ReportPrompt`
WHERE `id_report_prompt` = p_id_report_prompt
LIMIT 1;
END;;
DELIMITER ;
@@ -0,0 +1,15 @@
DELIMITER ;;
CREATE DEFINER=`root`@`%` PROCEDURE `sp_ReportPrompt_Update`(
IN p_id_report_prompt CHAR(36),
IN p_prompt TEXT,
IN p_reportname CHAR(100)
)
BEGIN
UPDATE `ReportPrompt`
SET
`prompt` = p_prompt,
`reportname` = p_reportname
WHERE `id_report_prompt` = p_id_report_prompt;
SELECT ROW_COUNT() AS rowsAffected;
END;;
DELIMITER ;
@@ -14,7 +14,6 @@ BEGIN
FROM v_student_card FROM v_student_card
WHERE studentId = p_id_student WHERE studentId = p_id_student
LIMIT 1; LIMIT 1;
-- Result set 2: Goals -- Result set 2: Goals
SELECT SELECT
s.`identifier` AS `studentIdentifier`, s.`identifier` AS `studentIdentifier`,
@@ -33,7 +32,6 @@ BEGIN
INNER JOIN `student` s ON s.`id_student` = vc.`studentId` INNER JOIN `student` s ON s.`id_student` = vc.`studentId`
WHERE vc.`studentId` = p_id_student WHERE vc.`studentId` = p_id_student
ORDER BY vc.`goalId`; ORDER BY vc.`goalId`;
-- Result set 3: Benchmarks -- Result set 3: Benchmarks
SELECT SELECT
s.`identifier` AS `studentIdentifier`, s.`identifier` AS `studentIdentifier`,
@@ -51,7 +49,6 @@ BEGIN
LEFT JOIN `user` u ON u.`id_user` = b.`id_user_created` LEFT JOIN `user` u ON u.`id_user` = b.`id_user_created`
WHERE g.`id_student` = p_id_student WHERE g.`id_student` = p_id_student
ORDER BY b.`created_at` DESC; ORDER BY b.`created_at` DESC;
-- Result set 4: Progress events (all goals for this student) -- Result set 4: Progress events (all goals for this student)
SELECT SELECT
vc.`progressEventId`, vc.`progressEventId`,
@@ -62,7 +59,6 @@ BEGIN
FROM `v_progress_event_card` vc FROM `v_progress_event_card` vc
WHERE vc.`studentId` = p_id_student WHERE vc.`studentId` = p_id_student
ORDER BY vc.`createdAt` DESC; ORDER BY vc.`createdAt` DESC;
-- Result set 5: Benchmark/progress-event associations -- Result set 5: Benchmark/progress-event associations
SELECT SELECT
peb.`id_progress_event` AS `progressEventId`, peb.`id_progress_event` AS `progressEventId`,
@@ -18,7 +18,6 @@ BEGIN
INNER JOIN student s ON s.id_student = vc.studentId INNER JOIN student s ON s.id_student = vc.studentId
WHERE s.id_program = p_id_program WHERE s.id_program = p_id_program
ORDER BY vc.studentId; ORDER BY vc.studentId;
IF p_scope = 'all' THEN IF p_scope = 'all' THEN
SELECT SELECT
us.id_user_student, us.id_user_student,
+7
View File
@@ -0,0 +1,7 @@
CREATE TABLE `ReportPrompt` (
`id_ReportPrompt` char(36) NOT NULL DEFAULT (uuid()),
`prompt` text NOT NULL,
`reportname` char(100) NOT NULL,
`id_program` char(36) DEFAULT 'NULL',
PRIMARY KEY (`id_ReportPrompt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
@@ -45,6 +45,22 @@
</div> </div>
} }
<div class="field">
<div class="field-label-row">
<label class="field-label" for="prompt">Prompt</label>
@if (promptSaved()) {
<span class="save-indicator">&#10003; Saved</span>
}
</div>
<textarea
id="prompt"
class="field-input prompt-textarea"
rows="6"
[(ngModel)]="promptText"
(ngModelChange)="onPromptChange()">
</textarea>
</div>
<div class="actions"> <div class="actions">
<button <button
class="toolbar-btn run-btn" class="toolbar-btn run-btn"
@@ -55,6 +55,37 @@
} }
} }
.field-label-row {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
.field-label {
margin-bottom: 0;
}
}
.save-indicator {
font-size: 12px;
font-weight: 500;
color: var(--accent-green, #22c55e);
animation: fadeIn 0.2s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.prompt-textarea {
width: 100%;
resize: vertical;
font-family: inherit;
font-size: 13px;
line-height: 1.5;
}
.run-btn { .run-btn {
background: var(--accent-indigo) !important; background: var(--accent-indigo) !important;
color: #fff !important; color: #fff !important;
@@ -1,9 +1,9 @@
import { Component, inject, signal } from '@angular/core'; import { Component, inject, signal, OnDestroy } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { StudentService } from '../../../shared/services/student.service'; import { StudentService } from '../../../shared/services/student.service';
import { ReportPromptService } from '../../../shared/services/report-prompt.service';
import { StudentCardDto } from '../../../shared/classes/student-card.dto'; import { StudentCardDto } from '../../../shared/classes/student-card.dto';
import { StudentGoalItem } from '../../../shared/classes/student-goal';
import { toIsoDateString } from '../../../shared/utils/format-date'; import { toIsoDateString } from '../../../shared/utils/format-date';
interface GoalCheckItem { interface GoalCheckItem {
@@ -18,29 +18,41 @@ interface GoalCheckItem {
templateUrl: './student-progress-report.html', templateUrl: './student-progress-report.html',
styleUrl: './student-progress-report.scss', styleUrl: './student-progress-report.scss',
}) })
export class StudentProgressReport { export class StudentProgressReport implements OnDestroy {
// ************************** Constructor ************************** // ************************** Constructor **************************
constructor() { constructor() {
this.loadStudents(); this.loadStudents();
this.loadPrompt();
} }
// ************************** Declarations ************************* // ************************** Declarations *************************
private readonly router = inject(Router); private readonly router = inject(Router);
private readonly studentService = inject(StudentService); private readonly studentService = inject(StudentService);
private readonly reportPromptService = inject(ReportPromptService);
protected readonly students = signal<StudentCardDto[]>([]); protected readonly students = signal<StudentCardDto[]>([]);
protected readonly goalItems = signal<GoalCheckItem[]>([]); protected readonly goalItems = signal<GoalCheckItem[]>([]);
protected readonly running = signal(false); protected readonly running = signal(false);
protected readonly promptSaved = signal(false);
protected selectedStudentId = ''; protected selectedStudentId = '';
protected fromDate = ''; protected fromDate = '';
protected toDate = ''; protected toDate = '';
protected promptText = '';
private promptId = '';
private debounceTimer: ReturnType<typeof setTimeout> | null = null;
private savedTimer: ReturnType<typeof setTimeout> | null = null;
// ************************** Properties *************************** // ************************** Properties ***************************
// ************************ Public Methods ************************* // ************************ Public Methods *************************
ngOnDestroy() {
if (this.debounceTimer) clearTimeout(this.debounceTimer);
if (this.savedTimer) clearTimeout(this.savedTimer);
}
// ************************ Event Handlers ************************* // ************************ Event Handlers *************************
onBack() { onBack() {
@@ -88,6 +100,26 @@ export class StudentProgressReport {
); );
} }
// *****************************************************************
// Debounces prompt changes and auto-saves after 1 second of
// inactivity. Shows a brief "Saved" indicator on success.
// *****************************************************************
onPromptChange() {
this.promptSaved.set(false);
if (this.debounceTimer) clearTimeout(this.debounceTimer);
if (!this.promptId) return;
this.debounceTimer = setTimeout(async () => {
const result = await this.reportPromptService.updatePrompt(this.promptId, this.promptText);
if (result.success) {
this.promptSaved.set(true);
if (this.savedTimer) clearTimeout(this.savedTimer);
this.savedTimer = setTimeout(() => this.promptSaved.set(false), 3000);
}
}, 1000);
}
// ***************************************************************** // *****************************************************************
// Calls the API to generate the markdown report, passing only // Calls the API to generate the markdown report, passing only
// the checked goal IDs, and triggers a browser download. // the checked goal IDs, and triggers a browser download.
@@ -129,14 +161,34 @@ export class StudentProgressReport {
} }
// ***************************************************************** // *****************************************************************
// Triggers a browser download of the given markdown content. // Loads the prompt for 'progressreport' from the API.
// *****************************************************************
private async loadPrompt() {
const result = await this.reportPromptService.getByReportname('progressreport');
if (result.success && result.payload) {
this.promptId = result.payload.reportPromptId;
this.promptText = result.payload.prompt;
} else {
console.error('[loadPrompt] Failed to load prompt:', result.message);
}
}
// *****************************************************************
// Triggers a browser download of the given markdown content,
// prepending the prompt text at the top of the file.
// ***************************************************************** // *****************************************************************
private downloadMarkdown(content: string) { private downloadMarkdown(content: string) {
const student = this.students().find(s => s.studentId === this.selectedStudentId); const student = this.students().find(s => s.studentId === this.selectedStudentId);
const name = student ? student.identifier.replace(/\s+/g, '_') : 'report'; const name = student ? student.identifier.replace(/\s+/g, '_') : 'report';
const filename = `${name}_progress_report_${this.fromDate}_to_${this.toDate}.md`; const filename = `${name}_progress_report_${this.fromDate}_to_${this.toDate}.md`;
const blob = new Blob([content], { type: 'text/markdown;charset=utf-8' }); // Prepend the prompt if one exists.
let output = content;
if (this.promptText.trim()) {
output = this.promptText.trim() + '\n\n---\n\n' + content;
}
const blob = new Blob([output], { type: 'text/markdown;charset=utf-8' });
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
const a = document.createElement('a'); const a = document.createElement('a');
a.href = url; a.href = url;
@@ -0,0 +1,6 @@
export interface ReportPromptDto {
reportPromptId: string;
programId: string;
prompt: string;
reportname: string;
}
@@ -0,0 +1,59 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { firstValueFrom } from 'rxjs';
import { environment } from '../../../environments/environment';
import { ApiResult } from '../classes/api-result';
import { ResponseResult } from '../classes/auth.models';
import { ReportPromptDto } from '../classes/report-prompt.dto';
import { describeHttpError } from '../classes/http-errors';
@Injectable({
providedIn: 'root',
})
export class ReportPromptService {
// ************************** Declarations *************************
private readonly http = inject(HttpClient);
private readonly base = environment.apiBaseUrl;
// ************************ Public Methods *************************
// *****************************************************************
// Returns the report prompt for the given reportname, scoped to
// the authenticated user's program.
// *****************************************************************
async getByReportname(name: string): Promise<ApiResult<ReportPromptDto>> {
try {
const result = await firstValueFrom(
this.http.get<ResponseResult<ReportPromptDto>>(
`${this.base}/api/ReportPrompt/by-name/${encodeURIComponent(name)}`
)
);
return result.success && result.data
? ApiResult.ok(result.data)
: ApiResult.fail(result.message);
} catch (error) {
return ApiResult.fail(describeHttpError(error as HttpErrorResponse));
}
}
// *****************************************************************
// Updates the prompt text for an existing report prompt.
// *****************************************************************
async updatePrompt(id: string, prompt: string): Promise<ApiResult> {
try {
const result = await firstValueFrom(
this.http.put<ResponseResult<void>>(
`${this.base}/api/ReportPrompt/${id}`,
{ prompt }
)
);
return result.success
? ApiResult.empty()
: ApiResult.fail(result.message);
} catch (error) {
return ApiResult.fail(describeHttpError(error as HttpErrorResponse));
}
}
}