Add toggle messages
This commit is contained in:
parent
d4332dce35
commit
ad272300eb
17 changed files with 364 additions and 26 deletions
|
|
@ -27,7 +27,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"@angular/material/prebuilt-themes/azure-blue.css",
|
"@angular/material/prebuilt-themes/magenta-violet.css",
|
||||||
"src/styles.css"
|
"src/styles.css"
|
||||||
],
|
],
|
||||||
"scripts": [],
|
"scripts": [],
|
||||||
|
|
|
||||||
29
db.json
29
db.json
|
|
@ -1,5 +1,30 @@
|
||||||
{
|
{
|
||||||
"tasks": [],
|
"tasks": [
|
||||||
|
{
|
||||||
|
"id": "a2e6",
|
||||||
|
"title": "Teste",
|
||||||
|
"categoryId": "1",
|
||||||
|
"isCompleted": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9992",
|
||||||
|
"title": "Testeasdas",
|
||||||
|
"categoryId": "1",
|
||||||
|
"isCompleted": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c544",
|
||||||
|
"title": "treinar",
|
||||||
|
"categoryId": "1",
|
||||||
|
"isCompleted": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ecc9",
|
||||||
|
"title": "treinar 2",
|
||||||
|
"categoryId": "1",
|
||||||
|
"isCompleted": false
|
||||||
|
}
|
||||||
|
],
|
||||||
"categories": [
|
"categories": [
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "1",
|
||||||
|
|
@ -27,4 +52,4 @@
|
||||||
"color": "purple"
|
"color": "purple"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
17
package-lock.json
generated
17
package-lock.json
generated
|
|
@ -8,6 +8,7 @@
|
||||||
"name": "my-task-board-angular",
|
"name": "my-task-board-angular",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@angular/animations": "^19.2.6",
|
||||||
"@angular/cdk": "^19.2.9",
|
"@angular/cdk": "^19.2.9",
|
||||||
"@angular/common": "^19.2.0",
|
"@angular/common": "^19.2.0",
|
||||||
"@angular/compiler": "^19.2.0",
|
"@angular/compiler": "^19.2.0",
|
||||||
|
|
@ -393,6 +394,22 @@
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@angular/animations": {
|
||||||
|
"version": "19.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-19.2.6.tgz",
|
||||||
|
"integrity": "sha512-0Ei7pKXpq0eoijakRB+TQCh2EB02ReYUzRkhdw5kbQLOlTftBWWnMNn2qRfKU6cra+RyRXU8c34ZkEw6K7hZAw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.19.1 || ^20.11.1 || >=22.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": "19.2.6",
|
||||||
|
"@angular/core": "19.2.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@angular/build": {
|
"node_modules/@angular/build": {
|
||||||
"version": "19.2.7",
|
"version": "19.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/build/-/build-19.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/build/-/build-19.2.7.tgz",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@angular/animations": "^19.2.6",
|
||||||
"@angular/cdk": "^19.2.9",
|
"@angular/cdk": "^19.2.9",
|
||||||
"@angular/common": "^19.2.0",
|
"@angular/common": "^19.2.0",
|
||||||
"@angular/compiler": "^19.2.0",
|
"@angular/compiler": "^19.2.0",
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
||||||
import { provideRouter } from '@angular/router';
|
import { provideRouter } from '@angular/router';
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
|
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
|
||||||
|
import { provideAnimations } from '@angular/platform-browser/animations';
|
||||||
import { provideHttpClient, withFetch } from '@angular/common/http'
|
import { provideHttpClient, withFetch } from '@angular/common/http'
|
||||||
import { providerThemeInitializer } from './initializers/theme-initializer';
|
import { providerThemeInitializer } from './initializers/theme-initializer';
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [
|
providers: [
|
||||||
|
|
@ -11,6 +12,7 @@ export const appConfig: ApplicationConfig = {
|
||||||
provideRouter(routes),
|
provideRouter(routes),
|
||||||
provideClientHydration(withEventReplay()),
|
provideClientHydration(withEventReplay()),
|
||||||
provideHttpClient(withFetch()),
|
provideHttpClient(withFetch()),
|
||||||
|
provideAnimations(),
|
||||||
providerThemeInitializer,
|
providerThemeInitializer,
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,15 @@
|
||||||
export const categoryBackgroundColors: Record<string,string> = {
|
export const categoryBackgroundColors: Record<string, string> = {
|
||||||
green: 'bg-green-600',
|
green: 'bg-green-600',
|
||||||
orange: 'bg-orange-600',
|
orange: 'bg-yellow-600',
|
||||||
red: 'bg-red-600',
|
red: 'bg-red-600',
|
||||||
blue: 'bg-blue-600',
|
blue: 'bg-blue-600',
|
||||||
purple: 'bg-purple-600',
|
purple: 'bg-purple-600',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const categoryBackgroundIdColors: Record<string, string> = {
|
||||||
|
'1': 'bg-green-600',
|
||||||
|
'2': 'bg-yellow-600',
|
||||||
|
'3': 'bg-red-600',
|
||||||
|
'4': 'bg-blue-600',
|
||||||
|
'5': 'bg-purple-600',
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable, signal } from '@angular/core';
|
||||||
|
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Category } from '../model/category.model';
|
import { Category } from '../model/category.model';
|
||||||
|
|
@ -17,4 +17,6 @@ export class CategoryService {
|
||||||
public categories = toSignal(this.categories$, {
|
public categories = toSignal(this.categories$, {
|
||||||
initialValue: [] as Category[],
|
initialValue: [] as Category[],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
public selectedCategoryId = signal('1')
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { CategoryService } from './../../../../category/services/category.service';
|
||||||
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
computed,
|
||||||
|
DestroyRef,
|
||||||
|
inject,
|
||||||
|
OnInit,
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatSelectChange, MatSelectModule } from '@angular/material/select';
|
||||||
|
import { createTaskForm } from '../../../constants/create-task-form';
|
||||||
|
import { Task } from '../../../model/task.model';
|
||||||
|
import { TaskService } from '../../../service/task.service';
|
||||||
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
import { delay, finalize } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { NgClass } from '@angular/common';
|
||||||
|
import { SnackBarService } from '../../../../../shared/services/snack-bar.service';
|
||||||
|
import { throws } from 'assert';
|
||||||
|
|
||||||
|
const MODULES = [
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatSelectModule,
|
||||||
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
];
|
||||||
|
|
||||||
|
// const COMPONENTS: never[] = [];
|
||||||
|
|
||||||
|
const COMMONS = [NgClass];
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-include-task-form',
|
||||||
|
standalone: true,
|
||||||
|
imports: [...COMMONS, ...MODULES],
|
||||||
|
template: `
|
||||||
|
<form
|
||||||
|
[ngClass]="{
|
||||||
|
'cursor-not-allowed animate-pulse': isIncludeTaskFormDisabled(),
|
||||||
|
'cursor-pointer': !isIncludeTaskFormDisabled()
|
||||||
|
}"
|
||||||
|
autocomplete="off"
|
||||||
|
class="flex flex-row gap-2 select-none"
|
||||||
|
[formGroup]="newsTaskForm"
|
||||||
|
>
|
||||||
|
<mat-form-field class="w-full">
|
||||||
|
<mat-label>Tarefas</mat-label>
|
||||||
|
<input
|
||||||
|
formControlName="title"
|
||||||
|
matInput
|
||||||
|
placeholder="Adicionar tarefa"
|
||||||
|
(keyup.enter)="onEnterToaddATask()"
|
||||||
|
/>
|
||||||
|
<mat-hint class="text-tertiary">Aperte enter para adicionar</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>Categorias</mat-label>
|
||||||
|
<mat-select
|
||||||
|
formControlName="categoryId"
|
||||||
|
(selectionChange)="selectionChangeHandler($event)"
|
||||||
|
(keyup.enter)="onEnterToaddATask()"
|
||||||
|
>
|
||||||
|
@for(category of categories(); track category.id) {
|
||||||
|
<mat-option value="{{ category.id }}">{{ category.name }}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
`,
|
||||||
|
styles: ``,
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class IncludeTaskFormComponent {
|
||||||
|
private readonly categoryService = inject(CategoryService);
|
||||||
|
|
||||||
|
private readonly taskService = inject(TaskService);
|
||||||
|
|
||||||
|
private readonly snackBarService = inject(SnackBarService);
|
||||||
|
|
||||||
|
private readonly destroy$ = inject(DestroyRef);
|
||||||
|
|
||||||
|
public readonly categories = this.categoryService.categories;
|
||||||
|
|
||||||
|
public readonly newsTaskForm = createTaskForm();
|
||||||
|
|
||||||
|
|
||||||
|
public selectionChangeHandler(event: MatSelectChange): void {
|
||||||
|
const categoryId = event.value;
|
||||||
|
this.categoryService.selectedCategoryId.set(categoryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onEnterToaddATask(): void {
|
||||||
|
if (this.newsTaskForm.invalid) return;
|
||||||
|
|
||||||
|
this.taskService.isLoadingTask.set(true);
|
||||||
|
|
||||||
|
const { categoryId, title } = this.newsTaskForm.value;
|
||||||
|
|
||||||
|
const newTask: Partial<Task> = {
|
||||||
|
title,
|
||||||
|
categoryId,
|
||||||
|
isCompleted: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.taskService
|
||||||
|
.createTask(newTask)
|
||||||
|
.pipe(
|
||||||
|
delay(4000),
|
||||||
|
finalize(() => this.taskService.isLoadingTask.set(false)),
|
||||||
|
takeUntilDestroyed(this.destroy$)
|
||||||
|
)
|
||||||
|
.subscribe({
|
||||||
|
next: (task) => this.taskService.insertATaskInTheTasksList(task),
|
||||||
|
error: (error) => {
|
||||||
|
this.snackBarConfigHandler(error.message)
|
||||||
|
},
|
||||||
|
complete: () => this.snackBarConfigHandler('Tarefa concluida!')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public isIncludeTaskFormDisabled = computed(() => {
|
||||||
|
if (this.taskService.isLoadingTask()) {
|
||||||
|
this.newsTaskForm.disable();
|
||||||
|
|
||||||
|
return this.taskService.isLoadingTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.newsTaskForm.enable();
|
||||||
|
|
||||||
|
return this.taskService.isLoadingTask();
|
||||||
|
});
|
||||||
|
|
||||||
|
public snackBarConfigHandler(message : string): void {
|
||||||
|
this.snackBarService.showSnackBar(
|
||||||
|
message
|
||||||
|
,4000
|
||||||
|
,'end'
|
||||||
|
,'top'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { TaskService } from './../../service/task.service';
|
||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { IncludeTaskFormComponent } from './include-task-form/include-task-form.component';
|
||||||
|
import { CategoryService } from '../../../category/services/category.service';
|
||||||
|
import { categoryBackgroundIdColors } from '../../../category/constants/category-colors';
|
||||||
|
import { NgClass } from '@angular/common';
|
||||||
|
|
||||||
|
const COMPONENTS = [IncludeTaskFormComponent]
|
||||||
|
const COMMONS = [NgClass];
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-inclusion-form',
|
||||||
|
imports: [...COMPONENTS, ...COMMONS],
|
||||||
|
template: `
|
||||||
|
<div class="grid grid-cols-12 gap-2 mt-8">
|
||||||
|
<app-include-task-form class="col-span-11" />
|
||||||
|
|
||||||
|
<div class="colspan-1 flex items-start mt-2">
|
||||||
|
<span
|
||||||
|
[ngClass]="{
|
||||||
|
'opacity-30': taskService.isLoadingTask(),
|
||||||
|
'opacity-100': !taskService.isLoadingTask()
|
||||||
|
}"
|
||||||
|
class=" {{
|
||||||
|
colorVariants[selectedCategoryId()]
|
||||||
|
}} rounded-full w-10 h-10 bg-blue-700"
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
standalone: true,
|
||||||
|
styles: ``,
|
||||||
|
})
|
||||||
|
export class InclusionFormComponent {
|
||||||
|
private readonly categoryService = inject(CategoryService);
|
||||||
|
|
||||||
|
public readonly taskService = inject(TaskService);
|
||||||
|
|
||||||
|
public readonly selectedCategoryId = this.categoryService.selectedCategoryId;
|
||||||
|
|
||||||
|
public colorVariants = categoryBackgroundIdColors;
|
||||||
|
}
|
||||||
27
src/app/features/task/constants/create-task-form.ts
Normal file
27
src/app/features/task/constants/create-task-form.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Task } from './../model/task.model';
|
||||||
|
import { inject } from "@angular/core";
|
||||||
|
import { FormControl, FormGroup, NonNullableFormBuilder, Validators } from "@angular/forms";
|
||||||
|
|
||||||
|
type TaskFormControl = {
|
||||||
|
title: FormControl<string>;
|
||||||
|
categoryId: FormControl<string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createTaskForm(): FormGroup<TaskFormControl> {
|
||||||
|
const formBuilder = inject(NonNullableFormBuilder);
|
||||||
|
|
||||||
|
return formBuilder.group({
|
||||||
|
title: new FormControl('', {
|
||||||
|
validators: [Validators.required, Validators.minLength(3)],
|
||||||
|
nonNullable: true,
|
||||||
|
}),
|
||||||
|
categoryId: new FormControl('1', {
|
||||||
|
validators: [Validators.required],
|
||||||
|
nonNullable: true,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TaskFormGroup = ReturnType<typeof createTaskForm>;
|
||||||
|
|
||||||
|
export type TaskFormValue = ReturnType<TaskFormGroup['getRawValue']>;
|
||||||
|
|
@ -3,6 +3,7 @@ import { TestBed, waitForAsync } from '@angular/core/testing';
|
||||||
import { HttpErrorResponse, provideHttpClient } from '@angular/common/http';
|
import { HttpErrorResponse, provideHttpClient } from '@angular/common/http';
|
||||||
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
|
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
|
||||||
import { TaskService } from './task.service';
|
import { TaskService } from './task.service';
|
||||||
|
import { Task } from '../model/task.model';
|
||||||
|
|
||||||
describe('TaskService', () => {
|
describe('TaskService', () => {
|
||||||
let taskService: TaskService;
|
let taskService: TaskService;
|
||||||
|
|
@ -75,16 +76,16 @@ describe('TaskService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('creatTask', () => {
|
describe('creatTask', () => {
|
||||||
it('should create a new task', waitForAsync(() => {
|
it('should create a new task with waitForAsync', waitForAsync(() => {
|
||||||
taskService.createTask(MOCKED_TASK).subscribe(() => {
|
let task: Task | undefined;
|
||||||
expect(taskService.tasks()[0]).toEqual(MOCKED_TASK);
|
taskService.createTask(MOCKED_TASK).subscribe((response) => {
|
||||||
expect(taskService.tasks().length).toEqual(1);
|
task = response
|
||||||
});
|
});
|
||||||
|
|
||||||
const req = httpTestingController.expectOne(`${baseURL}/tasks`);
|
const req = httpTestingController.expectOne(`${baseURL}/tasks`);
|
||||||
|
|
||||||
req.flush(MOCKED_TASK);
|
req.flush(MOCKED_TASK);
|
||||||
|
expect(task).toEqual(MOCKED_TASK);
|
||||||
expect(req.request.method).toEqual('POST');
|
expect(req.request.method).toEqual('POST');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { HttpClient } from '@angular/common/http';
|
||||||
import { Injectable, computed, inject, signal } from '@angular/core';
|
import { Injectable, computed, inject, signal } from '@angular/core';
|
||||||
import { environment } from '../../../../env/environment.prod';
|
import { environment } from '../../../../env/environment.prod';
|
||||||
import { Observable, tap } from 'rxjs';
|
import { Observable, tap } from 'rxjs';
|
||||||
|
import { setThrowInvalidWriteToSignalError } from '@angular/core/primitives/signals';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
|
|
@ -10,11 +11,13 @@ import { Observable, tap } from 'rxjs';
|
||||||
export class TaskService {
|
export class TaskService {
|
||||||
private readonly httpClient = inject(HttpClient);
|
private readonly httpClient = inject(HttpClient);
|
||||||
|
|
||||||
public tasks = signal<Task[]>([]);
|
private readonly _apiUrl = environment.apiUrl;
|
||||||
|
|
||||||
public numberOfTasks = computed(() => this.tasks().length);
|
public readonly tasks = signal<Task[]>([]);
|
||||||
|
|
||||||
public readonly _apiUrl = environment.apiUrl;
|
public readonly numberOfTasks = computed(() => this.tasks().length);
|
||||||
|
|
||||||
|
public isLoadingTask = signal(false);
|
||||||
|
|
||||||
public getTasks(): Observable<Task[]> {
|
public getTasks(): Observable<Task[]> {
|
||||||
return this.httpClient.get<Task[]>(`${this._apiUrl}/tasks`).pipe(
|
return this.httpClient.get<Task[]>(`${this._apiUrl}/tasks`).pipe(
|
||||||
|
|
@ -32,14 +35,13 @@ export class TaskService {
|
||||||
public createTask(task: Partial<Task>): Observable<Task> {
|
public createTask(task: Partial<Task>): Observable<Task> {
|
||||||
return this.httpClient
|
return this.httpClient
|
||||||
.post<Task>(`${this._apiUrl}/tasks`, task)
|
.post<Task>(`${this._apiUrl}/tasks`, task)
|
||||||
.pipe(tap((tasks) => this.insertATaskInTheTasksList(tasks)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public insertATaskInTheTasksList(newTask: Task): void {
|
public insertATaskInTheTasksList(newTask: Task): void {
|
||||||
const updatedTasks = [...this.tasks(), newTask];
|
this.tasks.update(tasks => {
|
||||||
const sortedTasks = this.getSortedTasks(updatedTasks);
|
const newTasksList = [...tasks, newTask];
|
||||||
|
return this.getSortedTasks(newTasksList);
|
||||||
this.tasks.set(sortedTasks);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public insertATasksList(newTask: Task): void {
|
public insertATasksList(newTask: Task): void {
|
||||||
|
|
@ -54,7 +56,10 @@ export class TaskService {
|
||||||
.pipe(tap((tasks) => this.updateTaskInTheTasksList(tasks)));
|
.pipe(tap((tasks) => this.updateTaskInTheTasksList(tasks)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateIsCompletedStatus(taskId: string, isCompleted: boolean ): Observable<Task> {
|
public updateIsCompletedStatus(
|
||||||
|
taskId: string,
|
||||||
|
isCompleted: boolean
|
||||||
|
): Observable<Task> {
|
||||||
return this.httpClient
|
return this.httpClient
|
||||||
.patch<Task>(`${this._apiUrl}/tasks/${taskId}`, { isCompleted })
|
.patch<Task>(`${this._apiUrl}/tasks/${taskId}`, { isCompleted })
|
||||||
.pipe(tap((tasks) => this.updateTaskInTheTasksList(tasks)));
|
.pipe(tap((tasks) => this.updateTaskInTheTasksList(tasks)));
|
||||||
|
|
@ -73,8 +78,8 @@ export class TaskService {
|
||||||
|
|
||||||
public deleteTask(taskId: string): Observable<Task> {
|
public deleteTask(taskId: string): Observable<Task> {
|
||||||
return this.httpClient
|
return this.httpClient
|
||||||
.delete<Task>(`${this._apiUrl}/tasks/${taskId}`)
|
.delete<Task>(`${this._apiUrl}/tasks/${taskId}`)
|
||||||
.pipe(tap(() => this.deleteATaksInTheTasksList(taskId)));
|
.pipe(tap(() => this.deleteATaksInTheTasksList(taskId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteATaksInTheTasksList(taskId: string): void {
|
public deleteATaksInTheTasksList(taskId: string): void {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,22 @@
|
||||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
|
import { InclusionFormComponent } from '../../components/inclusion-form/inclusion-form.component';
|
||||||
|
|
||||||
|
const COMPONENTS = [InclusionFormComponent];
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-task',
|
selector: 'app-task',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [],
|
imports: [...COMPONENTS],
|
||||||
template: `<p>task works!</p>`,
|
template: ` <div class="flex flex-col mx-10">
|
||||||
|
<!-- Titulo -->
|
||||||
|
<span class="font-bold text-4xl">Meu quadro de tarefas</span>
|
||||||
|
|
||||||
|
<!-- Formulario -->
|
||||||
|
<app-inclusion-form />
|
||||||
|
|
||||||
|
<!-- Lista de tarefas -->
|
||||||
|
</div>`,
|
||||||
styles: ``,
|
styles: ``,
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ const MODULES = [MatDivider];
|
||||||
<mat-divider class="h-full border-2 border-orange-700" />
|
<mat-divider class="h-full border-2 border-orange-700" />
|
||||||
|
|
||||||
<!-- Tarefas -->
|
<!-- Tarefas -->
|
||||||
<app-task class="w-3/4 border-2 border-green-700" />
|
<app-task class="w-3/4 border-2 border-green-700 pt-10" />
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
styles: ``,
|
styles: ``,
|
||||||
|
|
|
||||||
38
src/app/shared/services/snack-bar.service.ts
Normal file
38
src/app/shared/services/snack-bar.service.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { inject, Injectable, signal } from '@angular/core';
|
||||||
|
import { MatSnackBar, MatSnackBarHorizontalPosition, MatSnackBarVerticalPosition } from '@angular/material/snack-bar'
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class SnackBarService {
|
||||||
|
public message = signal('');
|
||||||
|
|
||||||
|
private _snackBar = inject(MatSnackBar);
|
||||||
|
|
||||||
|
public durationInMiliSeconds = 3000;
|
||||||
|
|
||||||
|
public horizontalPosition: MatSnackBarHorizontalPosition = 'end';
|
||||||
|
public verticalPosition: MatSnackBarVerticalPosition = 'top';
|
||||||
|
|
||||||
|
public showSnackBar(
|
||||||
|
message: string,
|
||||||
|
duration: number,
|
||||||
|
horizontalPosition: MatSnackBarHorizontalPosition,
|
||||||
|
verticalPosition: MatSnackBarVerticalPosition
|
||||||
|
): void {
|
||||||
|
this.message.set(message);
|
||||||
|
this.durationInMiliSeconds = duration;
|
||||||
|
this.horizontalPosition = horizontalPosition;
|
||||||
|
this.verticalPosition = verticalPosition;
|
||||||
|
|
||||||
|
this.openSnackBar();
|
||||||
|
};
|
||||||
|
|
||||||
|
private openSnackBar(): void {
|
||||||
|
this._snackBar.open(this.message(), '❌', {
|
||||||
|
duration: this.durationInMiliSeconds,
|
||||||
|
horizontalPosition: this.horizontalPosition,
|
||||||
|
verticalPosition: this.verticalPosition,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
/* You can add global styles to this file, and also import other style files */
|
/* You can add global styles to this file, and also import other style files */
|
||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
@import "./styles/overrides.css";
|
||||||
|
|
||||||
/* Tema claro */
|
/* Tema claro */
|
||||||
.light-theme {
|
.light-theme {
|
||||||
|
|
@ -18,3 +19,6 @@ body {
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
transition: background-color 0.3s, color 0.3s;
|
transition: background-color 0.3s, color 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html, body { height: 100%; }
|
||||||
|
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
||||||
|
|
|
||||||
4
src/styles/overrides.css
Normal file
4
src/styles/overrides.css
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
.mat-mdc-form-field-hint-wrapper {
|
||||||
|
padding: 0px !important;
|
||||||
|
margin: 0px !important;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue