diff --git a/package.json b/package.json
index c51c02de7..79f059e33 100644
--- a/package.json
+++ b/package.json
@@ -29,13 +29,14 @@
"@types/googlemaps": "3.43.3",
"animate.css": "4.1.1",
"arrive": "2.4.1",
- "bootstrap": "3.3.7",
+ "bootstrap": "^3.3.7",
"bootstrap-notify": "3.1.3",
"chartist": "0.11.4",
"googleapis": "66.0.0",
"jquery": "3.5.1",
"perfect-scrollbar": "1.5.0",
"rxjs": "~7.5.0",
+ "sweetalert2": "^11.17.2",
"tslib": "^2.3.0",
"zone.js": "~0.11.4"
},
@@ -43,22 +44,22 @@
"@angular-devkit/build-angular": "^14.2.3",
"@angular/cli": "~14.2.3",
"@angular/compiler-cli": "^14.2.0",
+ "@types/chartist": "0.11.0",
"@types/jasmine": "~5.1.4",
+ "@types/jasminewd2": "~2.0.13",
+ "@types/jquery": "3.5.30",
+ "@types/node": "20.14.11",
+ "codelyzer": "6.0.2",
+ "cross-env": "^7.0.3",
"jasmine-core": "~4.3.0",
+ "jasmine-spec-reporter": "~7.0.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.0.0",
- "typescript": "~4.7.2",
- "@types/jasminewd2": "~2.0.13",
- "@types/chartist": "0.11.0",
- "@types/jquery": "3.5.30",
- "@types/node": "20.14.11",
- "codelyzer": "6.0.2",
- "jasmine-spec-reporter": "~7.0.0",
"protractor": "7.0.0",
"ts-node": "~10.7.0",
- "cross-env": "^7.0.3"
+ "typescript": "~4.7.2"
}
}
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 24da5d994..bb112b9e5 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -3,6 +3,10 @@ import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';
+import { ReactiveFormsModule } from '@angular/forms';
+import { HTTP_INTERCEPTORS } from '@angular/common/http';
+import { AuthInterceptor } from './interceptors/auth.interceptor';
+
import { AppRoutingModule } from './app.routing';
import { NavbarModule } from './shared/navbar/navbar.module';
@@ -12,6 +16,11 @@ import { SidebarModule } from './sidebar/sidebar.module';
import { AppComponent } from './app.component';
import { AdminLayoutComponent } from './layouts/admin-layout/admin-layout.component';
+import { LoginComponent } from './login/login.component';
+import { UsersListComponent } from './users-list/users-list.component';
+import { FormateurListComponent } from './formateur-list/formateur-list.component';
+import { FormationListeComponent } from './formation-liste/formation-liste.component';
+import { ParticipantListComponent } from './participant-list/participant-list.component';
@NgModule({
imports: [
@@ -22,13 +31,20 @@ import { AdminLayoutComponent } from './layouts/admin-layout/admin-layout.compon
NavbarModule,
FooterModule,
SidebarModule,
+ ReactiveFormsModule,
+
AppRoutingModule
],
declarations: [
AppComponent,
- AdminLayoutComponent
+ AdminLayoutComponent,
+ LoginComponent,
+ UsersListComponent,
+ FormateurListComponent,
+ FormationListeComponent,
+ ParticipantListComponent
],
- providers: [],
+ providers: [{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }],
bootstrap: [AppComponent]
})
export class AppModule { }
diff --git a/src/app/app.routing.ts b/src/app/app.routing.ts
index 993dc346d..be35698c7 100644
--- a/src/app/app.routing.ts
+++ b/src/app/app.routing.ts
@@ -3,24 +3,29 @@ import { CommonModule, } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { Routes, RouterModule } from '@angular/router';
+import { LoginComponent } from './login/login.component';
import { AdminLayoutComponent } from './layouts/admin-layout/admin-layout.component';
const routes: Routes =[
+ {
+ path: 'login',
+ component: LoginComponent,
+ },
{
path: '',
- redirectTo: 'dashboard',
+ redirectTo: 'login',
pathMatch: 'full',
}, {
path: '',
component: AdminLayoutComponent,
- children: [
+ children: [
{
path: '',
loadChildren: () => import('./layouts/admin-layout/admin-layout.module').then(x => x.AdminLayoutModule)
}]},
{
path: '**',
- redirectTo: 'dashboard'
+ redirectTo: 'login'
}
];
diff --git a/src/app/formateur-list/formateur-list.component.css b/src/app/formateur-list/formateur-list.component.css
new file mode 100644
index 000000000..20575b25a
--- /dev/null
+++ b/src/app/formateur-list/formateur-list.component.css
@@ -0,0 +1,56 @@
+/* Amélioration de l'apparence des boutons */
+.btn {
+ border-radius: 4px;
+ font-weight: 500;
+ padding: 0.375rem 0.75rem;
+ transition: all 0.2s ease-in-out;
+ margin-right: 8px;
+}
+
+.btn-sm {
+ font-size: 1.3rem;
+ padding: 0.25rem 0.5rem;
+}
+
+.btn-info {
+ box-shadow: 0 2px 4px rgba(23, 162, 184, 0.3);
+}
+
+.btn-danger {
+ box-shadow: 0 2px 4px rgba(220, 53, 69, 0.3);
+}
+
+.btn-primary {
+ box-shadow: 0 2px 4px rgba(13, 110, 253, 0.3);
+}
+
+.btn:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+}
+
+.btn i {
+ margin-right: 5px;
+}
+
+/* Amélioration de l'espacement dans le tableau */
+.table td, .table th {
+ padding: 12px 15px;
+ vertical-align: middle;
+}
+
+/* Amélioration pour le bouton Ajouter */
+.header .btn-primary {
+ padding: 0.5rem 1rem;
+ display: flex;
+ align-items: center;
+}
+
+.header .btn-primary i {
+ margin-right: 8px;
+}
+
+.modal-body {
+ max-height: 400px; /* Taille maximale du contenu */
+ overflow-y: auto; /* Permet de faire défiler le contenu */
+}
\ No newline at end of file
diff --git a/src/app/formateur-list/formateur-list.component.html b/src/app/formateur-list/formateur-list.component.html
new file mode 100644
index 000000000..8146ddf03
--- /dev/null
+++ b/src/app/formateur-list/formateur-list.component.html
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+ {{ cell }} |
+ Actions |
+
+
+
+
+ {{cell}} |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Êtes-vous sûr de vouloir supprimer ce formateur?
+
+ Nom: {{ selectedFormateur[1] }}
+ ID: {{ selectedFormateur[0] }}
+
+
+
+
+
+
+
diff --git a/src/app/formateur-list/formateur-list.component.spec.ts b/src/app/formateur-list/formateur-list.component.spec.ts
new file mode 100644
index 000000000..6cd8d0edc
--- /dev/null
+++ b/src/app/formateur-list/formateur-list.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FormateurListComponent } from './formateur-list.component';
+
+describe('FormateurListComponent', () => {
+ let component: FormateurListComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ FormateurListComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(FormateurListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/formateur-list/formateur-list.component.ts b/src/app/formateur-list/formateur-list.component.ts
new file mode 100644
index 000000000..1b0891b4b
--- /dev/null
+++ b/src/app/formateur-list/formateur-list.component.ts
@@ -0,0 +1,144 @@
+import { Component, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+
+declare interface TableData {
+ headerRow: string[];
+ dataRows: string[][];
+}
+
+@Component({
+ selector: 'app-formateurs-list',
+ templateUrl: './formateur-list.component.html',
+ styleUrls: ['./formateur-list.component.css']
+})
+export class FormateurListComponent implements OnInit {
+ public tableData1: TableData;
+ public formateurForm: FormGroup;
+ public isEditMode: boolean = false;
+ public selectedFormateurIndex: number = -1;
+ public selectedFormateur: string[] = null;
+
+ // Variables pour contrôler l'affichage des modals
+ public showFormateurModal: boolean = false;
+ public showDeleteModal: boolean = false;
+ employeurs: string[] = ['Entreprise A', 'Entreprise B', 'Entreprise C', 'Freelance'];
+ types: string[]=['interne','externe']
+ constructor(private formBuilder: FormBuilder) { }
+
+ ngOnInit() {
+ this.tableData1 = {
+ headerRow: ['ID', 'Nom', 'Prénom', 'Email', 'Tel', 'Type', 'Employeur'],
+ dataRows: [
+ ['1', 'Dakota', 'Rice', 'dakota@gmail.com', '123456789', 'interne', 'Entreprise A'],
+ ['2', 'Minerva', 'Hooper', 'minerva@gmail.com', '987654321', 'externe', 'Entreprise A'],
+ // ... autres données
+ ]
+ };
+
+ this.initForm();
+ }
+
+ initForm() {
+ this.formateurForm = this.formBuilder.group({
+ id: ['', Validators.required],
+ nom: ['', Validators.required],
+ prenom: ['', Validators.required],
+ email: ['', [Validators.required, Validators.email]],
+ tel: ['', Validators.required],
+ type: ['', Validators.required],
+ employeur: ['', Validators.required]
+ });
+ }
+
+ openAddModal() {
+ this.isEditMode = false;
+ this.selectedFormateurIndex = -1;
+
+ // Generate a new ID
+ const nextId = (Math.max(...this.tableData1.dataRows.map(row => parseInt(row[0]))) + 1).toString();
+
+ this.formateurForm.reset();
+ this.formateurForm.patchValue({
+ id: nextId,
+ nom: '',
+ prenom: '',
+ email: '',
+ tel: '',
+ type: '',
+ employeur: ''
+ });
+
+ this.showFormateurModal = true;
+ }
+
+ openEditModal(index: number) {
+ this.isEditMode = true;
+ this.selectedFormateurIndex = index;
+ const formateurData = this.tableData1.dataRows[index];
+
+ this.formateurForm.patchValue({
+ id: formateurData[0],
+ nom: formateurData[1],
+ prenom: formateurData[2],
+ email: formateurData[3],
+ tel: formateurData[4],
+ type: formateurData[5],
+ employeur: formateurData[6]
+ });
+
+ this.showFormateurModal = true;
+ }
+
+ saveFormateur() {
+ if (this.formateurForm.invalid) {
+ return;
+ }
+
+ const formValues = this.formateurForm.value;
+ const formateurData = [
+ formValues.id,
+ formValues.nom,
+ formValues.prenom,
+ formValues.email,
+ formValues.tel,
+ formValues.type,
+ formValues.employeur
+ ];
+
+ if (this.isEditMode) {
+ // Update existing formateur
+ this.tableData1.dataRows[this.selectedFormateurIndex] = formateurData;
+ } else {
+ // Add new formateur
+ this.tableData1.dataRows.push(formateurData);
+ }
+
+ // Close modal
+ this.showFormateurModal = false;
+ this.formateurForm.reset();
+ }
+
+ deleteFormateur(index: number) {
+ this.selectedFormateurIndex = index;
+ this.selectedFormateur = this.tableData1.dataRows[index];
+ this.showDeleteModal = true;
+ }
+
+ confirmDelete() {
+ // Remove formateur from array
+ this.tableData1.dataRows.splice(this.selectedFormateurIndex, 1);
+
+ // Close modal
+ this.showDeleteModal = false;
+ this.selectedFormateurIndex = -1;
+ this.selectedFormateur = null;
+ }
+
+ closeFormateurModal() {
+ this.showFormateurModal = false;
+ }
+
+ closeDeleteModal() {
+ this.showDeleteModal = false;
+ }
+}
diff --git a/src/app/formation-liste/formation-liste.component.css b/src/app/formation-liste/formation-liste.component.css
new file mode 100644
index 000000000..41dd2d1f7
--- /dev/null
+++ b/src/app/formation-liste/formation-liste.component.css
@@ -0,0 +1,126 @@
+/* Amélioration de l'apparence des boutons */
+.btn {
+ border-radius: 4px;
+ font-weight: 500;
+ padding: 0.375rem 0.75rem;
+ transition: all 0.2s ease-in-out;
+ margin-right: 8px;
+}
+
+.btn-sm {
+ font-size: 0.875rem;
+ padding: 0.25rem 0.5rem;
+}
+
+.btn-info {
+ box-shadow: 0 2px 4px rgba(23, 162, 184, 0.3);
+}
+
+.btn-danger {
+ box-shadow: 0 2px 4px rgba(220, 53, 69, 0.3);
+}
+
+.btn-primary {
+ box-shadow: 0 2px 4px rgba(13, 110, 253, 0.3);
+}
+
+.btn-success {
+ box-shadow: 0 2px 4px rgba(40, 167, 69, 0.3);
+}
+
+.btn-warning {
+ box-shadow: 0 2px 4px rgba(255, 193, 7, 0.3);
+ color: #212529;
+}
+
+.btn:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+}
+
+.btn i {
+ margin-right: 5px;
+}
+
+/* Amélioration de l'espacement dans le tableau */
+.table td, .table th {
+ padding: 12px 15px;
+ vertical-align: middle;
+}
+
+/* Amélioration pour le bouton Ajouter */
+.header .btn-primary {
+ padding: 0.5rem 1rem;
+ display: flex;
+ align-items: center;
+}
+
+.header .btn-primary i {
+ margin-right: 8px;
+}
+
+/* Style pour les modales */
+.modal-body {
+ max-height: 70vh;
+ overflow-y: auto;
+}
+
+/* Style pour la liste des participants */
+.list-group-item {
+ transition: background-color 0.2s ease;
+}
+
+.list-group-item.active {
+ background-color: #007bff;
+ border-color: #007bff;
+}
+
+.list-group-item:hover {
+ background-color: #f8f9fa;
+}
+
+.list-group-item.active:hover {
+ background-color: #0069d9;
+}
+
+.badge {
+ transition: all 0.2s ease;
+}
+
+/* Ajustements pour les modales de grande taille */
+.modal-lg {
+ max-width: 800px;
+}
+
+/* Styles pour les cartes */
+.card {
+ border-radius: 8px;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+ margin-bottom: 20px;
+}
+
+.card .header {
+ padding: 15px;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+}
+
+.card .content {
+ padding: 15px;
+}
+
+/* Style pour l'entête du tableau */
+.table thead th {
+ background-color: #f8f9fa;
+ font-weight: 600;
+ border-top: none;
+}
+
+/* Style pour les lignes alternées du tableau */
+.table-striped tbody tr:nth-of-type(odd) {
+ background-color: rgba(0, 0, 0, 0.02);
+}
+
+/* Style pour le survol des lignes du tableau */
+.table-hover tbody tr:hover {
+ background-color: rgba(0, 123, 255, 0.05);
+}
\ No newline at end of file
diff --git a/src/app/formation-liste/formation-liste.component.html b/src/app/formation-liste/formation-liste.component.html
new file mode 100644
index 000000000..775afa3f9
--- /dev/null
+++ b/src/app/formation-liste/formation-liste.component.html
@@ -0,0 +1,266 @@
+
+
+
+
+
+
+
+
+
+
+ {{ cell }} |
+ Actions |
+
+
+
+
+ {{cell}} |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Êtes-vous sûr de vouloir supprimer cette formation?
+
+ Titre: {{ selectedFormation[1] }}
+ ID: {{ selectedFormation[0] }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/formation-liste/formation-liste.component.spec.ts b/src/app/formation-liste/formation-liste.component.spec.ts
new file mode 100644
index 000000000..47e2490f7
--- /dev/null
+++ b/src/app/formation-liste/formation-liste.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FormationListeComponent } from './formation-liste.component';
+
+describe('FormationListeComponent', () => {
+ let component: FormationListeComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ FormationListeComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(FormationListeComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/formation-liste/formation-liste.component.ts b/src/app/formation-liste/formation-liste.component.ts
new file mode 100644
index 000000000..70af89bb7
--- /dev/null
+++ b/src/app/formation-liste/formation-liste.component.ts
@@ -0,0 +1,269 @@
+import { Component, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+
+@Component({
+ selector: 'app-formation-liste',
+ templateUrl: './formation-liste.component.html',
+ styleUrls: ['./formation-liste.component.css']
+})
+export class FormationListeComponent implements OnInit {
+ // Variables pour la table
+ tableData = {
+ headerRow: ['ID', 'Titre', 'Date Début', 'Date Fin', 'Durée (jours)', 'Domaine', 'Formateur', 'Budget (€)', 'Participants'],
+ dataRows: [
+ ['F001', 'Angular Avancé', '10/05/2025', '15/05/2025', '5', 'Développement Web', 'Dupont Jean', '3500', '15'],
+ ['F002', 'React Fondamentaux', '01/06/2025', '05/06/2025', '5', 'Développement Web', 'Martin Sophie', '3000', '12'],
+ ['F003', 'Management d\'équipe', '15/06/2025', '17/06/2025', '3', 'Management', 'Dubois Pierre', '2500', '8'],
+ ['F004', 'Excel Avancé', '20/06/2025', '21/06/2025', '2', 'Bureautique', 'Leroy Marie', '1200', '20']
+ ]
+ };
+
+ // Variables pour les modals
+ showFormationModal = false;
+ showDeleteModal = false;
+ showEmailModal = false;
+ showCertificatModal = false;
+ isEditMode = false;
+ selectedFormation: any = null;
+ selectedIndex: number = -1;
+
+ // Listes pour les select
+ domaines = ['Développement Web', 'Management', 'Bureautique', 'Communication', 'Marketing Digital', 'Data Science'];
+ formateurs = ['Dupont Jean', 'Martin Sophie', 'Dubois Pierre', 'Leroy Marie', 'Garcia Thomas'];
+ participants = [
+ { id: 'P001', nom: 'miladi', prenom: 'imen', email: 'miladiphg@gmail.com' },
+ { id: 'P002', nom: 'Moreau', prenom: 'Thomas', email: 'thomas.moreau@example.com' },
+ { id: 'P003', nom: 'Petit', prenom: 'Sophie', email: 'sophie.petit@example.com' },
+ { id: 'P004', nom: 'Bernard', prenom: 'Luc', email: 'luc.bernard@example.com' },
+ { id: 'P005', nom: 'Durant', prenom: 'Emma', email: 'emma.durant@example.com' }
+ ];
+
+ // Form Group
+ formationForm: FormGroup;
+ emailForm: FormGroup;
+ certificatForm: FormGroup;
+
+ // Liste des participants sélectionnés pour la formation en cours d'édition
+ selectedParticipants: any[] = [];
+
+ constructor(private fb: FormBuilder) {
+ this.formationForm = this.fb.group({
+ id: ['', Validators.required],
+ titre: ['', Validators.required],
+ dateDebut: ['', Validators.required],
+ dateFin: ['', Validators.required],
+ duree: ['', [Validators.required, Validators.min(1)]],
+ domaine: ['', Validators.required],
+ formateur: ['', Validators.required],
+ budget: ['', [Validators.required, Validators.min(0)]],
+ participants: [[]]
+ });
+
+ this.emailForm = this.fb.group({
+ objet: ['Convocation à la formation', Validators.required],
+ message: ['', Validators.required],
+ destinataires: [[], Validators.required]
+ });
+
+ this.certificatForm = this.fb.group({
+ titre: ['Certificat de réussite', Validators.required],
+ dateGeneration: [new Date().toISOString().split('T')[0], Validators.required],
+ participants: [[], Validators.required]
+ });
+ }
+
+ ngOnInit() {
+ // Initialisation des données si nécessaire
+ }
+
+ // Méthodes pour la gestion des formations
+ openAddModal() {
+ this.isEditMode = false;
+ this.formationForm.reset();
+ this.generateNewId();
+ this.selectedParticipants = [];
+ this.showFormationModal = true;
+
+ }
+
+ openEditModal(index: number) {
+ this.isEditMode = true;
+ this.selectedIndex = index;
+ const formation = this.tableData.dataRows[index];
+
+ // Simulation des participants pour l'édition
+ this.selectedParticipants = this.participants.slice(0, parseInt(formation[8]));
+
+ this.formationForm.patchValue({
+ id: formation[0],
+ titre: formation[1],
+ dateDebut: this.formatDateForInput(formation[2]),
+ dateFin: this.formatDateForInput(formation[3]),
+ duree: formation[4],
+ domaine: formation[5],
+ formateur: formation[6],
+ budget: formation[7],
+ participants: this.selectedParticipants.map(p => p.id)
+ });
+
+ this.showFormationModal = true;
+ }
+
+ closeFormationModal() {
+ this.showFormationModal = false;
+ this.formationForm.reset();
+ }
+
+ saveFormation() {
+ const formValues = this.formationForm.value;
+ const formationData = [
+ formValues.id,
+ formValues.titre,
+ this.formatDateForDisplay(formValues.dateDebut),
+ this.formatDateForDisplay(formValues.dateFin),
+ formValues.duree.toString(),
+ formValues.domaine,
+ formValues.formateur,
+ formValues.budget.toString(),
+ this.selectedParticipants.length.toString()
+ ];
+
+ if (this.isEditMode) {
+ this.tableData.dataRows[this.selectedIndex] = formationData;
+ } else {
+ this.tableData.dataRows.push(formationData);
+ }
+
+ this.closeFormationModal();
+ }
+
+ deleteFormation(index: number) {
+ this.selectedIndex = index;
+ this.selectedFormation = this.tableData.dataRows[index];
+ this.showDeleteModal = true;
+ }
+
+ closeDeleteModal() {
+ this.showDeleteModal = false;
+ this.selectedFormation = null;
+ }
+
+ confirmDelete() {
+ this.tableData.dataRows.splice(this.selectedIndex, 1);
+ this.closeDeleteModal();
+ }
+
+ // Méthodes pour l'envoi d'email
+ openEmailModal(index: number) {
+ this.selectedIndex = index;
+ this.selectedFormation = this.tableData.dataRows[index];
+
+ // Simulation des destinataires pour l'email
+ const nbParticipants = parseInt(this.selectedFormation[8]);
+ const destinataires = this.participants.slice(0, nbParticipants);
+
+ const formationTitle = this.selectedFormation[1];
+ const startDate = this.selectedFormation[2];
+
+ this.emailForm.patchValue({
+ objet: `Convocation à la formation "${formationTitle}"`,
+ message: `Bonjour,\n\nVous êtes convoqué(e) à la formation "${formationTitle}" qui débutera le ${startDate}.\nVoici le lien google meet de la formation https://meet.google.com/landing\nCordialement,\nLe service formation`,
+ destinataires: destinataires.map(p => p.id)
+ });
+
+ this.showEmailModal = true;
+ }
+
+ closeEmailModal() {
+ this.showEmailModal = false;
+ }
+
+ sendEmail() {
+ // Simulation d'envoi d'email
+ console.log('Email envoyé !', this.emailForm.value);
+ alert('Les emails ont été envoyés avec succès !');
+ this.closeEmailModal();
+ }
+
+ // Méthodes pour la génération de certificats
+ openCertificatModal(index: number) {
+ this.selectedIndex = index;
+ this.selectedFormation = this.tableData.dataRows[index];
+
+ // Simulation des participants pour les certificats
+ const nbParticipants = parseInt(this.selectedFormation[8]);
+ const participantsForCert = this.participants.slice(0, nbParticipants);
+
+ this.certificatForm.patchValue({
+ titre: `Certificat de réussite - ${this.selectedFormation[1]}`,
+ participants: participantsForCert.map(p => p.id)
+ });
+
+ this.showCertificatModal = true;
+ }
+
+ closeCertificatModal() {
+ this.showCertificatModal = false;
+ }
+
+ generateCertificats() {
+ // Simulation de génération de certificats
+ console.log('Certificats générés !', this.certificatForm.value);
+ alert('Les certificats ont été générés avec succès !');
+ this.closeCertificatModal();
+ }
+
+ // Gestion des participants
+ toggleParticipant(participant: any) {
+ const index = this.selectedParticipants.findIndex(p => p.id === participant.id);
+
+ if (index === -1) {
+ this.selectedParticipants.push(participant);
+ } else {
+ this.selectedParticipants.splice(index, 1);
+ }
+
+ this.formationForm.patchValue({
+ participants: this.selectedParticipants.map(p => p.id)
+ });
+ }
+
+ isParticipantSelected(participant: any): boolean {
+ return this.selectedParticipants.some(p => p.id === participant.id);
+ }
+
+ // Utilitaires
+ generateNewId() {
+ // Génère un ID basé sur le nombre de formations existantes
+ const newNum = this.tableData.dataRows.length + 1;
+ const id = 'F' + newNum.toString().padStart(3, '0');
+ this.formationForm.patchValue({ id });
+ }
+
+ formatDateForInput(dateStr: string): string {
+ // Convertit DD/MM/YYYY en YYYY-MM-DD pour les inputs de type date
+ const parts = dateStr.split('/');
+ return `${parts[2]}-${parts[1]}-${parts[0]}`;
+ }
+
+ formatDateForDisplay(dateStr: string): string {
+ // Convertit YYYY-MM-DD en DD/MM/YYYY pour l'affichage
+ const parts = dateStr.split('-');
+ return `${parts[2]}/${parts[1]}/${parts[0]}`;
+ }
+
+ calculateDuration() {
+ // Calcule automatiquement la durée entre les dates
+ const dateDebut = this.formationForm.get('dateDebut')?.value;
+ const dateFin = this.formationForm.get('dateFin')?.value;
+
+ if (dateDebut && dateFin) {
+ const start = new Date(dateDebut);
+ const end = new Date(dateFin);
+ const diffTime = Math.abs(end.getTime() - start.getTime());
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1; // +1 pour inclure le jour de début
+
+ this.formationForm.patchValue({ duree: diffDays });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/app/guards/auth.guard.spec.ts b/src/app/guards/auth.guard.spec.ts
new file mode 100644
index 000000000..68889d22d
--- /dev/null
+++ b/src/app/guards/auth.guard.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { AuthGuard } from './auth.guard';
+
+describe('AuthGuard', () => {
+ let guard: AuthGuard;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ guard = TestBed.inject(AuthGuard);
+ });
+
+ it('should be created', () => {
+ expect(guard).toBeTruthy();
+ });
+});
diff --git a/src/app/guards/auth.guard.ts b/src/app/guards/auth.guard.ts
new file mode 100644
index 000000000..a5fbc9200
--- /dev/null
+++ b/src/app/guards/auth.guard.ts
@@ -0,0 +1,18 @@
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree ,Router } from '@angular/router';
+import { Observable } from 'rxjs';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AuthGuard implements CanActivate {
+ constructor(private router: Router) {}
+ canActivate(): boolean {
+ if (localStorage.getItem('token')) {
+ return true;
+ }
+ this.router.navigate(['/login']);
+ return false;
+ }
+
+}
diff --git a/src/app/interceptors/auth.interceptor.spec.ts b/src/app/interceptors/auth.interceptor.spec.ts
new file mode 100644
index 000000000..7ab58dbd1
--- /dev/null
+++ b/src/app/interceptors/auth.interceptor.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { AuthInterceptor } from './auth.interceptor';
+
+describe('AuthInterceptor', () => {
+ beforeEach(() => TestBed.configureTestingModule({
+ providers: [
+ AuthInterceptor
+ ]
+ }));
+
+ it('should be created', () => {
+ const interceptor: AuthInterceptor = TestBed.inject(AuthInterceptor);
+ expect(interceptor).toBeTruthy();
+ });
+});
diff --git a/src/app/interceptors/auth.interceptor.ts b/src/app/interceptors/auth.interceptor.ts
new file mode 100644
index 000000000..fe935125c
--- /dev/null
+++ b/src/app/interceptors/auth.interceptor.ts
@@ -0,0 +1,26 @@
+import { Injectable } from '@angular/core';
+import {
+ HttpRequest,
+ HttpHandler,
+ HttpEvent,
+ HttpInterceptor
+} from '@angular/common/http';
+import { Observable } from 'rxjs';
+
+@Injectable()
+export class AuthInterceptor implements HttpInterceptor {
+
+ constructor() {}
+
+ intercept(request: HttpRequest, next: HttpHandler): Observable> {
+ const token = localStorage.getItem('token');
+ if (token) {
+ request = request.clone({
+ setHeaders: {
+ Authorization: `Bearer ${token}`
+ }
+ });
+ }
+ return next.handle(request);
+ }
+}
diff --git a/src/app/interfaces/login-request.interface.ts b/src/app/interfaces/login-request.interface.ts
new file mode 100644
index 000000000..2b26d9f8c
--- /dev/null
+++ b/src/app/interfaces/login-request.interface.ts
@@ -0,0 +1,4 @@
+export interface LoginRequest {
+ login: string;
+ motDePasse: string;
+ }
\ No newline at end of file
diff --git a/src/app/layouts/admin-layout/admin-layout.routing.ts b/src/app/layouts/admin-layout/admin-layout.routing.ts
index e09417d82..09818768b 100644
--- a/src/app/layouts/admin-layout/admin-layout.routing.ts
+++ b/src/app/layouts/admin-layout/admin-layout.routing.ts
@@ -2,20 +2,33 @@ import { Routes } from '@angular/router';
import { HomeComponent } from '../../home/home.component';
import { UserComponent } from '../../user/user.component';
+
import { TablesComponent } from '../../tables/tables.component';
import { TypographyComponent } from '../../typography/typography.component';
import { IconsComponent } from '../../icons/icons.component';
import { MapsComponent } from '../../maps/maps.component';
import { NotificationsComponent } from '../../notifications/notifications.component';
import { UpgradeComponent } from '../../upgrade/upgrade.component';
+import { UsersListComponent } from 'app/users-list/users-list.component';
+import { FormateurListComponent } from 'app/formateur-list/formateur-list.component';
+import { FormationListeComponent } from 'app/formation-liste/formation-liste.component';
+import { ParticipantListComponent } from 'app/participant-list/participant-list.component';
+import { AuthGuard } from 'app/guards/auth.guard';
export const AdminLayoutRoutes: Routes = [
- { path: 'dashboard', component: HomeComponent },
- { path: 'user', component: UserComponent },
- { path: 'table', component: TablesComponent },
- { path: 'typography', component: TypographyComponent },
- { path: 'icons', component: IconsComponent },
- { path: 'maps', component: MapsComponent },
- { path: 'notifications', component: NotificationsComponent },
- { path: 'upgrade', component: UpgradeComponent },
+ { path: 'dashboard', component: HomeComponent ,canActivate: [AuthGuard]},
+ { path: 'user', component: UserComponent ,canActivate: [AuthGuard]},
+
+ { path: 'user-list', component: UsersListComponent ,canActivate: [AuthGuard]},
+ { path: 'participant-list', component: ParticipantListComponent ,canActivate: [AuthGuard]},
+ { path: 'table', component: TablesComponent ,canActivate: [AuthGuard]},
+ { path: 'typography', component: TypographyComponent ,canActivate: [AuthGuard]},
+ { path: 'icons', component: IconsComponent ,canActivate: [AuthGuard]},
+ { path: 'maps', component: MapsComponent ,canActivate: [AuthGuard]},
+ { path: 'notifications', component: NotificationsComponent ,canActivate: [AuthGuard]},
+ { path: 'upgrade', component: UpgradeComponent ,canActivate: [AuthGuard]},
+ {path: 'formateur-list', component:FormateurListComponent ,canActivate: [AuthGuard]},
+ {path: 'formation-liste', component:FormationListeComponent ,canActivate: [AuthGuard]},
+ { path: 'participant-list', component: ParticipantListComponent ,canActivate: [AuthGuard]},
+
];
diff --git a/src/app/login/login.component.css b/src/app/login/login.component.css
new file mode 100644
index 000000000..96cb2a90b
--- /dev/null
+++ b/src/app/login/login.component.css
@@ -0,0 +1,106 @@
+/* login.component.css */
+.login-container {
+ height: 100vh;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-image: url('assets/img/background_login.jpg');
+ background-size: cover;
+ background-position: center;
+ }
+
+ .login-card {
+ width: 400px;
+ padding: 40px;
+ border-radius: 10px;
+ background-color: rgba(255, 255, 255, 0.95);
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
+ }
+
+ .logo-container {
+ text-align: center;
+ margin-bottom: 30px;
+ }
+
+ .logo {
+ width: 100px;
+ height: auto;
+ margin-bottom: 15px;
+ }
+
+ h1 {
+ color: #d82c2c;
+ margin: 0;
+ font-size: 24px;
+ font-weight: 600;
+ }
+
+ .login-form .form-group {
+ margin-bottom: 20px;
+ }
+
+ .login-form label {
+ display: block;
+ margin-bottom: 8px;
+ font-weight: 500;
+ color: #333;
+ }
+
+ .login-form input[type="text"],
+ .login-form input[type="password"] {
+ width: 100%;
+ padding: 12px;
+ border: 1px solid #ddd;
+ border-radius: 5px;
+ font-size: 16px;
+ transition: border-color 0.3s;
+ }
+
+ .login-form input:focus {
+ border-color: #d82c2c;
+ outline: none;
+ box-shadow: 0 0 0 2px rgba(216, 44, 44, 0.2);
+ }
+
+ .remember-me {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+ }
+
+ .remember-me input {
+ margin-right: 8px;
+ }
+
+ .login-button {
+ width: 100%;
+ padding: 14px;
+ border: none;
+ border-radius: 5px;
+ background-color: #d82c2c;
+ color: white;
+ font-size: 16px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: background-color 0.3s;
+ }
+
+ .login-button:hover {
+ background-color: #b52222;
+ }
+
+ .forgot-password {
+ margin-top: 15px;
+ text-align: center;
+ }
+
+ .forgot-password a {
+ color: #d82c2c;
+ text-decoration: none;
+ font-size: 14px;
+ }
+
+ .forgot-password a:hover {
+ text-decoration: underline;
+ }
\ No newline at end of file
diff --git a/src/app/login/login.component.html b/src/app/login/login.component.html
new file mode 100644
index 000000000..ea6f0796e
--- /dev/null
+++ b/src/app/login/login.component.html
@@ -0,0 +1,44 @@
+
+
+
+
+

+
Centre de Formation
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/login/login.component.spec.ts b/src/app/login/login.component.spec.ts
new file mode 100644
index 000000000..10eca249d
--- /dev/null
+++ b/src/app/login/login.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { LoginComponent } from './login.component';
+
+describe('LoginComponent', () => {
+ let component: LoginComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ LoginComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(LoginComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/login/login.component.ts b/src/app/login/login.component.ts
new file mode 100644
index 000000000..9d79d272d
--- /dev/null
+++ b/src/app/login/login.component.ts
@@ -0,0 +1,53 @@
+// login.component.ts
+import { Component } from '@angular/core';
+import { Router } from '@angular/router';
+import { AuthService } from 'app/services/auth.service';
+import Swal from 'sweetalert2';
+@Component({
+ selector: 'app-login',
+ templateUrl: './login.component.html',
+ styleUrls: ['./login.component.css']
+})
+export class LoginComponent {
+ username: string = '';
+ password: string = '';
+ rememberMe: boolean = false;
+
+ credentials = {
+ login: '',
+ motDePasse: ''
+ };
+
+ constructor(private authService: AuthService, private router: Router) {}
+
+ onLogin() {
+ this.authService.login(this.credentials).subscribe({
+ next: (response) => {
+ localStorage.setItem('token', response.token);
+ this.router.navigate(['/dashboard']);
+ },
+ error: (err) => {
+ if (err.status === 500 || err.status === 0) {
+ // Erreur serveur ou backend non joignable
+ Swal.fire({
+ icon: 'error',
+ title: 'Erreur serveur',
+ text: 'Veuillez réessayer plus tard.',
+ confirmButtonColor: '#d82c2c',
+ confirmButtonText:"réessayer"
+ });
+ } else {
+ // Erreur d’identifiants (ex : exception Runtime côté backend)
+ Swal.fire({
+ icon: 'warning',
+ title: 'Identifiants invalides',
+ text: "Nom d'utilisateur ou mot de passe incorrect.",
+ confirmButtonColor: '#d82c2c',
+ confirmButtonText:"réessayer",
+
+
+ });
+ }
+ },
+ });
+ }}
\ No newline at end of file
diff --git a/src/app/participant-list/participant-list.component.css b/src/app/participant-list/participant-list.component.css
new file mode 100644
index 000000000..35527918f
--- /dev/null
+++ b/src/app/participant-list/participant-list.component.css
@@ -0,0 +1,56 @@
+/* Amélioration de l'apparence des boutons */
+.btn {
+ border-radius: 4px;
+ font-weight: 500;
+ padding: 0.375rem 0.75rem;
+ transition: all 0.2s ease-in-out;
+ margin-right: 8px;
+}
+
+.btn-sm {
+ font-size: 1.3rem;
+ padding: 0.25rem 0.5rem;
+}
+
+.btn-info {
+ box-shadow: 0 2px 4px rgba(23, 162, 184, 0.3);
+}
+
+.btn-danger {
+ box-shadow: 0 2px 4px rgba(220, 53, 69, 0.3);
+}
+
+.btn-primary {
+ box-shadow: 0 2px 4px rgba(13, 110, 253, 0.3);
+}
+
+.btn:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+}
+
+.btn i {
+ margin-right: 5px;
+}
+
+/* Amélioration de l'espacement dans le tableau */
+.table td, .table th {
+ padding: 12px 15px;
+ vertical-align: middle;
+}
+
+/* Amélioration pour le bouton Ajouter */
+.header .btn-primary {
+ padding: 0.5rem 1rem;
+ display: flex;
+ align-items: center;
+}
+
+.header .btn-primary i {
+ margin-right: 8px;
+}
+
+.modal-body {
+ max-height: 70vh;
+ overflow-y: auto;
+}
\ No newline at end of file
diff --git a/src/app/participant-list/participant-list.component.html b/src/app/participant-list/participant-list.component.html
new file mode 100644
index 000000000..37421da4a
--- /dev/null
+++ b/src/app/participant-list/participant-list.component.html
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+ {{ cell }} |
+ Actions |
+
+
+
+
+ {{cell}} |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Êtes-vous sûr de vouloir supprimer cet utilisateur?
+
+ Nom: {{ selectedUser[1] }}
+ ID: {{ selectedUser[0] }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/participant-list/participant-list.component.spec.ts b/src/app/participant-list/participant-list.component.spec.ts
new file mode 100644
index 000000000..e8050d745
--- /dev/null
+++ b/src/app/participant-list/participant-list.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ParticipantListComponent } from './participant-list.component';
+
+describe('ParticipantListComponent', () => {
+ let component: ParticipantListComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ ParticipantListComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ParticipantListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/participant-list/participant-list.component.ts b/src/app/participant-list/participant-list.component.ts
new file mode 100644
index 000000000..0cd317e0b
--- /dev/null
+++ b/src/app/participant-list/participant-list.component.ts
@@ -0,0 +1,129 @@
+import { Component, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+
+declare interface TableData {
+ headerRow: string[];
+ dataRows: string[][];
+}
+
+@Component({
+ selector: 'app-participant-list',
+ templateUrl: './participant-list.component.html',
+ styleUrls: ['./participant-list.component.css']
+})
+export class ParticipantListComponent implements OnInit {
+ public tableData1: TableData;
+ public userForm: FormGroup;
+ public isEditMode: boolean = false;
+ public selectedUserIndex: number = -1;
+ public selectedUser: string[] = null;
+
+ public showUserModal: boolean = false;
+ public showDeleteModal: boolean = false;
+
+ structures = ['Direction centrale', 'Direction régionale'];
+ profiles = ['Informaticien', 'Technicien', 'Juriste', 'Gestionnaire'];
+
+ constructor(private formBuilder: FormBuilder) {}
+
+ ngOnInit() {
+ this.tableData1 = {
+ headerRow: ['ID', 'Nom', 'Prénom', 'Structure', 'Profil', 'Email', 'Téléphone'],
+ dataRows: [
+ ['1', 'Ahmed', 'Ben Ali', 'Direction centrale', 'Informaticien', 'ahmed@example.com', '12345678'],
+ ['2', 'Sana', 'Trabelsi', 'Direction régionale', 'Juriste', 'sana@example.com', '87654321'],
+ ]
+ };
+
+ this.initForm();
+ }
+
+ initForm() {
+ this.userForm = this.formBuilder.group({
+ id: ['', Validators.required],
+ nom: ['', Validators.required],
+ prenom: ['', Validators.required],
+ structure: ['', Validators.required],
+ profile: ['', Validators.required],
+ email: ['', [Validators.required, Validators.email]],
+ telephone: ['', [Validators.required, Validators.pattern('^[0-9]{8}$')]]
+ });
+ }
+
+ openAddModal() {
+ this.isEditMode = false;
+ this.selectedUserIndex = -1;
+
+ const nextId = (
+ Math.max(...this.tableData1.dataRows.map(row => parseInt(row[0]))) + 1
+ ).toString();
+
+ this.userForm.reset();
+ this.userForm.patchValue({ id: nextId });
+
+ this.showUserModal = true;
+ }
+
+ openEditModal(index: number) {
+ this.isEditMode = true;
+ this.selectedUserIndex = index;
+ const userData = this.tableData1.dataRows[index];
+
+ this.userForm.patchValue({
+ id: userData[0],
+ nom: userData[1],
+ prenom: userData[2],
+ structure: userData[3],
+ profile: userData[4],
+ email: userData[5],
+ telephone: userData[6]
+ });
+
+ this.showUserModal = true;
+ }
+
+ saveUser() {
+ if (this.userForm.invalid) return;
+
+ const formValues = this.userForm.value;
+ const userData = [
+ formValues.id,
+ formValues.nom,
+ formValues.prenom,
+ formValues.structure,
+ formValues.profile,
+ formValues.email,
+ formValues.telephone
+ ];
+
+ if (this.isEditMode) {
+ this.tableData1.dataRows[this.selectedUserIndex] = userData;
+ } else {
+ this.tableData1.dataRows.push(userData);
+ }
+
+ this.showUserModal = false;
+ this.userForm.reset();
+ }
+
+ deleteUser(index: number) {
+ this.selectedUserIndex = index;
+ this.selectedUser = this.tableData1.dataRows[index];
+ this.showDeleteModal = true;
+ }
+
+ confirmDelete() {
+ this.tableData1.dataRows.splice(this.selectedUserIndex, 1);
+ this.showDeleteModal = false;
+ this.selectedUserIndex = -1;
+ this.selectedUser = null;
+ }
+
+ closeUserModal() {
+ this.showUserModal = false;
+ }
+
+ closeDeleteModal() {
+ this.showDeleteModal = false;
+ }
+}
diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts
new file mode 100644
index 000000000..d10f2d7e3
--- /dev/null
+++ b/src/app/services/auth.service.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AuthService {
+ private apiUrl = 'http://localhost:8094/authenticate'; // URL du backend
+
+ constructor(private http: HttpClient) {}
+
+ login(credentials: { login: string, motDePasse: string }): Observable<{token: string}> {
+ return this.http.post<{token: string}>(this.apiUrl, credentials);
+ }
+
+ saveToken(token: string) {
+ localStorage.setItem('jwt', token);
+ }
+
+ getToken(): string | null {
+ return localStorage.getItem('jwt');
+ }
+
+ isLoggedIn(): boolean {
+ return !!this.getToken();
+ }
+
+ logout() {
+ localStorage.removeItem('jwt');
+ }
+}
diff --git a/src/app/services/user-list.service.spec.ts b/src/app/services/user-list.service.spec.ts
new file mode 100644
index 000000000..a65e883e1
--- /dev/null
+++ b/src/app/services/user-list.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { UserListService } from './user-list.service';
+
+describe('UserListService', () => {
+ let service: UserListService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(UserListService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/src/app/services/user-list.service.ts b/src/app/services/user-list.service.ts
new file mode 100644
index 000000000..eb3a25b47
--- /dev/null
+++ b/src/app/services/user-list.service.ts
@@ -0,0 +1,15 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class UserListService {
+ private apiUrl = 'http://localhost:8094/utilisateurs'; // URL du backend
+
+ constructor(private http: HttpClient) { }
+
+ getAllUsers() {
+ return this.http.get(this.apiUrl);
+ }
+}
diff --git a/src/app/shared/footer/footer.component.html b/src/app/shared/footer/footer.component.html
index 12fe1788b..c17954ad9 100644
--- a/src/app/shared/footer/footer.component.html
+++ b/src/app/shared/footer/footer.component.html
@@ -25,7 +25,7 @@
- © {{test | date: 'yyyy'}} Creative Tim, made with love for a better web
+ © {{test | date: 'yyyy'}} IMM made with love & kif for a better web
diff --git a/src/app/shared/navbar/navbar.component.html b/src/app/shared/navbar/navbar.component.html
index 6a5aca258..f9630c9ef 100644
--- a/src/app/shared/navbar/navbar.component.html
+++ b/src/app/shared/navbar/navbar.component.html
@@ -67,7 +67,7 @@
-
+
Log out
diff --git a/src/app/shared/navbar/navbar.component.ts b/src/app/shared/navbar/navbar.component.ts
index 068ed7ee8..4fa508b22 100644
--- a/src/app/shared/navbar/navbar.component.ts
+++ b/src/app/shared/navbar/navbar.component.ts
@@ -1,6 +1,7 @@
import { Component, OnInit, ElementRef } from '@angular/core';
import { ROUTES } from '../../sidebar/sidebar.component';
import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common';
+import { Router } from '@angular/router';
@Component({
// moduleId: module.id,
@@ -14,7 +15,7 @@ export class NavbarComponent implements OnInit{
private toggleButton: any;
private sidebarVisible: boolean;
- constructor(location: Location, private element: ElementRef) {
+ constructor(location: Location, private element: ElementRef , private router: Router) {
this.location = location;
this.sidebarVisible = false;
}
@@ -63,4 +64,9 @@ export class NavbarComponent implements OnInit{
}
return 'Dashboard';
}
+
+ logout() {
+ localStorage.removeItem('token'); // Supprime le token
+ this.router.navigate(['/login']); // Redirige vers la page de connexion
+ }
}
diff --git a/src/app/sidebar/sidebar.component.html b/src/app/sidebar/sidebar.component.html
index 817b194c6..dfe3fd145 100644
--- a/src/app/sidebar/sidebar.component.html
+++ b/src/app/sidebar/sidebar.component.html
@@ -1,11 +1,11 @@