Skip to content

Commit

Permalink
feat(notes): handle note editing and saving
Browse files Browse the repository at this point in the history
  • Loading branch information
faouziMohamed committed Jun 30, 2023
1 parent 038b871 commit b2d6d75
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 30 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"push-release": "git push --follow-tags origin main",
"prepare": "husky install",
"container:run": "docker compose -f docker-compose.yml up",
"container:build": "docker build -t mfaouzi ."
"container:build": "docker build -t trakz ."
},
"private": true,
"dependencies": {
Expand Down
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { LayoutModule } from '@angular/cdk/layout';
import { DatePipe, NgOptimizedImage } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatLineModule } from '@angular/material/core';
import { MatIconModule } from '@angular/material/icon';
Expand Down Expand Up @@ -93,6 +94,7 @@ import { TaskGroupListComponent } from './pages/tasks/task-group-list/task-group
NgOptimizedImage,
HttpClientModule,
MatLineModule,
FormsModule,
],
providers: [DatePipe],
bootstrap: [AppComponent],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@
>
</app-task-detail>
</div>
<app-task-note [note]="task.note"></app-task-note>
<app-task-note
*ngIf="shouldShowNoteTextarea"
[task]="task"
></app-task-note>
</div>
</div>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export class RightSidebarComponent implements OnDestroy, OnInit {

currentTaskId: string | undefined;

shouldShowNoteTextarea = true;

protected readonly Date = Date;

protected readonly capitalizeFirstLetter = capitalizeFirstLetter;
Expand Down Expand Up @@ -57,16 +59,19 @@ export class RightSidebarComponent implements OnDestroy, OnInit {
this._taskObserver = this._tasksService
.getSelectedTask()
.subscribe((task) => {
if (task) {
const taskId = taskGeneratedId(task);
// If clicked on the same task, close the right sidebar
if (taskId === this.currentTaskId) {
this.onRightSidebarClose();
return;
}
this.task = task;
this.currentTaskId = taskId;
if (!task) {
this.shouldShowNoteTextarea = false;
return;
}
this.shouldShowNoteTextarea = false;
this.shouldShowNoteTextarea = true;
const taskId = taskGeneratedId(task);
if (taskId === this.currentTaskId) {
this.onRightSidebarClose();
return;
}
this.task = task;
this.currentTaskId = taskId;
});
}

Expand All @@ -85,6 +90,7 @@ export class RightSidebarComponent implements OnDestroy, OnInit {
}

onRightSidebarClose() {
this.shouldShowNoteTextarea = false;
this._tasksService.setSelectedTask(null);
this.task = undefined;
this.currentTaskId = undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@
class="bg-inherit !flex border-gray-300 focus-within:border-gray-400 rounded border !flex-col"
>
<textarea
(keyup)="onUserTyping($event)"
[(ngModel)]="task.note.content"
class="w-full h-32 p-2 border-none resize-none focus-visible:outline-none rounded bg-inherit !text-[0.78rem] text-slate-600"
placeholder="Add a note"
>{{ note?.content || '' }}</textarea
>{{ task.note?.content || '' }}</textarea
>
<ng-container *ngIf="note">
<ng-container *ngIf="task.note">
<mat-divider class="opacity-30"></mat-divider>
<small class="text-gray-500 !text-[0.68rem] p-0.5 text-center">
Updated on {{ note.updatedAt | date : 'EEE, MMM d' }}
<small
*ngIf="!isTaskBeingUpdate"
class="text-gray-500 !text-[0.68rem] p-0.5 text-center"
>
Last saved {{ getLastUpdateDate() }}
</small>
<small
*ngIf="isTaskBeingUpdate"
class="text-gray-500 !text-[0.68rem] p-0.5 text-center"
>
Saving...
</small>
</ng-container>
</div>
Original file line number Diff line number Diff line change
@@ -1,12 +1,49 @@
import { Component, Input } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { debounceTime, distinctUntilChanged, Subject, switchMap } from 'rxjs';

import { TaskNote } from '@/models/task';
import { Task } from '@/models/task';
import { TaskService } from '@/services/tasks/task.service';
import { passedTimeFormatted } from '@/utils/trakzUtils';

@Component({
selector: 'app-task-note',
templateUrl: './task-note.component.html',
styleUrls: ['./task-note.component.scss'],
})
export class TaskNoteComponent {
@Input() note: TaskNote | undefined;
export class TaskNoteComponent implements OnInit {
@Input() task: Task = {} as Task;

withRefresh = false;

isTaskBeingUpdate = false;

private typedNoteText$ = new Subject<string>();

constructor(private _tasksService: TaskService) {}

ngOnInit() {
this.typedNoteText$
.pipe(
debounceTime(1000),
distinctUntilChanged(),
switchMap((content) => {
this.task.note.content = content;
this.isTaskBeingUpdate = true;
return this._tasksService.updateTask(this.task);
}),
)
.subscribe((task) => {
this.task = task;
this.isTaskBeingUpdate = false;
});
}

onUserTyping(event: Event) {
const content = (event.target as HTMLTextAreaElement).value;
this.typedNoteText$.next(content);
}

getLastUpdateDate() {
return passedTimeFormatted(this.task.note.updatedAt);
}
}
6 changes: 3 additions & 3 deletions src/app/models/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export interface TaskStep extends TimeStampsDate {

export interface TaskNote {
content: string | '';
createdAt?: TimeStampsDate['createdAt'];
updatedAt?: TimeStampsDate['updatedAt'];
createdAt: TimeStampsDate['createdAt'];
updatedAt: TimeStampsDate['updatedAt'];
}

export interface Folder {
Expand All @@ -48,7 +48,7 @@ export interface Task extends TimeStampsDate {
isCompleted: boolean;
steps: TaskStep[];
recurrence?: Recurrence | null;
note?: TaskNote;
note: TaskNote;
}

export enum TaskStatus {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export class AddTaskInputComponent implements OnInit {
.subscribe((task) => {
// eslint-disable-next-line no-param-reassign
taskInput.value = '';

// scroll to the task that was just added to the list of tasks in the DOM
setTimeout(() => {
AddTaskInputComponent.scrollInToNewAddedTask(task);
Expand Down
14 changes: 13 additions & 1 deletion src/app/services/tasks/task.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,11 @@ export class TaskService {
isImportant: isImportant ?? false,
steps: steps ?? [],
recurrence: recurrence ?? 'ONCE',
note: note ?? { content: '' },
note: note ?? {
content: '',
updatedAt: new Date(),
createdAt: new Date(),
},
};
}

Expand Down Expand Up @@ -363,6 +367,12 @@ export class TaskService {
);
};

// private _updateTaskNote$ = (note: string, taskID: number) => {
// return this.http.patch<TaskNote>(`${this.apiUrl}/tasks/${taskID}/note`, {
// content: note,
// });
// };

private _updateTask$ = (task: Task): Observable<Task> => {
const { id } = task;
const url = `${this.apiUrl}/tasks/${id}`;
Expand Down Expand Up @@ -429,6 +439,8 @@ export class TaskService {
res.data.createdAt = newTask.createdAt;
res.data.updatedAt = newTask.updatedAt;
this.updateTask(res.data);
newTask.id = res.data.id;

this._snackBar.open('Task added successfully', 'Dismiss', {
duration: 2000,
});
Expand Down
59 changes: 52 additions & 7 deletions src/app/utils/trakzUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,22 @@ export function isOverdue(date: Date) {

export function isToday(date: Date | string) {
const today = new Date();
const dueDate = new Date(date);
const comparedDate = new Date(date);
return (
dueDate.getDate() === today.getDate() &&
dueDate.getMonth() === today.getMonth() &&
dueDate.getFullYear() === today.getFullYear() &&
dueDate.getHours() <= 23 &&
dueDate.getMinutes() <= 59 &&
dueDate.getSeconds() <= 59
comparedDate.getDate() === today.getDate() &&
comparedDate.getMonth() === today.getMonth() &&
comparedDate.getFullYear() === today.getFullYear() &&
comparedDate.getHours() <= 23 &&
comparedDate.getMinutes() <= 59 &&
comparedDate.getSeconds() <= 59
);
}

export function isThisYear(date: Date) {
const today = new Date();
return date.getFullYear() === today.getFullYear();
}

export function capitalizeFirstLetter(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
}
Expand Down Expand Up @@ -152,3 +157,43 @@ export function taskGeneratedId(task: Task): string {
const d2 = toDateString(task.updatedAt);
return `${d1}${d2}${task.folderName}`;
}

/**
* - If today show time only (h:mm a) else show date and time (EEE, MMM d y, h:mm a)
* - If yesterday show 'Yesterday at ' + time (h:mm a)
* - If this year show date and time (EEE, MMM d, h:mm a)
* - else show date only (EEE, MMM d y)
* @example: Today at 2:30 PM, Yesterday at 2:30 PM, Mon, Jan 1, 2021, 2:30 PM, Mon, Jan 1, 2021
* @param date
* @param locale
* */
export function passedTimeFormatted(date: string | Date, locale = 'en-US') {
const usedDate = new Date(date);
const formatOpt: Record<
'today' | 'yesterday' | 'thisYear' | 'other',
Intl.DateTimeFormatOptions
> = {
today: { hour: 'numeric', minute: 'numeric' },
yesterday: { hour: 'numeric', minute: 'numeric' },
thisYear: { weekday: 'short', hour: 'numeric', minute: 'numeric' },
other: {
weekday: 'short',
month: 'short',
day: 'numeric',
year: 'numeric',
},
};
const toDayYesterdayFmt = new Intl.DateTimeFormat(locale, formatOpt.today);
if (isToday(usedDate)) {
return `Today at ${toDayYesterdayFmt.format(usedDate)}`;
}
if (isYesterday(usedDate)) {
return `Yesterday at ${toDayYesterdayFmt.format(usedDate)}`;
}
const thisYearFmt = new Intl.DateTimeFormat(locale, formatOpt.thisYear);
if (isThisYear(usedDate)) {
return thisYearFmt.format(usedDate);
}
const otherFmt = new Intl.DateTimeFormat(locale, formatOpt.other);
return otherFmt.format(usedDate);
}

1 comment on commit b2d6d75

@vercel
Copy link

@vercel vercel bot commented on b2d6d75 Jun 30, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.