Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A user can set a due date #27 #78

Closed
13 changes: 6 additions & 7 deletions src/main/java/com/coyoapp/tinytask/domain/Task.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
package com.coyoapp.tinytask.domain;

import java.time.Instant;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.time.Instant;
import java.time.LocalDateTime;

@Table(name = "task")
@Entity
@Setter
Expand All @@ -28,6 +25,8 @@ public class Task {

private String name;

private LocalDateTime dueDate;

@CreatedDate
private Instant created;
}
8 changes: 7 additions & 1 deletion src/main/java/com/coyoapp/tinytask/dto/TaskRequest.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.coyoapp.tinytask.dto;

import javax.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.FutureOrPresent;
import javax.validation.constraints.NotEmpty;
import java.time.LocalDateTime;

@Data
@Builder
@NoArgsConstructor
Expand All @@ -15,4 +18,7 @@ public class TaskRequest {
@NotEmpty
private String name;

@FutureOrPresent
private LocalDateTime dueDate;

}
6 changes: 6 additions & 0 deletions src/main/java/com/coyoapp/tinytask/dto/TaskResponse.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.coyoapp.tinytask.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@Builder
@NoArgsConstructor
Expand All @@ -14,4 +17,7 @@ public class TaskResponse {
private String id;

private String name;

@JsonFormat(pattern = "MM/dd/yyyy HH:mm")
private LocalDateTime dueDate;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
import com.coyoapp.tinytask.domain.Task;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface TaskRepository extends JpaRepository<Task, String> {
List<Task> findAllByOrderByDueDateAscCreatedAsc();
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
import com.coyoapp.tinytask.dto.TaskResponse;
import com.coyoapp.tinytask.exception.TaskNotFoundException;
import com.coyoapp.tinytask.repository.TaskRepository;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import static java.util.stream.Collectors.toList;

@Slf4j
Expand All @@ -34,7 +35,7 @@ public TaskResponse createTask(TaskRequest taskRequest) {
@Transactional(readOnly = true)
public List<TaskResponse> getTasks() {
log.debug("getTasks()");
return taskRepository.findAll().stream().map(this::transformToResponse).collect(toList());
return taskRepository.findAllByOrderByDueDateAscCreatedAsc().stream().map(this::transformToResponse).collect(toList());
}

private TaskResponse transformToResponse(Task task) {
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/db/migration/V2__Due_Date.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE task ADD due_date TIMESTAMP WITH TIME ZONE;
5 changes: 3 additions & 2 deletions src/main/webapp/app/app.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
width: 90vw;
min-width: 200px;
max-width: 600px;
height: 20vh;
height: auto;
min-height: 80px;
max-height: 240px;
}
Expand All @@ -28,9 +28,10 @@
margin: 0;
text-align: center;
user-select: none;
margin-bottom:40px;
}
}

.content {
margin-top: -40px;
}
}
4 changes: 2 additions & 2 deletions src/main/webapp/app/tasks/default-task.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export class DefaultTaskService implements TaskService {
constructor(private http: HttpClient, @Inject(BASE_URL) private baseUrl: string) {
}

create(name: string): Observable<Task> {
return this.http.post<Task>(this.baseUrl + '/tasks', {name: name} as Task);
create(name: string, dueDate: Date): Observable<Task> {
return this.http.post<Task>(this.baseUrl + '/tasks', {name: name, dueDate: dueDate} as Task);
}

delete(id: string): Observable<void> {
Expand Down
4 changes: 2 additions & 2 deletions src/main/webapp/app/tasks/local-task.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ export class LocalTaskService implements TaskService {
return of(this.readTasks());
}

create(name: string): Observable<Task> {
create(name: string, dueDate: Date): Observable<Task> {
const tasks = this.readTasks();
const task = {id: uuid(), name};
const task = {id: uuid(), name, dueDate};
tasks.push(task);
this.writeTasks(tasks);
return of(task);
Expand Down
20 changes: 18 additions & 2 deletions src/main/webapp/app/tasks/task-form/task-form.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
<form [formGroup]="taskForm" (ngSubmit)="onSubmit()">
<form (ngSubmit)="onSubmit()" [formGroup]="taskForm">
<mat-form-field>
<input type="text" formControlName="name" matInput placeholder="Add a new tiny task…" data-cy="task-input">
<input data-cy="task-input" formControlName="name" matInput placeholder="Add a new tiny task…" type="text">
</mat-form-field>

<mat-form-field>
<input [matDatepicker]="picker" [min]="startDate" formControlName="dueDate" matInput
placeholder="Choose a due date">
<mat-datepicker-toggle [for]="picker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #picker [startAt]="startDate"></mat-datepicker>

</mat-form-field>

<mat-form-field>
<input formControlName="time" matInput placeholder="Time" type="time">
</mat-form-field>

<button color="warn" mat-raised-button style="flex:1" type="submit">Add task</button>


</form>
7 changes: 4 additions & 3 deletions src/main/webapp/app/tasks/task-form/task-form.component.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
form {
display: flex;
align-items: center;
display: flex;
align-items: center;
flex-wrap:wrap;
}

.mat-form-field {
flex: 1;
flex: 2;
}
12 changes: 10 additions & 2 deletions src/main/webapp/app/tasks/task-form/task-form.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,25 @@ import { TaskService } from '../task.service';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TaskFormComponent {
startDate = new Date();

@Output() created: EventEmitter<Task> = new EventEmitter();

taskForm: FormGroup = new FormGroup({
name: new FormControl('', Validators.required)
name: new FormControl('', Validators.required),
dueDate: new FormControl(''),
time: new FormControl('')
});

constructor(@Inject('TaskService') private taskService: TaskService) { }

onSubmit(): void {
this.taskService.create(this.taskForm.value.name).subscribe(task => {
if(this.taskForm.value.dueDate && this.taskForm.value.time){

Choose a reason for hiding this comment

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

I would use the patchValue method here and move the setting of the time to date into a specific private method. Like:
` onSubmit(): void {
if (this.taskForm.value.dueDate && this.taskForm.value.time) {
this.taskForm.patchValue({dueDate: this.setTimeToDate(this.taskForm.value.dueDate, this.taskForm.value.time)});
}
this.taskService.create(this.taskForm.value.name, this.taskForm.value.dueDate).subscribe(task => {
this.created.emit(task);
this.taskForm.reset();
});
}

private setTimeToDate(date: Date, time: string): string {
const hour = +time.split(':')[0];
const minute = +time.split(':')[1];
date.setHours(hour, minute);
return date.toISOString();
}`

const hour = this.taskForm.value.time.split(':')[0];
const minute = this.taskForm.value.time.split(':')[1];
this.taskForm.value.dueDate.setHours(hour, minute);
}
this.taskService.create(this.taskForm.value.name,this.taskForm.value.dueDate).subscribe(task => {
this.created.emit(task);
this.taskForm.reset();
});
Expand Down
10 changes: 7 additions & 3 deletions src/main/webapp/app/tasks/task-list/task-list.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
<mat-list-item *ngFor="let task of tasks" class="mat-elevation-z1">
<mat-icon mat-list-icon>assignment</mat-icon>
<h4 mat-line>{{task.name}}</h4>
<p *ngIf="task.dueDate; else other_content" mat-line>Due Date: {{task.dueDate | date:'full' :'+0200'}}</p>
<ng-template #other_content>
<p mat-line>Due Date: No due date for this task</p>
</ng-template>
<p mat-line>ID: {{task.id}}</p>
<button mat-icon-button color="primary">
<mat-icon aria-label="Delete task" (click)="delete(task)">delete</mat-icon>
<button color="primary" mat-icon-button>
<mat-icon (click)="delete(task)" aria-label="Delete task">delete</mat-icon>
</button>
</mat-list-item>
</mat-list>
</mat-list>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.mat-list-item {
background: #fff;
margin: 16px 0;
margin: 35px 0;
}

.mat-list-icon {
Expand Down
2 changes: 1 addition & 1 deletion src/main/webapp/app/tasks/task.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface TaskService {
* @param name the task's name
* @returns an `Observable` holding the created task
*/
create(name: string): Observable<Task>;
create(name: string, dueDate: Date): Observable<Task>;

Choose a reason for hiding this comment

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

dueDate should be optional in my opinion.


/**
* Removes the task with the given ID from the list of tasks.
Expand Down
1 change: 1 addition & 0 deletions src/main/webapp/app/tasks/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
export interface Task {
id: string;
name: string;
dueDate: Date;
}
5 changes: 4 additions & 1 deletion src/main/webapp/app/tasks/tasks.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import {MatDatepickerModule, MatNativeDateModule} from '@angular/material';

import { TaskFormComponent } from './task-form/task-form.component';
import { TaskListComponent } from './task-list/task-list.component';
Expand All @@ -17,7 +18,9 @@ import { TaskListComponent } from './task-list/task-list.component';
MatButtonModule,
MatIconModule,
MatInputModule,
MatListModule
MatListModule,
MatDatepickerModule,
MatNativeDateModule
],
exports: [TaskFormComponent, TaskListComponent]
})
Expand Down