Compare commits
5 Commits
d3040c0268
...
base-crud
| Author | SHA1 | Date | |
|---|---|---|---|
| d33630fc50 | |||
| d8dec863e4 | |||
| cb36cb6c7b | |||
| 55f4a665f8 | |||
| c09e2655b9 |
@@ -1,59 +1,9 @@
|
||||
# DoItEarlier
|
||||
# Do it earlier
|
||||
|
||||
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 22.0.4.
|
||||
Une application *todo list* destinée à un usage personnel. Ses fonctionnalités sont fortement inspirées par Todoist, dont l'abonnement payant m'a poussé à créer ma propre version.
|
||||
|
||||
## Development server
|
||||
# Stack
|
||||
|
||||
To start a local development server, run:
|
||||
Application web réalisée en angular 22.0.4 et node.js 24.18.0.
|
||||
|
||||
```bash
|
||||
ng serve
|
||||
```
|
||||
|
||||
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
||||
|
||||
```bash
|
||||
ng generate component component-name
|
||||
```
|
||||
|
||||
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
||||
|
||||
```bash
|
||||
ng generate --help
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To build the project run:
|
||||
|
||||
```bash
|
||||
ng build
|
||||
```
|
||||
|
||||
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
To execute unit tests with the [Vitest](https://vitest.dev/) test runner, use the following command:
|
||||
|
||||
```bash
|
||||
ng test
|
||||
```
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
For end-to-end (e2e) testing, run:
|
||||
|
||||
```bash
|
||||
ng e2e
|
||||
```
|
||||
|
||||
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||
|
||||
## Additional Resources
|
||||
|
||||
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
||||
Elle utilise une API maison interrogeant une base de données privée self-hosted.
|
||||
|
||||
+1
-3
@@ -24,9 +24,7 @@
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
]
|
||||
"styles": ["src/material-theme.scss", "src/styles.css"]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
|
||||
Generated
+36
-2
@@ -8,10 +8,12 @@
|
||||
"name": "do-it-earlier",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@angular/cdk": "^22.2.0",
|
||||
"@angular/common": "^22.0.0",
|
||||
"@angular/compiler": "^22.0.0",
|
||||
"@angular/core": "^22.0.0",
|
||||
"@angular/forms": "^22.0.0",
|
||||
"@angular/material": "^22.2.0",
|
||||
"@angular/platform-browser": "^22.0.0",
|
||||
"@angular/router": "^22.0.0",
|
||||
"rxjs": "~7.8.0",
|
||||
@@ -221,6 +223,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cdk": {
|
||||
"version": "22.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-22.2.0.tgz",
|
||||
"integrity": "sha512-Vxiqo03yKxzmON+hfa0UkUSC+TrWdtRgc1MtkE5l3NJQ5euF9Os4kOqDfW1nDt3/AjCplE64HX3h0gOK5m3zjw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"parse5": "^8.0.0",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^22.0.0 || ^23.0.0",
|
||||
"@angular/core": "^22.0.0 || ^23.0.0",
|
||||
"@angular/forms": "^22.0.0 || ^23.0.0",
|
||||
"@angular/platform-browser": "^22.0.0 || ^23.0.0",
|
||||
"rxjs": "^6.5.3 || ^7.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cli": {
|
||||
"version": "22.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-22.1.7.tgz",
|
||||
@@ -358,6 +377,23 @@
|
||||
"rxjs": "^6.5.3 || ^7.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/material": {
|
||||
"version": "22.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@angular/material/-/material-22.2.0.tgz",
|
||||
"integrity": "sha512-upeJyTUwiq3oMxGsLtTmddTjdqN8xgO0M2Rs3GaLSPqcXp/n7ScrDdN6sFHYLZtIs1KHmMEYnSBHm5F1ofVZow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/cdk": "22.2.0",
|
||||
"@angular/common": "^22.0.0 || ^23.0.0",
|
||||
"@angular/core": "^22.0.0 || ^23.0.0",
|
||||
"@angular/forms": "^22.0.0 || ^23.0.0",
|
||||
"@angular/platform-browser": "^22.0.0 || ^23.0.0",
|
||||
"rxjs": "^6.5.3 || ^7.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/platform-browser": {
|
||||
"version": "22.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-22.1.5.tgz",
|
||||
@@ -6282,7 +6318,6 @@
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz",
|
||||
"integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"entities": "^8.0.0"
|
||||
@@ -6336,7 +6371,6 @@
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz",
|
||||
"integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
"private": true,
|
||||
"packageManager": "npm@11.16.0",
|
||||
"dependencies": {
|
||||
"@angular/cdk": "^22.2.0",
|
||||
"@angular/common": "^22.0.0",
|
||||
"@angular/compiler": "^22.0.0",
|
||||
"@angular/core": "^22.0.0",
|
||||
"@angular/forms": "^22.0.0",
|
||||
"@angular/material": "^22.2.0",
|
||||
"@angular/platform-browser": "^22.0.0",
|
||||
"@angular/router": "^22.0.0",
|
||||
"rxjs": "~7.8.0",
|
||||
|
||||
+31
-10
@@ -1,13 +1,34 @@
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>DoItEarlier</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>DoItEarlier</title>
|
||||
<base href="/" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet"
|
||||
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Include theming for Angular Material with `mat.theme()`.
|
||||
// This Sass mixin will define CSS variables that are used for styling Angular Material
|
||||
// components according to the Material 3 design spec.
|
||||
// Learn more about theming and how to use it for your application's
|
||||
// custom components at https://material.angular.dev/guide/theming
|
||||
@use '@angular/material' as mat;
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
@include mat.theme(
|
||||
(
|
||||
color: (
|
||||
primary: mat.$magenta-palette,
|
||||
tertiary: mat.$violet-palette,
|
||||
),
|
||||
typography: Roboto,
|
||||
density: 0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
body {
|
||||
// Default the application to a light color theme. This can be changed to
|
||||
// `dark` to enable the dark color theme, or to `light dark` to defer to the
|
||||
// user's system settings.
|
||||
color-scheme: light;
|
||||
|
||||
// Set a default background, font and text colors for the application using
|
||||
// Angular Material's system-level CSS variables. Learn more about these
|
||||
// variables at https://material.angular.dev/guide/system-variables
|
||||
background-color: var(--mat-sys-surface);
|
||||
color: var(--mat-sys-on-surface);
|
||||
font: var(--mat-sys-body-medium);
|
||||
|
||||
// Reset the user agent margin.
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -14,4 +14,10 @@ export class BaseService {
|
||||
protected post<T>(url: string, body: T): Observable<T> {
|
||||
return this.http.post<T>(this.baseAddress + url, body);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected delete<T>(url: string): Observable<T> {
|
||||
return this.http.delete<T>(`${this.baseAddress}${url}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,16 @@ export class GroupService extends BaseService {
|
||||
return this.get<Group[]>("group");
|
||||
}
|
||||
|
||||
public addGroup(name:string):Observable<Group>{
|
||||
let body:Group = {
|
||||
id_group:0,
|
||||
name_group:name,
|
||||
public addGroup(name: string): Observable<Group> {
|
||||
let body: Group = {
|
||||
id_group: 0,
|
||||
name_group: name,
|
||||
};
|
||||
|
||||
return this.post<Group>("group/add",body);
|
||||
return this.post<Group>("group/add", body);
|
||||
}
|
||||
|
||||
public deleteGroup(id_group: number): Observable<void> {
|
||||
return this.delete<void>(`group/delete?id=${id_group}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,4 +17,8 @@ export class ProjectService extends BaseService {
|
||||
|
||||
return this.post<Project>("project/add", body);
|
||||
}
|
||||
|
||||
public deleteProject(id_project: number): Observable<void> {
|
||||
return this.delete<void>(`project/delete?id=${id_project}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@ export class TaskService extends BaseService {
|
||||
return this.get<Task[]>("task");
|
||||
}
|
||||
|
||||
public addTask(name: string, dueDate: string | null, priority: string | null, status: string | null): Observable<Task> {
|
||||
public addTask(name: string,
|
||||
dueDate: string | null,
|
||||
priority: string | null,
|
||||
status: string | null): Observable<Task> {
|
||||
let body: Task = {
|
||||
name_task: name,
|
||||
date_task: new Date(dueDate!),
|
||||
@@ -19,4 +22,8 @@ export class TaskService extends BaseService {
|
||||
}
|
||||
return this.post<Task>("task/add", body);
|
||||
}
|
||||
|
||||
public deleteTask(id_task: number): Observable<void> {
|
||||
return this.delete<void>(`task/delete?id=${id_task}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,19 @@
|
||||
Section tâches
|
||||
</h2>
|
||||
<div>
|
||||
@for (task of tasks(); track task.id_task) {
|
||||
<p>
|
||||
{{ task.name_task }}
|
||||
</p>
|
||||
}
|
||||
<div>
|
||||
@for (task of tasks(); track task.id_task) {
|
||||
<p>
|
||||
{{ task.name_task }}
|
||||
</p>
|
||||
|
||||
<button (click)="deleteTask(task.id_task)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
|
||||
}
|
||||
</div>
|
||||
<br/>
|
||||
<button (click)="toggleTaskForm()">
|
||||
Ajouter une tâche
|
||||
</button>
|
||||
@@ -39,11 +46,19 @@
|
||||
Section groupes de tâches
|
||||
</h2>
|
||||
<div>
|
||||
@for (group of groups(); track group.id_group) {
|
||||
<p>
|
||||
{{ group.name_group }}
|
||||
</p>
|
||||
}
|
||||
<div>
|
||||
@for (group of groups(); track group.id_group) {
|
||||
<p>
|
||||
{{ group.name_group }}
|
||||
</p>
|
||||
|
||||
<button (click)="deleteGroup(group.id_group)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<button (click)="toggleGroupForm()">Ajouter un groupe</button>
|
||||
|
||||
@@ -62,12 +77,19 @@
|
||||
Section projets
|
||||
</h2>
|
||||
<div>
|
||||
@for (project of projects(); track project.id_project){
|
||||
<p>
|
||||
{{ project.name_project }}
|
||||
</p>
|
||||
}
|
||||
<div>
|
||||
@for (project of projects(); track project.id_project){
|
||||
<p>
|
||||
{{ project.name_project }}
|
||||
</p>
|
||||
|
||||
<button (click)="deleteProject(project.id_project)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<button (click)="toggleProjectForm()">Ajouter un projet</button>
|
||||
|
||||
@if (showProjectForm){
|
||||
@@ -75,7 +97,9 @@
|
||||
<label for="name-project">Nom </label>
|
||||
<input id="name-project" type="text" formControlName="name" />
|
||||
|
||||
<button type="submit" [disabled]="!newProjectForm.valid">Valider</button>
|
||||
<button type="submit" [disabled]="!newProjectForm.valid">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -8,9 +8,10 @@ import { ProjectService } from '../../../services/project.service';
|
||||
import { Project } from '../../../model/Project';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { Observable } from 'rxjs';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
@Component({
|
||||
imports: [RouterOutlet, ReactiveFormsModule],
|
||||
imports: [RouterOutlet, ReactiveFormsModule, MatIconModule],
|
||||
selector: 'app-root',
|
||||
styleUrl: './home.component.css',
|
||||
templateUrl: './home.component.html',
|
||||
@@ -49,17 +50,32 @@ export class Home {
|
||||
//#endregion
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.taskService.getTasks().subscribe((response: Task[]): void => {
|
||||
this.tasks.set(response);
|
||||
this.taskService.getTasks().subscribe({
|
||||
next: (response: Task[]) => {
|
||||
this.tasks.set(response);
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(`Récupération des tâches impossible\nErreur:${error.error.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
this.groupService.getGroups().subscribe((response: Group[]): void => {
|
||||
this.groups.set(response);
|
||||
this.groupService.getGroups().subscribe({
|
||||
next: (response: Group[]) => {
|
||||
this.groups.set(response);
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(`Récupération des groupes impossible\nErreur:${error.error.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
this.projectService.getProjects().subscribe((response: Project[]): void => {
|
||||
this.projects.set(response);
|
||||
})
|
||||
this.projectService.getProjects().subscribe({
|
||||
next: (response: Project[]) => {
|
||||
this.projects.set(response);
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(`Récupération des projets impossible\nErreur:${error.error.message}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public toggleTaskForm(): void {
|
||||
@@ -70,15 +86,43 @@ export class Home {
|
||||
* submitTask
|
||||
*/
|
||||
public submitTask(): void {
|
||||
let response: Observable<Task> = this.taskService.addTask(this.newTaskForm.controls.name.value!,
|
||||
this.toggleTaskForm();
|
||||
let response: Observable<Task> = this.taskService.addTask(
|
||||
this.newTaskForm.controls.name.value!,
|
||||
this.newTaskForm.controls.dueDate.value,
|
||||
this.newTaskForm.controls.priority.value,
|
||||
this.newTaskForm.controls.status.value);
|
||||
this.newTaskForm.controls.status.value
|
||||
);
|
||||
|
||||
response.subscribe(response => {
|
||||
this.tasks.update(values => {
|
||||
return [...values, response];
|
||||
});
|
||||
response.subscribe({
|
||||
next: (response) => {
|
||||
this.tasks.update(values => {
|
||||
return [...values, response];
|
||||
});
|
||||
|
||||
this.newTaskForm.reset();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(`L'ajout de tâche est impossible\nErreur:${error.error.message}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* deleteTask
|
||||
*/
|
||||
public deleteTask(id_task: number) {
|
||||
let response: Observable<void> = this.taskService.deleteTask(id_task);
|
||||
|
||||
response.subscribe({
|
||||
next: () => {
|
||||
this.tasks.update((tasks) => {
|
||||
return tasks.filter(((task) => task.id_task != id_task));
|
||||
});
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(`La suppression de tâche est impossible\nErreur:${error.error.message}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,12 +134,39 @@ export class Home {
|
||||
* submitGroup
|
||||
*/
|
||||
public submitGroup() {
|
||||
let response: Observable<Group> = this.groupService.addGroup(this.newGroupForm.controls.name.value!);
|
||||
this.toggleGroupForm();
|
||||
let response: Observable<Group> = this.groupService.addGroup(
|
||||
this.newGroupForm.controls.name.value!
|
||||
);
|
||||
|
||||
response.subscribe(response => {
|
||||
this.groups.update(values => {
|
||||
return [...values, response];
|
||||
});
|
||||
response.subscribe({
|
||||
next: (response) => {
|
||||
this.groups.update(values => {
|
||||
return [...values, response];
|
||||
});
|
||||
this.newGroupForm.reset();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(`L'ajout d'un groupe est impossible\nErreur:${error.error.message}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* deleteGroup
|
||||
*/
|
||||
public deleteGroup(id_group: number) {
|
||||
let response: Observable<void> = this.groupService.deleteGroup(id_group);
|
||||
|
||||
response.subscribe({
|
||||
next: () => {
|
||||
this.groups.update((groups) => {
|
||||
return groups.filter(((group) => group.id_group != id_group));
|
||||
});
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(`La suppression du groupe est impossible\nErreur: ${error.error.message}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -107,12 +178,39 @@ export class Home {
|
||||
* submitProject
|
||||
*/
|
||||
public submitProject() {
|
||||
let response: Observable<Project> = this.projectService.addProject(this.newProjectForm.controls.name.value!);
|
||||
this.toggleProjectForm();
|
||||
let response: Observable<Project> = this.projectService.addProject(
|
||||
this.newProjectForm.controls.name.value!
|
||||
);
|
||||
|
||||
response.subscribe(response => {
|
||||
this.projects.update(values => {
|
||||
return [...values, response];
|
||||
});
|
||||
response.subscribe({
|
||||
next: (response) => {
|
||||
this.projects.update(values => {
|
||||
return [...values, response];
|
||||
});
|
||||
this.newProjectForm.reset();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(`L'ajout d'un projet est impossible\nErreur:${error.error.message}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* deleteProject
|
||||
*/
|
||||
public deleteProject(id_project: number) {
|
||||
let response: Observable<void> = this.projectService.deleteProject(id_project);
|
||||
|
||||
response.subscribe({
|
||||
next: () => {
|
||||
this.projects.update((projects) => {
|
||||
return projects.filter((project) => project.id_project != id_project);
|
||||
});
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(`Suppression du projet impossible\nErreur:${error.error.message}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user