mirror of
https://github.com/opelly27/WinStudentGoalTracker.git
synced 2026-05-20 02:57:36 +00:00
parent id fix
This commit is contained in:
@@ -163,6 +163,30 @@ public class StudentController : BaseController
|
||||
});
|
||||
}
|
||||
|
||||
if (dto.GoalParentId.HasValue)
|
||||
{
|
||||
var summary = await _studentRepository.GetGoalSummaryAsync(idStudent);
|
||||
var parentGoal = summary?.Goals.FirstOrDefault(g => g.GoalId == dto.GoalParentId.Value);
|
||||
|
||||
if (parentGoal is null)
|
||||
{
|
||||
return BadRequest(new ResponseResult<StudentGoalItem>
|
||||
{
|
||||
Success = false,
|
||||
Message = "Parent goal not found."
|
||||
});
|
||||
}
|
||||
|
||||
if (parentGoal.GoalParentId.HasValue)
|
||||
{
|
||||
return BadRequest(new ResponseResult<StudentGoalItem>
|
||||
{
|
||||
Success = false,
|
||||
Message = "The selected parent goal already has a parent."
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var created = await _studentRepository.InsertGoalAsync(idStudent, userId, dto);
|
||||
if (created is null)
|
||||
{
|
||||
|
||||
@@ -5,4 +5,5 @@ public class CreateGoalDto
|
||||
public string? Title { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? Category { get; set; }
|
||||
public Guid? GoalParentId { get; set; }
|
||||
}
|
||||
|
||||
@@ -110,6 +110,7 @@ public class StudentRepository
|
||||
new
|
||||
{
|
||||
p_id_goal = newGoalId.ToString(),
|
||||
p_id_goal_parent = dto.GoalParentId?.ToString(),
|
||||
p_id_student = idStudent.ToString(),
|
||||
p_id_user = userId.ToString(),
|
||||
p_title = dto.Title,
|
||||
|
||||
+12
@@ -32,6 +32,18 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
@if (parentGoalOptions().length > 0) {
|
||||
<div class="field">
|
||||
<label for="goalParentId">Parent Goal <span class="optional">(optional)</span></label>
|
||||
<select id="goalParentId" [(ngModel)]="form.goalParentId" name="goalParentId">
|
||||
<option [ngValue]="null">None</option>
|
||||
@for (goal of parentGoalOptions(); track goal.goalId) {
|
||||
<option [ngValue]="goal.goalId">{{ goal.title }}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="field">
|
||||
<label for="description">Description</label>
|
||||
<textarea
|
||||
|
||||
+9
-2
@@ -68,8 +68,14 @@
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.optional {
|
||||
font-weight: 400;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.field input,
|
||||
.field textarea {
|
||||
.field textarea,
|
||||
.field select {
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
@@ -80,7 +86,8 @@
|
||||
}
|
||||
|
||||
.field input:focus,
|
||||
.field textarea:focus {
|
||||
.field textarea:focus,
|
||||
.field select:focus {
|
||||
border-color: #4f46e5;
|
||||
box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.15);
|
||||
}
|
||||
|
||||
+7
-1
@@ -1,4 +1,4 @@
|
||||
import { Component, inject, input, output, signal } from '@angular/core';
|
||||
import { Component, computed, inject, input, output, signal } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CreateGoalDto } from '../../../shared/classes/create-goal.dto';
|
||||
import { StudentGoalItem } from '../../../shared/classes/student-goal';
|
||||
@@ -19,16 +19,22 @@ export class AddGoalModal {
|
||||
private readonly studentService = inject(StudentService);
|
||||
|
||||
readonly studentId = input.required<string>();
|
||||
readonly existingGoals = input.required<StudentGoalItem[]>();
|
||||
readonly goalCreated = output<StudentGoalItem>();
|
||||
readonly cancelled = output<void>();
|
||||
|
||||
protected readonly isSubmitting = signal(false);
|
||||
protected readonly errorMessage = signal<string | null>(null);
|
||||
|
||||
protected readonly parentGoalOptions = computed(() =>
|
||||
this.existingGoals().filter(g => g.goalParentId === null)
|
||||
);
|
||||
|
||||
protected form: CreateGoalDto = {
|
||||
title: '',
|
||||
description: '',
|
||||
category: '',
|
||||
goalParentId: null,
|
||||
};
|
||||
|
||||
// ************************** Properties ***************************
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
@if (showAddModal()) {
|
||||
<app-add-goal-modal
|
||||
[studentId]="studentId"
|
||||
[existingGoals]="goals()"
|
||||
(goalCreated)="onGoalCreated($event)"
|
||||
(cancelled)="onModalCancelled()"
|
||||
/>
|
||||
@@ -19,8 +20,12 @@
|
||||
<p class="error">{{ errorMessage() }}</p>
|
||||
}
|
||||
|
||||
@if (goals().length === 0 && !errorMessage()) {
|
||||
<p class="empty-state">No goals yet. Click <strong>+ Add a Goal</strong> to get started.</p>
|
||||
} @else {
|
||||
<div class="card-grid">
|
||||
@for (goal of goals(); track goal.goalId) {
|
||||
<app-goal-card [goal]="goal" />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -52,6 +52,13 @@
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
color: #888;
|
||||
font-size: 0.9375rem;
|
||||
margin: 2rem auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -2,4 +2,5 @@ export interface CreateGoalDto {
|
||||
title: string;
|
||||
description: string;
|
||||
category: string;
|
||||
goalParentId: string | null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user