auth front
This commit is contained in:
@@ -141,3 +141,42 @@ export const checkAuth = (req, res) => {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const getprofile = async (req, res) => {
|
||||
const token = req.cookies.jwt;
|
||||
let conn;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
|
||||
req.user = jwt.verify(token, process.env.JWT_SECRET);
|
||||
|
||||
// Requête pour récupérer les informations de l'utilisateur sauf le mot de passe
|
||||
const query = `
|
||||
SELECT id, email, firstname, lastname, updated_at, created_at
|
||||
FROM users
|
||||
WHERE id = ?`;
|
||||
const results = await conn.query(query, [req.user.id]);
|
||||
|
||||
// Vérifie si l'utilisateur existe
|
||||
if (results.length === 0) {
|
||||
return res.status(404).json({
|
||||
message: 'Utilisateur non trouvé.',
|
||||
status: false
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
results
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la récupération de l\'utilisateur :', error);
|
||||
return res.status(500).json({
|
||||
message: 'Erreur lors de la récupération de l\'utilisateur.',
|
||||
status: false
|
||||
});
|
||||
} finally {
|
||||
if (conn) {
|
||||
await conn.release();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
register,
|
||||
login,
|
||||
checkAuth,
|
||||
logout,
|
||||
logout, getprofile,
|
||||
} from "../controllers/authController.js";
|
||||
import {verifyToken} from "../middleware/tokenJWTMiddleware.js";
|
||||
import multer from "multer";
|
||||
@@ -29,7 +29,7 @@ const generateFileName = (originalName) => {
|
||||
};
|
||||
const storage = multer.diskStorage({
|
||||
destination: function (req, file, cb) {
|
||||
cb(null, 'uploads/'); // Stockage des fichiers dans le dossier uploads/
|
||||
cb(null, 'uploads/');
|
||||
},
|
||||
filename: function (req, file, cb) {
|
||||
cb(null, generateFileName(file.originalname));
|
||||
@@ -48,6 +48,7 @@ router.post('/upload', verifyToken, upload.single('file'), (req, res) => {
|
||||
router.post('/auth/register', register);
|
||||
router.post('/auth/login', login);
|
||||
router.post('/auth/logout', logout);
|
||||
router.get('/auth/user', verifyToken, getprofile);
|
||||
router.get('/auth/check-auth', verifyToken, checkAuth);
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -63,7 +63,6 @@ const startServer = async () => {
|
||||
console.log(`🚀 Lancement de l'API en cours... 🔧`);
|
||||
await testDatabaseConnection();
|
||||
app.listen(process.env.PORT, () => {
|
||||
console.log(`📢 NODE_ENV = ${process.env.NODE_ENV} 🌍`);
|
||||
console.log(`📢 Chargement du fichier : ${envFile} 📄`);
|
||||
console.log(`🚀 API démarrée sur le port ${process.env.PORT} 🎯`);
|
||||
console.log(`🌍 Allowed Origin : ${process.env.ALLOWED_ORIGIN} 🔗`);
|
||||
|
||||
16
package-lock.json
generated
16
package-lock.json
generated
@@ -8,6 +8,7 @@
|
||||
"name": "eni-angular",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@angular/animations": "^19.2.1",
|
||||
"@angular/common": "^19.2.0",
|
||||
"@angular/compiler": "^19.2.0",
|
||||
"@angular/core": "^19.2.0",
|
||||
@@ -350,6 +351,21 @@
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/animations": {
|
||||
"version": "19.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-19.2.1.tgz",
|
||||
"integrity": "sha512-I67XYXBic9bM+yfce6Dqa950TsrEWB6uwSB2l6eIg3Byp48yJxQYbyjvjDbMXPieU2Bzo8FYVSD+lc8cF4+L6A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.19.1 || ^20.11.1 || >=22.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": "19.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/build": {
|
||||
"version": "19.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@angular/build/-/build-19.2.1.tgz",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^19.2.1",
|
||||
"@angular/common": "^19.2.0",
|
||||
"@angular/compiler": "^19.2.0",
|
||||
"@angular/core": "^19.2.0",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</h5>
|
||||
</div>
|
||||
<nav class="flex min-w-[240px] flex-col gap-1 p-2 font-sans text-base font-normal text-blue-gray-700">
|
||||
<div class="relative block w-full">
|
||||
<div *ngIf="user.id !== 0" class="relative block w-full">
|
||||
<div role="button"
|
||||
class="flex items-center w-full p-0 leading-tight transition-all rounded-lg outline-none bg-blue-gray-50/50 text-start text-blue-gray-700 hover:bg-blue-gray-50 hover:bg-opacity-80 hover:text-blue-gray-900 focus:bg-blue-gray-50 focus:bg-opacity-80 focus:text-blue-gray-900 active:bg-blue-gray-50 active:bg-opacity-80 active:text-blue-gray-900">
|
||||
<button type="button"
|
||||
@@ -61,7 +61,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div role="button"
|
||||
<div *ngIf="user.id === 0" routerLink="/login" role="button"
|
||||
class="flex cursor-pointer items-center w-full p-3 leading-tight transition-all rounded-lg outline-none text-start hover:bg-blue-gray-50 hover:bg-opacity-80 hover:text-blue-gray-900 focus:bg-blue-gray-50 focus:bg-opacity-80 focus:text-blue-gray-900 active:bg-blue-gray-50 active:bg-opacity-80 active:text-blue-gray-900">
|
||||
<div class="grid mr-4 place-items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"
|
||||
class="w-5 h-5">
|
||||
<path fill-rule="evenodd"
|
||||
d="M18.685 19.097A9.723 9.723 0 0021.75 12c0-5.385-4.365-9.75-9.75-9.75S2.25 6.615 2.25 12a9.723 9.723 0 003.065 7.097A9.716 9.716 0 0012 21.75a9.716 9.716 0 006.685-2.653zm-12.54-1.285A7.486 7.486 0 0112 15a7.486 7.486 0 015.855 2.812A8.224 8.224 0 0112 20.25a8.224 8.224 0 01-5.855-2.438zM15.75 9a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
Connexion/Inscription
|
||||
</div>
|
||||
<div *ngIf="user.id !== 0" role="button"
|
||||
class="flex items-center w-full p-3 leading-tight transition-all rounded-lg outline-none text-start hover:bg-blue-gray-50 hover:bg-opacity-80 hover:text-blue-gray-900 focus:bg-blue-gray-50 focus:bg-opacity-80 focus:text-blue-gray-900 active:bg-blue-gray-50 active:bg-opacity-80 active:text-blue-gray-900">
|
||||
<div class="grid mr-4 place-items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"
|
||||
@@ -73,19 +85,7 @@
|
||||
</div>
|
||||
Profile
|
||||
</div>
|
||||
<div role="button"
|
||||
class="flex items-center w-full p-3 leading-tight transition-all rounded-lg outline-none text-start hover:bg-blue-gray-50 hover:bg-opacity-80 hover:text-blue-gray-900 focus:bg-blue-gray-50 focus:bg-opacity-80 focus:text-blue-gray-900 active:bg-blue-gray-50 active:bg-opacity-80 active:text-blue-gray-900">
|
||||
<div class="grid mr-4 place-items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"
|
||||
class="w-5 h-5">
|
||||
<path fill-rule="evenodd"
|
||||
d="M11.078 2.25c-.917 0-1.699.663-1.85 1.567L9.05 4.889c-.02.12-.115.26-.297.348a7.493 7.493 0 00-.986.57c-.166.115-.334.126-.45.083L6.3 5.508a1.875 1.875 0 00-2.282.819l-.922 1.597a1.875 1.875 0 00.432 2.385l.84.692c.095.078.17.229.154.43a7.598 7.598 0 000 1.139c.015.2-.059.352-.153.43l-.841.692a1.875 1.875 0 00-.432 2.385l.922 1.597a1.875 1.875 0 002.282.818l1.019-.382c.115-.043.283-.031.45.082.312.214.641.405.985.57.182.088.277.228.297.35l.178 1.071c.151.904.933 1.567 1.85 1.567h1.844c.916 0 1.699-.663 1.85-1.567l.178-1.072c.02-.12.114-.26.297-.349.344-.165.673-.356.985-.57.167-.114.335-.125.45-.082l1.02.382a1.875 1.875 0 002.28-.819l.923-1.597a1.875 1.875 0 00-.432-2.385l-.84-.692c-.095-.078-.17-.229-.154-.43a7.614 7.614 0 000-1.139c-.016-.2.059-.352.153-.43l.84-.692c.708-.582.891-1.59.433-2.385l-.922-1.597a1.875 1.875 0 00-2.282-.818l-1.02.382c-.114.043-.282.031-.449-.083a7.49 7.49 0 00-.985-.57c-.183-.087-.277-.227-.297-.348l-.179-1.072a1.875 1.875 0 00-1.85-1.567h-1.843zM12 15.75a3.75 3.75 0 100-7.5 3.75 3.75 0 000 7.5z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
Paramètre
|
||||
</div>
|
||||
<div role="button"
|
||||
<div *ngIf="user.id !== 0" role="button"
|
||||
class="flex items-center w-full p-3 leading-tight transition-all rounded-lg outline-none text-start hover:bg-blue-gray-50 hover:bg-opacity-80 hover:text-blue-gray-900 focus:bg-blue-gray-50 focus:bg-opacity-80 focus:text-blue-gray-900 active:bg-blue-gray-50 active:bg-opacity-80 active:text-blue-gray-900">
|
||||
<div class="grid mr-4 place-items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"
|
||||
|
||||
@@ -1,11 +1,40 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {AuthService} from '../../_services/auth.service';
|
||||
import {Users} from '../../_models/users';
|
||||
import {catchError, of} from 'rxjs';
|
||||
import {NgIf} from '@angular/common';
|
||||
import {RouterLink} from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sidbar',
|
||||
imports: [],
|
||||
imports: [
|
||||
NgIf,
|
||||
RouterLink
|
||||
],
|
||||
templateUrl: './sidbar.component.html',
|
||||
styleUrl: './sidbar.component.css'
|
||||
})
|
||||
export class SidbarComponent {
|
||||
export class SidbarComponent implements OnInit {
|
||||
|
||||
user: Users = { id: 0, email: '', firstname: '', lastname: '', password_hash: '', updated_at: new Date(), created_at: new Date() };
|
||||
|
||||
constructor(private authService: AuthService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadUsers();
|
||||
}
|
||||
|
||||
loadUsers(): void {
|
||||
this.authService.getProfil().pipe(
|
||||
catchError(error => {
|
||||
return of(null);
|
||||
})
|
||||
).subscribe(users => {
|
||||
if (users) {
|
||||
this.user = users;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
21
src/app/_guards/auth.guard.ts
Normal file
21
src/app/_guards/auth.guard.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import {CanActivate, Router} from '@angular/router';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {AuthService} from '../_services/auth.service';
|
||||
import {Observable, tap} from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class authGuard implements CanActivate {
|
||||
constructor(private authService: AuthService, private router: Router) {}
|
||||
|
||||
canActivate(): Observable<boolean> {
|
||||
return this.authService.isAuthenticated().pipe(
|
||||
tap(status => {
|
||||
if (!status) {
|
||||
this.router.navigate(['/login']);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
22
src/app/_guards/no-auth.guard.ts
Normal file
22
src/app/_guards/no-auth.guard.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CanActivate, Router } from '@angular/router';
|
||||
import { AuthService } from '../_services/auth.service';
|
||||
import {map, Observable, tap} from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class noAuthGuard implements CanActivate {
|
||||
constructor(private authService: AuthService, private router: Router) {}
|
||||
|
||||
canActivate(): Observable<boolean> {
|
||||
return this.authService.isAuthenticated().pipe(
|
||||
tap(status => {
|
||||
if (status) {
|
||||
this.router.navigate(['/profile']);
|
||||
}
|
||||
}),
|
||||
map(status => !status)
|
||||
);
|
||||
}
|
||||
}
|
||||
9
src/app/_models/users.ts
Normal file
9
src/app/_models/users.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export interface Users {
|
||||
id: number;
|
||||
email: string;
|
||||
firstname: string;
|
||||
lastname: string;
|
||||
password_hash: string;
|
||||
updated_at: Date;
|
||||
created_at: Date;
|
||||
}
|
||||
72
src/app/_services/auth.service.ts
Normal file
72
src/app/_services/auth.service.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
||||
import {Users} from '../_models/users';
|
||||
import {catchError, map, Observable, of} from 'rxjs';
|
||||
import {environment} from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthService {
|
||||
|
||||
constructor(private http: HttpClient) { }
|
||||
|
||||
register(user: Users): Observable<any> {
|
||||
const headers = new HttpHeaders({
|
||||
'Authorization': environment.apikey,
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
return this.http.post<any>(environment.apiurl + '/auth/register', user, { headers });
|
||||
}
|
||||
|
||||
login(user: { email: string; password: string }) {
|
||||
const headers = new HttpHeaders({
|
||||
'Authorization': environment.apikey,
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
return this.http.post(environment.apiurl + '/auth/login', user, {
|
||||
headers,
|
||||
withCredentials: true
|
||||
});
|
||||
}
|
||||
|
||||
logout(): Observable<any> {
|
||||
const headers = new HttpHeaders({
|
||||
'Authorization': environment.apikey,
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
return this.http.post(
|
||||
environment.apiurl + '/auth/logout', {}, {
|
||||
headers,
|
||||
withCredentials: true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
isAuthenticated(): Observable<boolean> {
|
||||
const headers = new HttpHeaders({
|
||||
'Authorization': environment.apikey,
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
return this.http.get(environment.apiurl + '/auth/check-auth', {
|
||||
headers,
|
||||
withCredentials: true
|
||||
}).pipe(
|
||||
map((response: any) => {
|
||||
return response.status;
|
||||
}),
|
||||
catchError(() => {
|
||||
return of(false);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getProfil(): Observable<Users> {
|
||||
const headers = new HttpHeaders({
|
||||
'Authorization': environment.apikey,
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
return this.http.get<Users>(environment.apiurl + '/auth/user', { headers, withCredentials: true });
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import {SidbarComponent} from './_component/sidbar/sidbar.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
standalone: true,
|
||||
imports: [RouterOutlet, SidbarComponent],
|
||||
templateUrl: './app.component.html',
|
||||
styleUrl: './app.component.css'
|
||||
|
||||
@@ -1,8 +1,27 @@
|
||||
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import {
|
||||
provideRouter,
|
||||
withEnabledBlockingInitialNavigation,
|
||||
withInMemoryScrolling,
|
||||
withViewTransitions
|
||||
} from '@angular/router';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
import {provideAnimations} from '@angular/platform-browser/animations';
|
||||
import {provideHttpClient} from '@angular/common/http';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)]
|
||||
providers: [
|
||||
provideAnimations(),
|
||||
provideRouter(routes,
|
||||
withViewTransitions(),
|
||||
withEnabledBlockingInitialNavigation(),
|
||||
withInMemoryScrolling({
|
||||
scrollPositionRestoration: 'enabled',
|
||||
anchorScrolling: 'enabled'
|
||||
})
|
||||
),
|
||||
provideZoneChangeDetection({ eventCoalescing: true }),
|
||||
provideHttpClient(),
|
||||
],
|
||||
};
|
||||
|
||||
0
src/app/public/pages/login/login.component.css
Normal file
0
src/app/public/pages/login/login.component.css
Normal file
32
src/app/public/pages/login/login.component.html
Normal file
32
src/app/public/pages/login/login.component.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<section class="bg-gray-100 flex items-center justify-center min-h-screen p-4">
|
||||
<div class="bg-white rounded-lg shadow-lg p-8 max-w-md w-full">
|
||||
<div class="text-center mb-8">
|
||||
<h1 class="text-2xl font-bold text-gray-800">Connexion</h1>
|
||||
<p class="text-gray-600 mt-2">Entrez vos identifiants pour vous connecter</p>
|
||||
</div>
|
||||
|
||||
<form>
|
||||
<div class="mb-6">
|
||||
<label for="email" class="block text-gray-700 text-sm font-medium mb-2">Email</label>
|
||||
<input type="email" id="email" name="email" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="votre@email.com" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<label for="password" class="block text-gray-700 text-sm font-medium">Mot de passe</label>
|
||||
</div>
|
||||
<input type="password" id="password" name="password" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="••••••••" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors">
|
||||
Se connecter
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="mt-6 text-center">
|
||||
<p class="text-sm text-gray-600">
|
||||
Pas encore de compte? <a routerLink="/register" class="text-blue-600 hover:text-blue-800 font-medium">S'inscrire</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
14
src/app/public/pages/login/login.component.ts
Normal file
14
src/app/public/pages/login/login.component.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {RouterLink} from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
imports: [
|
||||
RouterLink
|
||||
],
|
||||
templateUrl: './login.component.html',
|
||||
styleUrl: './login.component.css'
|
||||
})
|
||||
export class LoginComponent {
|
||||
|
||||
}
|
||||
43
src/app/public/pages/register/register.component.html
Normal file
43
src/app/public/pages/register/register.component.html
Normal file
@@ -0,0 +1,43 @@
|
||||
<section class="bg-gray-100 flex items-center justify-center min-h-screen p-4">
|
||||
<div class="bg-white rounded-lg shadow-lg p-8 max-w-md w-full">
|
||||
<div class="text-center mb-8">
|
||||
<h1 class="text-2xl font-bold text-gray-800">Inscription</h1>
|
||||
<p class="text-gray-600 mt-2">Entrez vos informations pour vous inscrire</p>
|
||||
</div>
|
||||
|
||||
<form>
|
||||
<div class="mb-6">
|
||||
<label for="email" class="block text-gray-700 text-sm font-medium mb-2">Email</label>
|
||||
<input type="email" id="email" name="email" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="votre@email.com" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<label for="firstname" class="block text-gray-700 text-sm font-medium mb-2">Prénom</label>
|
||||
<input type="text" id="firstname" name="firstname" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="votre@email.com" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<label for="lastname" class="block text-gray-700 text-sm font-medium mb-2">Nom</label>
|
||||
<input type="text" id="lastname" name="lastname" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="votre@email.com" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<label for="password" class="block text-gray-700 text-sm font-medium">Mot de passe</label>
|
||||
</div>
|
||||
<input type="password" id="password" name="password" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="••••••••" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<label for="confirmPassword" class="block text-gray-700 text-sm font-medium">Confirmer le mot de passe</label>
|
||||
</div>
|
||||
<input type="password" id="confirmPassword" name="confirmPassword" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="••••••••" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors">
|
||||
S'inscrire
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
14
src/app/public/pages/register/register.component.ts
Normal file
14
src/app/public/pages/register/register.component.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {RouterLink} from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-register',
|
||||
imports: [
|
||||
RouterLink
|
||||
],
|
||||
templateUrl: './register.component.html',
|
||||
styleUrl: './register.component.css'
|
||||
})
|
||||
export class RegisterComponent {
|
||||
|
||||
}
|
||||
@@ -3,10 +3,14 @@ import { RouterModule, Routes } from '@angular/router';
|
||||
import {NotFoundComponent} from './pages/not-found/not-found.component';
|
||||
import {PublicLayoutComponent} from './public-layout/public-layout.component';
|
||||
import {HomeComponent} from './pages/home/home.component';
|
||||
import {LoginComponent} from './pages/login/login.component';
|
||||
import {RegisterComponent} from './pages/register/register.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', component: PublicLayoutComponent, children: [
|
||||
{ path: '', component: HomeComponent },
|
||||
{ path: 'login', component: LoginComponent },
|
||||
{ path: 'register', component: RegisterComponent },
|
||||
]
|
||||
},
|
||||
{ path: '**', component: NotFoundComponent },
|
||||
|
||||
4
src/environments/environment.ts
Normal file
4
src/environments/environment.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const environment = {
|
||||
apiurl: 'http://localhost:3333',
|
||||
apikey: '9IgFg8cnUS4XJE7Q91A0XjrWnjbnBhdk98jcI6fV1n6NAEYz31SHicge8Vkq0bCGvfKsjylb19ouri6FFUeNC1PgPvwrNCC3G5jcz4PLInlFanzf47hCsBJw4IXuhNHC',
|
||||
};
|
||||
Reference in New Issue
Block a user