Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/app/projects/states/index/index.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ angular.module('doubtfire.projects.states.index', [])
templateUrl: "units/states/index/index.tpl.html" # We can re-use unit's index here
data:
pageTitle: "_Home_"
roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin', 'Auditor']
}
)

.controller("ProjectsIndexStateCtrl", ($scope, $rootScope, $state, $stateParams, newProjectService, listenerService, globalStateService) ->
.controller("ProjectsIndexStateCtrl", ($scope, $rootScope, $state, $stateParams, newProjectService, listenerService, GlobalStateService) ->
# Error - required projectId is missing!
projectId = +$stateParams.projectId
return $state.go('home') unless projectId

globalStateService.onLoad () ->
GlobalStateService.onLoad () ->
# Load in project
newProjectService.get(projectId, {
# Ensure that we cache queries here... so that we get any projects we are in
Expand All @@ -38,7 +39,7 @@ angular.module('doubtfire.projects.states.index', [])
$scope.project = project
$scope.unit = project.unit if project.unit.taskDefinitions.length > 0 && project.tasks.length == project.unit.taskDefinitions.length

globalStateService.setView('PROJECT', $scope.project)
GlobalStateService.setView('PROJECT', $scope.project)

# Go home if no project was found
return $state.go('home') unless project?
Expand Down
46 changes: 46 additions & 0 deletions src/app/projects/states/index/index.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<div class="p-6 bg-white shadow-md rounded-md">
<!-- Page Heading -->
<h1 class="text-2xl font-bold mb-4 text-gray-800">Projects Index</h1>

<!-- Project Info -->
<div *ngIf="project; else loadingOrError">
<p class="text-gray-700">
<span class="font-semibold">Project:</span> {{ project.name }}
</p>
<p class="text-gray-700">
<span class="font-semibold">Unit:</span> {{ unit?.name }}
</p>

<!-- Tasks Section -->
<h2 class="text-xl font-semibold mt-6 mb-2 text-gray-800">Tasks</h2>

<ul *ngIf="project?.tasks?.length > 0; else noTasks" class="space-y-2">
<li *ngFor="let task of project.tasks"
class="flex items-center justify-between bg-gray-100 p-3 rounded shadow-sm">
<span class="text-gray-700">
{{ task.name }} – Status:
<span class="font-medium">{{ task.status }}</span>
</span>
<button class="px-3 py-1 bg-blue-600 text-white rounded hover:bg-blue-700 transition"
(click)="completeTask(task)">
Complete
</button>
</li>
</ul>

<!-- No Tasks -->
<ng-template #noTasks>
<p class="text-gray-500 italic">No tasks found for this project.</p>
</ng-template>
</div>

<!-- Loading / Error States -->
<ng-template #loadingOrError>
<div *ngIf="isLoading" class="text-gray-500">Loading project...</div>
<div *ngIf="hasError" class="text-red-600">Error loading project.</div>
</ng-template>
</div>
<ng-template #loadingOrError>
<div *ngIf="isLoading">Loading project...</div>
<div *ngIf="hasError">Error loading project.</div>
</ng-template>
Empty file.
99 changes: 99 additions & 0 deletions src/app/projects/states/index/index.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute, Router, ParamMap } from '@angular/router';
import { Subject } from 'rxjs';
import { switchMap, takeUntil } from 'rxjs/operators';
import { GlobalStateService } from './global-state.service';
import { ProjectService } from '../../services/project.service';
import { ListenerService } from '../../services/listener.service';
import { ViewType } from '../../common/types/view-type';

@Component({
selector: 'app-projects-index',
templateUrl: './index.component.html',
styleUrls: ['./index.component.scss']
})
export class ProjectsIndexComponent implements OnInit, OnDestroy {
projectId!: number;
project: any;
unit: any;
isLoading = true;
hasError = false;

private destroy$ = new Subject<void>();

constructor(
private route: ActivatedRoute,
private router: Router,
private projectService: ProjectService,
private listenerService: ListenerService,
private globalStateService: GlobalStateService
) { }

ngOnInit(): void {
// Wait for global state to be ready, then react to route changes
this.globalStateService.onLoad(() => {
this.route.paramMap
.pipe(
takeUntil(this.destroy$),
switchMap((params: ParamMap) => {
const idParam = params.get('projectId');
this.projectId = Number(idParam);

if (!this.projectId || Number.isNaN(this.projectId)) {
this.hasError = true;
this.isLoading = false;
this.router.navigate(['/home']);
// Return an empty observable when navigation happens
return new Subject<never>();
}

this.isLoading = true;
this.hasError = false;

return this.projectService.get(this.projectId, {
cacheBehaviourOnGet: 'cacheQuery',
mappingCompleteCallback: (project: any) => {
this.unit = project?.unit;
}
});
})
)
.subscribe({
next: (project: any) => {
this.project = project;

// Guard against null/undefined project
if (!project) {
this.hasError = true;
this.isLoading = false;
this.router.navigate(['/home']);
return;
}

// Ensure unit is set when tasks match task definitions
if (
project.unit?.taskDefinitions?.length > 0 &&
project.tasks?.length === project.unit.taskDefinitions.length
) {
this.unit = project.unit;
}

// Use enum for view type
this.globalStateService.setView(ViewType.PROJECT, this.project);

this.isLoading = false;
},
error: () => {
this.isLoading = false;
this.hasError = true;
this.router.navigate(['/home']);
}
});
});
}

ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}