diff --git a/backend/.idea/workspace.xml b/backend/.idea/workspace.xml
index cf3cb53..1750b51 100644
--- a/backend/.idea/workspace.xml
+++ b/backend/.idea/workspace.xml
@@ -4,13 +4,11 @@
-
+
-
-
-
-
-
+
+
+
@@ -29,7 +27,7 @@
@@ -578,14 +576,21 @@
1699806194258
-
+
+
+ 1699809089060
+
+
+
+ 1699809089060
+
+
-
@@ -610,7 +615,8 @@
-
+
+
@@ -622,12 +628,7 @@
file://$PROJECT_DIR$/src/main/java/core/api/controller/ScheduleController.java
- 68
-
-
-
- file://$PROJECT_DIR$/src/main/java/core/api/controller/ScheduleController.java
- 93
+ 98
@@ -635,6 +636,11 @@
93
+
+ file://$PROJECT_DIR$/src/main/java/core/api/controller/ScheduleController.java
+ 83
+
+
diff --git a/backend/src/main/java/core/api/controller/ScheduleController.java b/backend/src/main/java/core/api/controller/ScheduleController.java
index 8cd2d83..4ef4130 100644
--- a/backend/src/main/java/core/api/controller/ScheduleController.java
+++ b/backend/src/main/java/core/api/controller/ScheduleController.java
@@ -78,7 +78,12 @@ public class ScheduleController {
return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo());
} else if(scheduleFieldInfo instanceof AdvancedScheduleFieldInfo) {
ServiceResult scheduleResult = taskScheduleService.scheduleAdvanced(permissionResult.getResult(), (AdvancedScheduleFieldInfo) scheduleFieldInfo);
- return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo());
+ if(scheduleResult.getResult() != null) {
+ return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo());
+ } else {
+ return ResponseEntity.status(400).body(new SimpleStatusResponse("failed"));
+ }
+
} else {
return ResponseEntity.status(400).body(new SimpleStatusResponse("failed"));
}
diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/scheduleInfos/BasicScheduleFieldInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/scheduleInfos/BasicScheduleFieldInfo.java
index 636b381..245140e 100644
--- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/scheduleInfos/BasicScheduleFieldInfo.java
+++ b/backend/src/main/java/core/api/models/timemanager/taskSchedule/scheduleInfos/BasicScheduleFieldInfo.java
@@ -8,6 +8,7 @@ import java.time.LocalDate;
public class BasicScheduleFieldInfo extends ScheduleFieldInfo{
@NotNull
+ @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
private LocalDate scheduleDate;
public BasicScheduleFieldInfo(LocalDate localDate) {
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 7c0a94c..31b612f 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -11,6 +11,7 @@ import {MissedSchedulesComponent} from "./missed-schedules/missed-schedules.comp
import {OverdueTaskOverviewComponent} from "./overdue-task-overview/overdue-task-overview.component";
import {UpcomingTaskOverviewComponent} from "./upcoming-task-overview/upcoming-task-overview.component";
import {ActiveTaskOverviewComponent} from "./active-task-overview/active-task-overview.component";
+import {DraggableSchedulerComponent} from "./schedules/draggable-scheduler/draggable-scheduler.component";
const routes: Routes = [
{path: '', component: MainComponent},
@@ -24,7 +25,8 @@ const routes: Routes = [
{path: 'reschedule', component: MissedSchedulesComponent},
{path: 'overdue', component: OverdueTaskOverviewComponent},
{path: 'upcoming', component: UpcomingTaskOverviewComponent},
- {path: 'active', component: ActiveTaskOverviewComponent}
+ {path: 'active', component: ActiveTaskOverviewComponent},
+ {path: 'scheduler', component: DraggableSchedulerComponent}
];
@NgModule({
diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html
index c242a74..ab245f6 100644
--- a/frontend/src/app/app.component.html
+++ b/frontend/src/app/app.component.html
@@ -4,6 +4,7 @@
+
diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts
index f68fa17..780c6bf 100644
--- a/frontend/src/app/app.module.ts
+++ b/frontend/src/app/app.module.ts
@@ -79,6 +79,7 @@ import {NgxMaterialTimepickerModule} from "ngx-material-timepicker";
import { DateTimePickerComponent } from './date-time-picker/date-time-picker.component';
import {MatSliderModule} from "@angular/material/slider";
import {MatLegacySliderModule} from "@angular/material/legacy-slider";
+import { DraggableSchedulerComponent } from './schedules/draggable-scheduler/draggable-scheduler.component';
@NgModule({
declarations: [
AppComponent,
@@ -117,7 +118,8 @@ import {MatLegacySliderModule} from "@angular/material/legacy-slider";
UpcomingTaskOverviewComponent,
ActiveTaskOverviewComponent,
AdvancedSchedulerComponent,
- DateTimePickerComponent
+ DateTimePickerComponent,
+ DraggableSchedulerComponent,
],
imports: [
BrowserModule,
diff --git a/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.css b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.css
new file mode 100644
index 0000000..e7a217e
--- /dev/null
+++ b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.css
@@ -0,0 +1,57 @@
+.container {
+ margin: 20px auto;
+ width: 80%;
+}
+
+.spacer {
+ margin-bottom: 2.5%;
+}
+
+
+@media screen and (max-width: 600px) {
+ .container {
+ width: 100%;
+ margin: 20px 10px;
+ }
+}
+
+.schedule-header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.long-form {
+ width: 100%;
+}
+
+.taskgroup-overview {
+ width: 90%;
+ display: inline-block;
+}
+
+app-task-overview {
+ margin-top: 20px;
+}
+
+::ng-deep .mat-mdc-list-base {
+ --mdc-list-list-item-label-text-color: black
+}
+
+::ng-deep .mat-mdc-list-base .taskgroup-btn, ::ng-deep .mat-mdc-list-base .taskgroup-last-btn {
+ --mdc-list-list-item-label-text-color: black
+}
+
+.task-card {
+ background-color: #f3f3f3;
+ border: 0;
+ line-height: 4em;
+}
+
+
+.lightBlueBtn {
+ background-color: #3498db;
+ color: white;
+}
+
diff --git a/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.html b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.html
new file mode 100644
index 0000000..8abe77b
--- /dev/null
+++ b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.html
@@ -0,0 +1,53 @@
+
+
diff --git a/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.spec.ts b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.spec.ts
new file mode 100644
index 0000000..786eca5
--- /dev/null
+++ b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DraggableSchedulerComponent } from './draggable-scheduler.component';
+
+describe('DraggableSchedulerComponent', () => {
+ let component: DraggableSchedulerComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [DraggableSchedulerComponent]
+ });
+ fixture = TestBed.createComponent(DraggableSchedulerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.ts b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.ts
new file mode 100644
index 0000000..9c32487
--- /dev/null
+++ b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.ts
@@ -0,0 +1,221 @@
+import {Component, ViewChild} from '@angular/core';
+import {NavigationLink, NavigationLinkListComponent} from "../../navigation-link-list/navigation-link-list.component";
+import {
+ AdvancedScheduleInfo,
+ BasicScheduleInfo,
+ ScheduleInfo,
+ ScheduleService,
+ TaskEntityInfo,
+ TaskgroupEntityInfo,
+ TaskOverviewInfo
+} from "../../../api";
+import {Subject} from "rxjs";
+import {CalendarEvent, CalendarEventTimesChangedEvent, CalendarView} from "angular-calendar";
+import {TaskOverviewData} from "../../dashboard/taskgroup-overview/taskgroup-overview.component";
+import {EventColor} from "calendar-utils";
+import * as moment from "moment";
+
+const colors: Record = {
+ red: {
+ primary: '#ad2121',
+ secondary: '#FAE3E3',
+ },
+ blue: {
+ primary: '#1e90ff',
+ secondary: '#D1E8FF',
+ },
+ yellow: {
+ primary: '#e3bc08',
+ secondary: '#FDF1BA',
+ },
+};
+@Component({
+ selector: 'app-draggable-scheduler',
+ templateUrl: './draggable-scheduler.component.html',
+ styleUrls: ['./draggable-scheduler.component.css']
+})
+export class DraggableSchedulerComponent {
+ defaultNavigationLinkPath: NavigationLink[] = [
+ {
+ linkText: "Dashboard",
+ routerLink: ['/']
+ },
+ {
+ linkText: "Taskgroups",
+ routerLink: ["/taskgroups"]
+ }
+ ]
+ taskgroups: TaskgroupEntityInfo[] = []
+ taskgroup: TaskgroupEntityInfo | undefined
+ taskgroupPath: TaskgroupEntityInfo[] = []
+ taskgroupID: number = -1;
+ scheduleID: number = -1;
+ editedSchedule: ScheduleInfo | undefined
+ @ViewChild('navLinkList') navLinkListComponent: NavigationLinkListComponent | undefined
+
+ task: TaskEntityInfo | undefined
+ scheduleStrategy: number = 1
+
+
+ /**************************************************/
+ //Calendar-Stuff
+ /**************************************************/
+ view: CalendarView = CalendarView.Week;
+ viewDate = new Date();
+ daysInWeek = 7;
+ refresh: Subject = new Subject()
+ events: CalendarEvent[] = []
+
+
+ tasks: CalendarEvent[] = []
+ selectedTaskgroupID: number | undefined
+
+ constructor(private scheduleService: ScheduleService) {
+ }
+
+ ngOnInit() {
+ this.scheduleService.schedulesGet().subscribe({
+ next: resp => {
+ resp.forEach(schedule => {
+ if(schedule.scheduleType == 'BASIC') {
+ const basicSchedule = schedule as BasicScheduleInfo
+ this.events.push({
+ title: schedule.task.taskName,
+ color: colors['red'],
+ start: new Date(basicSchedule.scheduleDate),
+ allDay: true,
+ draggable: true,
+ resizable: {
+ beforeStart: true,
+ afterEnd: true
+ },
+ meta: {
+ taskID: schedule.task.taskID,
+ scheduleID: schedule.scheduleID
+ }
+ })
+ } else {
+ const advancedSchedule = schedule as AdvancedScheduleInfo
+ this.events.push({
+ title: schedule.task.taskName,
+ color: colors['red'],
+ start: new Date(advancedSchedule.scheduleStartTime),
+ end: new Date(advancedSchedule.scheduleStopTime),
+ draggable: true,
+ resizable: {
+ beforeStart: true,
+ afterEnd: true
+ },
+ meta: {
+ taskID: schedule.task.taskID,
+ scheduleID: schedule.scheduleID
+ }
+ })
+ }
+ });
+ this.refresh.next();
+ }
+ })
+ }
+
+ onSelectTaskgroup(taskOverviewData: TaskOverviewData) {
+ this.tasks = [];
+ taskOverviewData.tasks.forEach(task => {
+ this.tasks.push({
+ title: task.taskName,
+ color: colors['yellow'],
+ start: new Date(),
+ draggable: true,
+ resizable: {
+ beforeStart: true,
+ afterEnd: true
+ },
+ meta: {
+ taskID: task.taskID,
+ scheduleID: undefined
+ }
+ })
+ })
+ this.selectedTaskgroupID = taskOverviewData.taskgroupID;
+ }
+
+
+ externalDrop(event: CalendarEvent) {
+ if (this.tasks.indexOf(event) === -1) {
+ this.events = this.events.filter((iEvent) => iEvent !== event);
+ this.tasks.push(event);
+ }
+ }
+
+ eventDropped({
+ event,
+ newStart,
+ newEnd,
+ allDay,
+ }: CalendarEventTimesChangedEvent): void {
+ const externalIndex = this.tasks.indexOf(event);
+ if (typeof allDay !== 'undefined') {
+ event.allDay = allDay;
+ }
+ if (externalIndex > -1) {
+ this.tasks.splice(externalIndex, 1);
+ this.events.push(event);
+ }
+
+ event.start = newStart;
+ if (newEnd) {
+ event.end = newEnd;
+ }
+ this.events = [...this.events];
+
+ if(externalIndex > -1) {
+ //Create new schedule as a new event was dropped
+ if(event.allDay) {
+ this.scheduleService.schedulesTaskIDBasicPut(event.meta.taskID,{
+ scheduleDate: moment(event.start).format('YYYY-MM-DDTHH:mm:ss.SSSZ')
+ }).subscribe({
+ next: resp => {
+ event.meta.scheduleID = resp.scheduleID;
+ event.color = colors['red']
+ }
+ })
+ } else {
+ console.log("Start: " + event.start);
+ console.log("End: " + event.end);
+ if(event.end == undefined) {
+ event.end = moment(event.start).add(30, 'm').toDate()
+ }
+ this.scheduleService.schedulesTaskIDAdvancedPut(event.meta.taskID, {
+ scheduleStartTime: moment(event.start).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
+ scheduleStopTime: moment(event.end).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
+ }).subscribe({
+ next: resp => {
+ event.meta.scheduleID = resp.scheduleID;
+ event.color = colors['red']
+ }
+ })
+ }
+ } else {
+ if(event.allDay) {
+ this.scheduleService.schedulesScheduleIDBasicPost(event.meta.scheduleID,{
+ scheduleDate: moment(event.start).format('YYYY-MM-DDTHH:mm:ss.SSSZ')
+ }).subscribe({
+ next: resp => {
+ console.log("Updated")
+ }
+ })
+ } else {
+ this.scheduleService.schedulesScheduleIDAdvancedPost(event.meta.scheduleID, {
+ scheduleStartTime: moment(event.start).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
+ scheduleStopTime: moment(event.end).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
+ }).subscribe({
+ next: resp => {
+ console.log("Updated")
+ }
+ })
+ }
+ }
+ }
+
+
+}