base de l'authentification (#4)
Co-authored-by: styve Lioumba <styve.lioumba@jdc.fr>
This commit is contained in:
committed by
styve Lioumba
parent
0d575e0737
commit
1dc1109482
@@ -4,8 +4,8 @@ main {
|
||||
min-height: 100vh; /* Minimum 100% de la hauteur de la fenêtre */
|
||||
}
|
||||
|
||||
#content {
|
||||
flex-grow: 1; /* Cette zone grandit pour remplir l'espace restant */
|
||||
.content {
|
||||
flex: 1; /* Cette zone grandit pour remplir l'espace restant */
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,16 @@ export const routes: Routes = [
|
||||
title: 'Liste des profiles',
|
||||
loadChildren: () => import('@app/routes/profile/profile.module').then(m => m.ProfileModule)
|
||||
},
|
||||
{
|
||||
path:'auth',
|
||||
title: 'Authentification',
|
||||
loadChildren: () => import('@app/routes/authentification/authentification.module').then(m => m.AuthentificationModule)
|
||||
},
|
||||
{
|
||||
path: 'my-profile',
|
||||
title: 'Mon profile',
|
||||
loadChildren: () => import('@app/routes/my-profile/my-profile.module').then(m => m.MyProfileModule)
|
||||
},
|
||||
{
|
||||
path: 'not-found',
|
||||
title: 'Page non trouvée',
|
||||
|
||||
86
src/app/routes/authentification/auth/auth.component.html
Normal file
86
src/app/routes/authentification/auth/auth.component.html
Normal file
File diff suppressed because one or more lines are too long
23
src/app/routes/authentification/auth/auth.component.spec.ts
Normal file
23
src/app/routes/authentification/auth/auth.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AuthComponent } from './auth.component';
|
||||
|
||||
describe('AuthComponent', () => {
|
||||
let component: AuthComponent;
|
||||
let fixture: ComponentFixture<AuthComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AuthComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AuthComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
16
src/app/routes/authentification/auth/auth.component.ts
Normal file
16
src/app/routes/authentification/auth/auth.component.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {RouterLink, RouterOutlet} from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: 'app-auth',
|
||||
standalone: true,
|
||||
imports: [
|
||||
RouterOutlet,
|
||||
RouterLink
|
||||
],
|
||||
templateUrl: './auth.component.html',
|
||||
styleUrl: './auth.component.scss'
|
||||
})
|
||||
export class AuthComponent {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {RegisterComponent} from "@app/shared/features/register/register.component";
|
||||
import {AuthComponent} from "@app/routes/authentification/auth/auth.component";
|
||||
import {LoginComponent} from "@app/shared/features/login/login.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '', component: AuthComponent, children: [
|
||||
|
||||
{path: '', component: LoginComponent},
|
||||
{path: 'register', component: RegisterComponent},
|
||||
]
|
||||
},
|
||||
{path: 'not-found', loadChildren: () => import('@app/routes/not-found/not-found.module').then(m => m.NotFoundModule)},
|
||||
{path: '**', redirectTo: 'not-found'}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AuthentificationRoutingModule {
|
||||
}
|
||||
14
src/app/routes/authentification/authentification.module.ts
Normal file
14
src/app/routes/authentification/authentification.module.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { AuthentificationRoutingModule } from './authentification-routing.module';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule,
|
||||
AuthentificationRoutingModule
|
||||
]
|
||||
})
|
||||
export class AuthentificationModule { }
|
||||
14
src/app/routes/my-profile/my-profile-routing.module.ts
Normal file
14
src/app/routes/my-profile/my-profile-routing.module.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {MyProfileComponent} from "@app/routes/my-profile/my-profile.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '', component: MyProfileComponent}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class MyProfileRoutingModule {
|
||||
}
|
||||
1
src/app/routes/my-profile/my-profile.component.html
Normal file
1
src/app/routes/my-profile/my-profile.component.html
Normal file
@@ -0,0 +1 @@
|
||||
<p>my-profile works!</p>
|
||||
0
src/app/routes/my-profile/my-profile.component.scss
Normal file
0
src/app/routes/my-profile/my-profile.component.scss
Normal file
23
src/app/routes/my-profile/my-profile.component.spec.ts
Normal file
23
src/app/routes/my-profile/my-profile.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MyProfileComponent } from './my-profile.component';
|
||||
|
||||
describe('MyProfileComponent', () => {
|
||||
let component: MyProfileComponent;
|
||||
let fixture: ComponentFixture<MyProfileComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MyProfileComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(MyProfileComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
12
src/app/routes/my-profile/my-profile.component.ts
Normal file
12
src/app/routes/my-profile/my-profile.component.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-my-profile',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './my-profile.component.html',
|
||||
styleUrl: './my-profile.component.scss'
|
||||
})
|
||||
export class MyProfileComponent {
|
||||
|
||||
}
|
||||
14
src/app/routes/my-profile/my-profile.module.ts
Normal file
14
src/app/routes/my-profile/my-profile.module.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { MyProfileRoutingModule } from './my-profile-routing.module';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MyProfileRoutingModule
|
||||
]
|
||||
})
|
||||
export class MyProfileModule { }
|
||||
@@ -1,4 +1,4 @@
|
||||
<header class="w-screen bg-white dark:bg-gray-900">
|
||||
<header class="w-screen bg-white dark:bg-gray-900 min-h-12">
|
||||
<div class="w-full">
|
||||
<nav
|
||||
class="fixed w-full z-20 top-0 start-1/2 max-w-6xl -translate-x-1/2 bg-white dark:bg-gray-900">
|
||||
@@ -42,8 +42,7 @@
|
||||
</button>
|
||||
}
|
||||
<span class="text-black dark:text-white"> | </span>
|
||||
<button
|
||||
type="button"
|
||||
<a [routerLink]="['/auth']"
|
||||
class="text-black dark:text-white font-medium rounded-lg text-sm px-4 py-2 text-center flex items-center justify-center gap-1">
|
||||
<span class="inline-block h-4 w-4">
|
||||
<svg
|
||||
@@ -55,7 +54,7 @@
|
||||
</svg>
|
||||
</span>
|
||||
<span class="hidden sm:block text-black dark:text-white">Se connecter</span>
|
||||
</button>
|
||||
</a>
|
||||
<button
|
||||
data-collapse-toggle="navbar-sticky"
|
||||
type="button"
|
||||
|
||||
56
src/app/shared/features/login/login.component.html
Normal file
56
src/app/shared/features/login/login.component.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()" class="w-full space-y-4">
|
||||
<div class="">
|
||||
<div class="relative">
|
||||
<span class="absolute block w-3 h-3 -translate-y-1/2 top-1/2 left-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-full h-full fill-current" viewBox="0 0 512 512">
|
||||
<path
|
||||
d="M256 64C150 64 64 150 64 256s86 192 192 192c17.7 0 32 14.3 32 32s-14.3 32-32 32C114.6 512 0 397.4 0 256S114.6 0 256 0S512 114.6 512 256v32c0 53-43 96-96 96c-29.3 0-55.6-13.2-73.2-33.9C320 371.1 289.5 384 256 384c-70.7 0-128-57.3-128-128s57.3-128 128-128c27.9 0 53.7 8.9 74.7 24.1c5.7-5 13.1-8.1 21.3-8.1c17.7 0 32 14.3 32 32v80 32c0 17.7 14.3 32 32 32s32-14.3 32-32V256c0-106-86-192-192-192zm64 192a64 64 0 1 0 -128 0 64 64 0 1 0 128 0z"/>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input formControlName="email" placeholder="email" type="email" id="email" name="email" class="w-full h-10 px-5 py-2 text-xs bg-transparent border rounded-md"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<div class="text-right">
|
||||
<div class="relative">
|
||||
<span class="absolute block w-3 h-3 -translate-y-1/2 top-1/2 left-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-full h-full fill-current" viewBox="0 0 448 512">
|
||||
<path
|
||||
d="M144 144v48H304V144c0-44.2-35.8-80-80-80s-80 35.8-80 80zM80 192V144C80 64.5 144.5 0 224 0s144 64.5 144 144v48h16c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V256c0-35.3 28.7-64 64-64H80z"/>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input formControlName="password" placeholder="mot de passe" type="password" id="password" name="" class="w-full h-10 px-5 py-2 text-xs bg-transparent border rounded-md"/>
|
||||
<button class="absolute w-4 h-4 -translate-y-1/2 right-1 top-1/2 togglePasswordVisibility">
|
||||
<span class="inline-block w-4 h-4">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-full h-full fill-current" viewBox="0 -960 960 960">
|
||||
<path d="M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<a [routerLink]="['']" class="text-xs">Mot de passe oublié?</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="relative">
|
||||
<button class="text-xs py-2 px-4 border bg-[#002B2F] w-1/2 text-center text-gray-50 rounded-md">
|
||||
Se connecter
|
||||
</button>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<div class="flex items-center">
|
||||
<input checked id="checked-checkbox" type="checkbox" value="" class="w-4 h-4 text-red-600 bg-gray-100 border-gray-300 rounded"/>
|
||||
<label for="checked-checkbox" class="text-sm font-medium ms-2">
|
||||
Se souvenir de moi
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="">
|
||||
<p class="text-xs font-light text-center"> Vous n'avez pas de compte?
|
||||
<a [routerLink]="['register']" class="font-bold">Créez-en ici</a>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
0
src/app/shared/features/login/login.component.scss
Normal file
0
src/app/shared/features/login/login.component.scss
Normal file
23
src/app/shared/features/login/login.component.spec.ts
Normal file
23
src/app/shared/features/login/login.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoginComponent } from './login.component';
|
||||
|
||||
describe('LoginComponent', () => {
|
||||
let component: LoginComponent;
|
||||
let fixture: ComponentFixture<LoginComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [LoginComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(LoginComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
35
src/app/shared/features/login/login.component.ts
Normal file
35
src/app/shared/features/login/login.component.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import {Component, inject, output} from '@angular/core';
|
||||
import {Router, RouterLink} from "@angular/router";
|
||||
import {FormBuilder, FormControl, ReactiveFormsModule, Validators} from "@angular/forms";
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
standalone: true,
|
||||
imports: [
|
||||
RouterLink,
|
||||
ReactiveFormsModule
|
||||
],
|
||||
templateUrl: './login.component.html',
|
||||
styleUrl: './login.component.scss'
|
||||
})
|
||||
export class LoginComponent {
|
||||
private formBuilder = inject(FormBuilder);
|
||||
private router = inject(Router);
|
||||
loginForm = this.formBuilder.group({
|
||||
email: new FormControl('', Validators.required),
|
||||
password: new FormControl('', Validators.required)
|
||||
});
|
||||
|
||||
formSubmitted = output<any>()
|
||||
|
||||
onSubmit() {
|
||||
if (this.loginForm.invalid) {
|
||||
return;
|
||||
}
|
||||
const data = this.loginForm.getRawValue();
|
||||
this.formSubmitted.emit(data);
|
||||
|
||||
this.router.navigate(['/my-profile'])
|
||||
}
|
||||
|
||||
}
|
||||
67
src/app/shared/features/register/register.component.html
Normal file
67
src/app/shared/features/register/register.component.html
Normal file
@@ -0,0 +1,67 @@
|
||||
<form [formGroup]="registerForm" (ngSubmit)="onSubmit()" class="w-full space-y-4">
|
||||
|
||||
<div class="">
|
||||
<div class="relative">
|
||||
<span class="absolute block w-3 h-3 -translate-y-1/2 top-1/2 left-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||
class="w-3 h-3">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"/>
|
||||
</svg>
|
||||
|
||||
</span>
|
||||
|
||||
<input formControlName="name" placeholder="nom" type="text" name="name" id="name"
|
||||
class="w-full h-10 px-5 py-2 text-xs bg-transparent border rounded-md"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<div class="relative">
|
||||
<span class="absolute block w-3 h-3 -translate-y-1/2 top-1/2 left-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-full h-full fill-current" viewBox="0 0 512 512">
|
||||
<path
|
||||
d="M256 64C150 64 64 150 64 256s86 192 192 192c17.7 0 32 14.3 32 32s-14.3 32-32 32C114.6 512 0 397.4 0 256S114.6 0 256 0S512 114.6 512 256v32c0 53-43 96-96 96c-29.3 0-55.6-13.2-73.2-33.9C320 371.1 289.5 384 256 384c-70.7 0-128-57.3-128-128s57.3-128 128-128c27.9 0 53.7 8.9 74.7 24.1c5.7-5 13.1-8.1 21.3-8.1c17.7 0 32 14.3 32 32v80 32c0 17.7 14.3 32 32 32s32-14.3 32-32V256c0-106-86-192-192-192zm64 192a64 64 0 1 0 -128 0 64 64 0 1 0 128 0z"/>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input formControlName="email" placeholder="email" type="email" id="email" name="email"
|
||||
class="w-full h-10 px-5 py-2 text-xs bg-transparent border rounded-md"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<div class="text-right">
|
||||
<div class="relative">
|
||||
<span class="absolute block w-3 h-3 -translate-y-1/2 top-1/2 left-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-full h-full fill-current" viewBox="0 0 448 512">
|
||||
<path
|
||||
d="M144 144v48H304V144c0-44.2-35.8-80-80-80s-80 35.8-80 80zM80 192V144C80 64.5 144.5 0 224 0s144 64.5 144 144v48h16c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V256c0-35.3 28.7-64 64-64H80z"/>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input formControlName="password" placeholder="mot de passe" type="password" id="password" name="password"
|
||||
class="w-full h-10 px-5 py-2 text-xs bg-transparent border rounded-md"/>
|
||||
<button class="absolute w-4 h-4 -translate-y-1/2 right-1 top-1/2 togglePasswordVisibility">
|
||||
<span class="inline-block w-4 h-4">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-full h-full fill-current" viewBox="0 -960 960 960">
|
||||
<path
|
||||
d="M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="relative">
|
||||
<button type="submit" class="text-xs py-2 px-4 border bg-[#002B2F] w-1/2 text-center text-gray-50 rounded-md">
|
||||
S'inscrire
|
||||
</button>
|
||||
</div>
|
||||
<div class="">
|
||||
<p class="text-xs font-light text-center"> Vous avez un compte?
|
||||
<a [routerLink]="['/auth']" class="font-bold">Connectez vous ici</a>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
23
src/app/shared/features/register/register.component.spec.ts
Normal file
23
src/app/shared/features/register/register.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RegisterComponent } from './register.component';
|
||||
|
||||
describe('RegisterComponent', () => {
|
||||
let component: RegisterComponent;
|
||||
let fixture: ComponentFixture<RegisterComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [RegisterComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(RegisterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
35
src/app/shared/features/register/register.component.ts
Normal file
35
src/app/shared/features/register/register.component.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import {Component, inject, output} from '@angular/core';
|
||||
import {Router, RouterLink} from "@angular/router";
|
||||
import {FormBuilder, FormControl, ReactiveFormsModule, Validators} from "@angular/forms";
|
||||
|
||||
@Component({
|
||||
selector: 'app-register',
|
||||
standalone: true,
|
||||
imports: [
|
||||
RouterLink,
|
||||
ReactiveFormsModule
|
||||
],
|
||||
templateUrl: './register.component.html',
|
||||
styleUrl: './register.component.scss'
|
||||
})
|
||||
export class RegisterComponent {
|
||||
private formBuilder = inject(FormBuilder);
|
||||
private router = inject(Router);
|
||||
protected registerForm = this.formBuilder.group({
|
||||
name: new FormControl('', Validators.required),
|
||||
email: new FormControl('', Validators.required),
|
||||
password: new FormControl('', Validators.required)
|
||||
});
|
||||
|
||||
formSubmitted = output<any>()
|
||||
|
||||
onSubmit() {
|
||||
if (this.registerForm.invalid) {
|
||||
return;
|
||||
}
|
||||
const data = this.registerForm.getRawValue();
|
||||
this.formSubmitted.emit(data);
|
||||
|
||||
this.router.navigate(['/auth'])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user