diff --git a/src/app/app.css b/src/app/app.css index 1fc8139..e69de29 100644 --- a/src/app/app.css +++ b/src/app/app.css @@ -1,113 +0,0 @@ -:host { - display: flex; -} - -.app-layout { - height: 100vh; -} - -nz-header { - display: flex; - align-items: center; - background: #001529; - padding: 0 24px; -} - -.header-container { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; -} - -/* --- LOGO + TITRE --- */ -.logo { - display: flex; - align-items: center; -} - -.logo a { - display: flex; - align-items: center; - text-decoration: none; -} - -.logo img { - height: 40px; - width: auto; -} - -.logo h1 { - margin: 0 0 0 10px; - color: #fff; - font-weight: 600; - font-size: 20px; - font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; -} - -/* --- MENU PRINCIPAL --- */ -.top-nav { - flex: 1; - margin: 0 40px; - line-height: 64px; - background: #001529; - border: none; -} - -/* Couleur grise par défaut + effet blanc et zoom au survol */ -.top-nav li { - transition: transform 0.2s ease, color 0.2s ease; -} - -.top-nav li a { - color: #bfbfbf !important; /* gris clair par défaut */ - transition: transform 0.2s ease, color 0.2s ease; -} - -/* Au survol → zoom + blanc pur */ -.top-nav li:hover { - transform: scale(1.08); - background: transparent !important; - color: #fff !important; -} - -.top-nav li:hover a { - color: #ffffff !important; -} - -/* Supprime toute coloration bleue ou fond par défaut NG-ZORRO */ -.top-nav li.ant-menu-item-active, -.top-nav li.ant-menu-item-selected { - background: transparent !important; - color: #fff !important; -} - -/* --- ICONES DROITES --- */ -.right-icons { - display: flex; - align-items: center; - gap: 20px; - color: #fff; - font-size: 18px; - cursor: pointer; -} - -.right-icons app-modal-nav { - transition: transform 0.2s ease, color 0.2s ease; -} - -.right-icons app-modal-nav:hover { - color: #40a9ff; - transform: scale(1.2); -} - -/* --- CONTENU --- */ -nz-content { - padding: 24px 50px; -} - -.inner-content { - padding: 24px; - background: #fff; - height: 100%; -} diff --git a/src/app/app.html b/src/app/app.html index 43a974e..90c6b64 100644 --- a/src/app/app.html +++ b/src/app/app.html @@ -1,87 +1 @@ - - - - - - -
- -
-
-
+ \ No newline at end of file diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index a649552..4580d5e 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,41 +1,56 @@ import {Routes} from '@angular/router'; export const routes: Routes = [ + { + path: 'login', + loadComponent: () => import('./pages/login/login').then(x => x.Login) + }, { path: '', - pathMatch: 'full', - redirectTo: '/dashboard' - }, - { - path: 'dashboard', - loadComponent: () => import('./pages/dashboard/dashboard').then(x => x.Dashboard) - }, - { - path: 'stock', - loadComponent: () => import('./pages/stock/stock').then(x => x.Stock) - }, - { - path: 'supplier', - loadComponent: () => import('./pages/supplier/supplier').then(x => x.Supplier) - }, - { - path: 'deliverer', - loadComponent: () => import('./pages/deliverer/deliverer').then(x => x.Deliverer) - }, - { - path: 'quotation', - loadComponent: () => import('./pages/quotation/quotation').then(x => x.Quotation) - }, - { - path: 'purchase-order', - loadComponent: () => import('./pages/purchase-order/purchase-order').then(x => x.PurchaseOrder) - }, - { - path: 'delivery-note', - loadComponent: () => import('./pages/delivery-note/delivery-note').then(x => x.DeliveryNote) - }, - { - path: 'user', - loadComponent: () => import('./pages/user/user').then(x => x.User) + loadComponent: () => + import('./components/layout/layout').then(m => m.Layout), + children: [ + { + path: '', + pathMatch: 'full', + redirectTo: '/dashboard' + }, + { + path: 'dashboard', + loadComponent: () => import('./pages/dashboard/dashboard').then(m => m.Dashboard) + }, + { + path: 'stock', + loadComponent: () => import('./pages/stock/stock').then(m => m.Stock) + }, + { + path: 'supplier', + loadComponent: () => import('./pages/supplier/supplier').then(m => m.Supplier) + }, + { + path: 'deliverer', + loadComponent: () => import('./pages/deliverer/deliverer').then(m => m.Deliverer) + }, + { + path: 'quotation', + loadComponent: () => import('./pages/quotation/quotation').then(m => m.Quotation) + }, + { + path: 'purchase-order', + loadComponent: () => import('./pages/purchase-order/purchase-order').then(m => m.PurchaseOrder) + }, + { + path: 'delivery-note', + loadComponent: () => import('./pages/delivery-note/delivery-note').then(m => m.DeliveryNote) + }, + { + path: 'user', + loadComponent: () => import('./pages/user/user').then(m => m.User) + }, + { + path: '**', + redirectTo: 'dashboard' + } + ] } ]; diff --git a/src/app/app.ts b/src/app/app.ts index 230f23c..8d3207b 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -1,15 +1,11 @@ import {Component} from '@angular/core'; -import {RouterLink, RouterLinkActive, RouterOutlet} from '@angular/router'; +import {RouterOutlet} from '@angular/router'; import {NzLayoutModule} from 'ng-zorro-antd/layout'; import {NzMenuModule} from 'ng-zorro-antd/menu'; -import {NzIconDirective} from "ng-zorro-antd/icon"; -import {ModalNav} from "./components/modal-nav/modal-nav"; -import {Profil} from "./components/profil/profil"; -import {SettingForm} from "./components/setting-form/setting-form"; @Component({ selector: 'app-root', - imports: [RouterOutlet, NzLayoutModule, NzMenuModule, NzIconDirective, RouterLinkActive, RouterLink, ModalNav, Profil, SettingForm], + imports: [RouterOutlet, NzLayoutModule, NzMenuModule], templateUrl: './app.html', styleUrl: './app.css' }) diff --git a/src/app/components/layout/layout.css b/src/app/components/layout/layout.css new file mode 100644 index 0000000..1fc8139 --- /dev/null +++ b/src/app/components/layout/layout.css @@ -0,0 +1,113 @@ +:host { + display: flex; +} + +.app-layout { + height: 100vh; +} + +nz-header { + display: flex; + align-items: center; + background: #001529; + padding: 0 24px; +} + +.header-container { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; +} + +/* --- LOGO + TITRE --- */ +.logo { + display: flex; + align-items: center; +} + +.logo a { + display: flex; + align-items: center; + text-decoration: none; +} + +.logo img { + height: 40px; + width: auto; +} + +.logo h1 { + margin: 0 0 0 10px; + color: #fff; + font-weight: 600; + font-size: 20px; + font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; +} + +/* --- MENU PRINCIPAL --- */ +.top-nav { + flex: 1; + margin: 0 40px; + line-height: 64px; + background: #001529; + border: none; +} + +/* Couleur grise par défaut + effet blanc et zoom au survol */ +.top-nav li { + transition: transform 0.2s ease, color 0.2s ease; +} + +.top-nav li a { + color: #bfbfbf !important; /* gris clair par défaut */ + transition: transform 0.2s ease, color 0.2s ease; +} + +/* Au survol → zoom + blanc pur */ +.top-nav li:hover { + transform: scale(1.08); + background: transparent !important; + color: #fff !important; +} + +.top-nav li:hover a { + color: #ffffff !important; +} + +/* Supprime toute coloration bleue ou fond par défaut NG-ZORRO */ +.top-nav li.ant-menu-item-active, +.top-nav li.ant-menu-item-selected { + background: transparent !important; + color: #fff !important; +} + +/* --- ICONES DROITES --- */ +.right-icons { + display: flex; + align-items: center; + gap: 20px; + color: #fff; + font-size: 18px; + cursor: pointer; +} + +.right-icons app-modal-nav { + transition: transform 0.2s ease, color 0.2s ease; +} + +.right-icons app-modal-nav:hover { + color: #40a9ff; + transform: scale(1.2); +} + +/* --- CONTENU --- */ +nz-content { + padding: 24px 50px; +} + +.inner-content { + padding: 24px; + background: #fff; + height: 100%; +} diff --git a/src/app/components/layout/layout.html b/src/app/components/layout/layout.html new file mode 100644 index 0000000..43a974e --- /dev/null +++ b/src/app/components/layout/layout.html @@ -0,0 +1,87 @@ + + + + + + +
+ +
+
+
diff --git a/src/app/components/layout/layout.ts b/src/app/components/layout/layout.ts new file mode 100644 index 0000000..f6a07d1 --- /dev/null +++ b/src/app/components/layout/layout.ts @@ -0,0 +1,32 @@ +import {Component} from '@angular/core'; +import {ModalNav} from "../modal-nav/modal-nav"; +import {NzContentComponent, NzHeaderComponent, NzLayoutComponent} from "ng-zorro-antd/layout"; +import {NzIconDirective} from "ng-zorro-antd/icon"; +import {NzMenuDirective, NzMenuItemComponent, NzSubMenuComponent} from "ng-zorro-antd/menu"; +import {Profil} from "../profil/profil"; +import {RouterLink, RouterLinkActive, RouterOutlet} from "@angular/router"; +import {SettingForm} from "../setting-form/setting-form"; + +@Component({ + selector: 'app-layout', + imports: [ + ModalNav, + NzContentComponent, + NzHeaderComponent, + NzIconDirective, + NzLayoutComponent, + NzMenuDirective, + NzMenuItemComponent, + NzSubMenuComponent, + Profil, + RouterLink, + RouterLinkActive, + RouterOutlet, + SettingForm + ], + templateUrl: './layout.html', + styleUrl: './layout.css', +}) +export class Layout { + +} diff --git a/src/app/interceptors/auth-interceptor.ts b/src/app/interceptors/auth-interceptor.ts new file mode 100644 index 0000000..77568a3 --- /dev/null +++ b/src/app/interceptors/auth-interceptor.ts @@ -0,0 +1,48 @@ +import {HttpInterceptorFn, HttpErrorResponse, HttpRequest, HttpHandlerFn} from '@angular/common/http'; +import {inject} from '@angular/core'; +import {AuthService} from '../services/auth.service'; +import {RefreshService} from '../services/api'; +import {NzNotificationService} from 'ng-zorro-antd/notification'; +import {catchError, switchMap, throwError} from 'rxjs'; + +export const authInterceptor: HttpInterceptorFn = (req: HttpRequest, next: HttpHandlerFn) => { + const authService = inject(AuthService); + const refreshService = inject(RefreshService); + const notification = inject(NzNotificationService); + const token = authService.getToken(); + + let authReq = req; + if (token) { + authReq = req.clone({ + setHeaders: {Authorization: `Bearer ${token}`} + }); + } + + return next(authReq).pipe( + catchError((error: HttpErrorResponse) => { + if (error.status === 401 && token) { + return refreshService.refreshTokenEndpoint({token}) + .pipe( + switchMap((res: any) => { + authService.setToken(res.token); + const newReq = req.clone({ + setHeaders: {Authorization: `Bearer ${res.token}`} + }); + return next(newReq); + }), + catchError((refreshErr) => { + authService.logout(); + notification.error('Session expirée', 'Veuillez vous reconnecter.'); + return throwError(() => refreshErr); + }) + ); + } + + if (error.status === 403) { + notification.error('Accès refusé', 'Vous n’avez pas les droits pour cette action.'); + } + + return throwError(() => error); + }) + ); +}; \ No newline at end of file diff --git a/src/app/pages/login/login.css b/src/app/pages/login/login.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/pages/login/login.html b/src/app/pages/login/login.html new file mode 100644 index 0000000..90c7af9 --- /dev/null +++ b/src/app/pages/login/login.html @@ -0,0 +1,46 @@ +
+
+ +
+ +
+ +
+ + +
+
+ + + Nom d'utilisateur + + + + + + + + + Mot de passe + + + + + + + + +
+
+ +
+
+
\ No newline at end of file diff --git a/src/app/pages/login/login.ts b/src/app/pages/login/login.ts new file mode 100644 index 0000000..2809b85 --- /dev/null +++ b/src/app/pages/login/login.ts @@ -0,0 +1,43 @@ +import {Component, inject, OnInit} from '@angular/core'; +import {NzColDirective} from "ng-zorro-antd/grid"; +import {NzFormControlComponent, NzFormDirective, NzFormItemComponent, NzFormLabelComponent} from "ng-zorro-antd/form"; +import {NzInputDirective} from "ng-zorro-antd/input"; +import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms"; +import {NzButtonComponent} from "ng-zorro-antd/button"; +import {AuthService} from "../../services/auth.service"; +import {Router} from "@angular/router"; + +@Component({ + selector: 'app-login', + imports: [ + NzColDirective, + NzFormControlComponent, + NzFormDirective, + NzFormItemComponent, + NzFormLabelComponent, + NzInputDirective, + ReactiveFormsModule, + NzButtonComponent + ], + templateUrl: './login.html', + styleUrl: './login.css', +}) +export class Login implements OnInit { + private authService = inject(AuthService); + private router = inject(Router); + + ngOnInit() { + this.authService.logout(); + } + + loginForm: FormGroup = new FormGroup({ + name: new FormControl(null, [Validators.required]), + password: new FormControl(null, [Validators.required]) + }) + + async connectUser() { + if (this.loginForm.invalid) return; + const ok = await this.authService.connectUser(this.loginForm.value.name, this.loginForm.value.password); + if (ok) await this.router.navigate(['/dashboard']); + } +} diff --git a/src/app/services/api/.openapi-generator/FILES b/src/app/services/api/.openapi-generator/FILES index 9a756b8..5511c45 100644 --- a/src/app/services/api/.openapi-generator/FILES +++ b/src/app/services/api/.openapi-generator/FILES @@ -11,6 +11,7 @@ api/prices.service.ts api/products.service.ts api/purchaseorders.service.ts api/quotations.service.ts +api/refresh.service.ts api/settings.service.ts api/suppliers.service.ts api/users.service.ts @@ -42,6 +43,7 @@ model/get-purchase-order-dto.ts model/get-purchase-product-dto.ts model/get-quotation-dto.ts model/get-quotation-product-dto.ts +model/get-refresh-token-dto.ts model/get-setting-dto.ts model/get-supplier-dto.ts model/get-token-dto.ts @@ -61,6 +63,7 @@ model/patch-quotation-product-quantity-dto.ts model/patch-supplier-delivery-delay-dto.ts model/patch-user-password-dto.ts model/patch-ware-house-product-quantity-dto.ts +model/refresh-token-dto.ts model/update-deliverer-dto.ts model/update-delivery-note-dto.ts model/update-product-dto.ts diff --git a/src/app/services/api/api/api.ts b/src/app/services/api/api/api.ts index a0b0052..9cc74bb 100644 --- a/src/app/services/api/api/api.ts +++ b/src/app/services/api/api/api.ts @@ -19,6 +19,9 @@ import {PurchaseordersService} from './purchaseorders.service'; export * from './quotations.service'; import {QuotationsService} from './quotations.service'; +export * from './refresh.service'; +import {RefreshService} from './refresh.service'; + export * from './settings.service'; import {SettingsService} from './settings.service'; @@ -34,4 +37,4 @@ import {WarehouseproductsService} from './warehouseproducts.service'; export * from './warehouses.service'; import {WarehousesService} from './warehouses.service'; -export const APIS = [CustomersService, DeliverersService, DeliverynotesService, PricesService, ProductsService, PurchaseordersService, QuotationsService, SettingsService, SuppliersService, UsersService, WarehouseproductsService, WarehousesService]; +export const APIS = [CustomersService, DeliverersService, DeliverynotesService, PricesService, ProductsService, PurchaseordersService, QuotationsService, RefreshService, SettingsService, SuppliersService, UsersService, WarehouseproductsService, WarehousesService]; diff --git a/src/app/services/api/api/purchaseorders.service.ts b/src/app/services/api/api/purchaseorders.service.ts index ed2a306..c03db1f 100644 --- a/src/app/services/api/api/purchaseorders.service.ts +++ b/src/app/services/api/api/purchaseorders.service.ts @@ -152,22 +152,22 @@ export class PurchaseordersService extends BaseService { * @param reportProgress flag to report request and response progress. */ public createPurchaseOrder(createPurchaseOrderDto: CreatePurchaseOrderDto, observe?: 'body', reportProgress?: boolean, options?: { - httpHeaderAccept?: undefined, + httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean - }): Observable; + }): Observable; public createPurchaseOrder(createPurchaseOrderDto: CreatePurchaseOrderDto, observe?: 'response', reportProgress?: boolean, options?: { - httpHeaderAccept?: undefined, + httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean - }): Observable>; + }): Observable>; public createPurchaseOrder(createPurchaseOrderDto: CreatePurchaseOrderDto, observe?: 'events', reportProgress?: boolean, options?: { - httpHeaderAccept?: undefined, + httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean - }): Observable>; + }): Observable>; public createPurchaseOrder(createPurchaseOrderDto: CreatePurchaseOrderDto, observe: any = 'body', reportProgress: boolean = false, options?: { - httpHeaderAccept?: undefined, + httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean }): Observable { @@ -177,7 +177,9 @@ export class PurchaseordersService extends BaseService { let localVarHeaders = this.defaultHeaders; - const localVarHttpHeaderAcceptSelected: string | undefined = options?.httpHeaderAccept ?? this.configuration.selectHeaderAccept([]); + const localVarHttpHeaderAcceptSelected: string | undefined = options?.httpHeaderAccept ?? this.configuration.selectHeaderAccept([ + 'application/json' + ]); if (localVarHttpHeaderAcceptSelected !== undefined) { localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); } @@ -209,7 +211,7 @@ export class PurchaseordersService extends BaseService { let localVarPath = `/API/purchaseOrders`; const {basePath, withCredentials} = this.configuration; - return this.httpClient.request('post', `${basePath}${localVarPath}`, + return this.httpClient.request('post', `${basePath}${localVarPath}`, { context: localVarHttpContext, body: createPurchaseOrderDto, diff --git a/src/app/services/api/api/refresh.service.ts b/src/app/services/api/api/refresh.service.ts new file mode 100644 index 0000000..4497a1f --- /dev/null +++ b/src/app/services/api/api/refresh.service.ts @@ -0,0 +1,120 @@ +/** + * PyroFetes + * + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +/* tslint:disable:no-unused-variable member-ordering */ + +import {Inject, Injectable, Optional} from '@angular/core'; +import { + HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent, HttpParameterCodec, HttpContext +} from '@angular/common/http'; +import {CustomHttpParameterCodec} from '../encoder'; +import {Observable} from 'rxjs'; + +// @ts-ignore +import {GetRefreshTokenDto} from '../model/get-refresh-token-dto'; +// @ts-ignore +import {RefreshTokenDto} from '../model/refresh-token-dto'; + +// @ts-ignore +import {BASE_PATH, COLLECTION_FORMATS} from '../variables'; +import {Configuration} from '../configuration'; +import {BaseService} from '../api.base.service'; + + +@Injectable({ + providedIn: 'root' +}) +export class RefreshService extends BaseService { + + constructor(protected httpClient: HttpClient, @Optional() @Inject(BASE_PATH) basePath: string | string[], @Optional() configuration?: Configuration) { + super(basePath, configuration); + } + + /** + * @endpoint post /API/refresh + * @param refreshTokenDto + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public refreshTokenEndpoint(refreshTokenDto: RefreshTokenDto, observe?: 'body', reportProgress?: boolean, options?: { + httpHeaderAccept?: 'application/json', + context?: HttpContext, + transferCache?: boolean + }): Observable; + public refreshTokenEndpoint(refreshTokenDto: RefreshTokenDto, observe?: 'response', reportProgress?: boolean, options?: { + httpHeaderAccept?: 'application/json', + context?: HttpContext, + transferCache?: boolean + }): Observable>; + public refreshTokenEndpoint(refreshTokenDto: RefreshTokenDto, observe?: 'events', reportProgress?: boolean, options?: { + httpHeaderAccept?: 'application/json', + context?: HttpContext, + transferCache?: boolean + }): Observable>; + public refreshTokenEndpoint(refreshTokenDto: RefreshTokenDto, observe: any = 'body', reportProgress: boolean = false, options?: { + httpHeaderAccept?: 'application/json', + context?: HttpContext, + transferCache?: boolean + }): Observable { + if (refreshTokenDto === null || refreshTokenDto === undefined) { + throw new Error('Required parameter refreshTokenDto was null or undefined when calling refreshTokenEndpoint.'); + } + + let localVarHeaders = this.defaultHeaders; + + const localVarHttpHeaderAcceptSelected: string | undefined = options?.httpHeaderAccept ?? this.configuration.selectHeaderAccept([ + 'application/json' + ]); + if (localVarHttpHeaderAcceptSelected !== undefined) { + localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); + } + + const localVarHttpContext: HttpContext = options?.context ?? new HttpContext(); + + const localVarTransferCache: boolean = options?.transferCache ?? true; + + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected !== undefined) { + localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected); + } + + let responseType_: 'text' | 'json' | 'blob' = 'json'; + if (localVarHttpHeaderAcceptSelected) { + if (localVarHttpHeaderAcceptSelected.startsWith('text')) { + responseType_ = 'text'; + } else if (this.configuration.isJsonMime(localVarHttpHeaderAcceptSelected)) { + responseType_ = 'json'; + } else { + responseType_ = 'blob'; + } + } + + let localVarPath = `/API/refresh`; + const {basePath, withCredentials} = this.configuration; + return this.httpClient.request('post', `${basePath}${localVarPath}`, + { + context: localVarHttpContext, + body: refreshTokenDto, + responseType: responseType_, + ...(withCredentials ? {withCredentials} : {}), + headers: localVarHeaders, + observe: observe, + ...(localVarTransferCache !== undefined ? {transferCache: localVarTransferCache} : {}), + reportProgress: reportProgress + } + ); + } + +} diff --git a/src/app/services/api/model/get-refresh-token-dto.ts b/src/app/services/api/model/get-refresh-token-dto.ts new file mode 100644 index 0000000..e279288 --- /dev/null +++ b/src/app/services/api/model/get-refresh-token-dto.ts @@ -0,0 +1,15 @@ +/** + * PyroFetes + * + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export interface GetRefreshTokenDto { + token?: string | null; +} + diff --git a/src/app/services/api/model/models.ts b/src/app/services/api/model/models.ts index 706d060..a02ef36 100644 --- a/src/app/services/api/model/models.ts +++ b/src/app/services/api/model/models.ts @@ -20,6 +20,7 @@ export * from './get-purchase-order-dto'; export * from './get-purchase-product-dto'; export * from './get-quotation-dto'; export * from './get-quotation-product-dto'; +export * from './get-refresh-token-dto'; export * from './get-setting-dto'; export * from './get-supplier-dto'; export * from './get-token-dto'; @@ -38,6 +39,7 @@ export * from './patch-quotation-product-quantity-dto'; export * from './patch-supplier-delivery-delay-dto'; export * from './patch-user-password-dto'; export * from './patch-ware-house-product-quantity-dto'; +export * from './refresh-token-dto'; export * from './update-deliverer-dto'; export * from './update-delivery-note-dto'; export * from './update-product-dto'; diff --git a/src/app/services/api/model/refresh-token-dto.ts b/src/app/services/api/model/refresh-token-dto.ts new file mode 100644 index 0000000..cddb8f8 --- /dev/null +++ b/src/app/services/api/model/refresh-token-dto.ts @@ -0,0 +1,15 @@ +/** + * PyroFetes + * + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export interface RefreshTokenDto { + token?: string | null; +} + diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts new file mode 100644 index 0000000..323aea2 --- /dev/null +++ b/src/app/services/auth.service.ts @@ -0,0 +1,37 @@ +import {inject, Injectable} from '@angular/core'; +import {firstValueFrom} from 'rxjs'; +import {NzNotificationService} from 'ng-zorro-antd/notification'; +import {UsersService} from "./api"; + +@Injectable({ + providedIn: 'root', +}) +export class AuthService { + private usersService = inject(UsersService); + private notificationService = inject(NzNotificationService); + + async connectUser(name: string, password: string) { + try { + const loginDto = {name, password}; + const res = await firstValueFrom(this.usersService.connectUserEndpoint(loginDto)); + localStorage.setItem('jwt', res.token); + return true; + } catch { + this.notificationService.error('Erreur', 'Identifiant invalide'); + return false; + } + } + + getToken(): string | null { + return localStorage.getItem('jwt'); + } + + setToken(token: string) { + localStorage.setItem('jwt', token); + } + + logout() { + localStorage.removeItem('jwt'); + } + +}