Add new components for AI and tutorials, update routing, and enhance file upload functionality
This commit is contained in:
@@ -1,78 +0,0 @@
|
||||
<h1 mat-dialog-title>Hi </h1>
|
||||
<form [formGroup]="signUpForm">
|
||||
<div mat-dialog-content>
|
||||
<p>User name</p>
|
||||
<mat-form-field class="fillField">
|
||||
<input matInput
|
||||
formControlName="username"
|
||||
[(ngModel)]="data.username"
|
||||
minlength="3"
|
||||
>
|
||||
</mat-form-field>
|
||||
<p>Email</p>
|
||||
<mat-form-field class="fillField">
|
||||
<mat-label>Email</mat-label>
|
||||
<input matInput type="email"
|
||||
formControlName="email"
|
||||
|
||||
placeholder="Ex. pat@example.com"
|
||||
[(ngModel)]="data.email"
|
||||
(blur)="updateErrorMessage()"
|
||||
required
|
||||
>
|
||||
@if (emailFormControl.invalid) {
|
||||
<mat-error>{{errorMessage()}}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<p>Password</p>
|
||||
<mat-form-field class="fillField">
|
||||
<mat-label>Enter your password</mat-label>
|
||||
<input matInput
|
||||
|
||||
formControlName = "password"
|
||||
[type]="hide() ? 'password' : 'text'"
|
||||
[(ngModel)]="data.password"
|
||||
minlength="6"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
mat-icon-button
|
||||
matSuffix
|
||||
(click)="clickEvent($event)"
|
||||
[attr.aria-label]="'Hide password'"
|
||||
[attr.aria-pressed]="hide()"
|
||||
>
|
||||
<mat-icon>{{hide() ? 'visibility_off' : 'visibility'}}</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
<p>Confirm password</p>
|
||||
<mat-form-field class="fillField">
|
||||
<mat-label>Confirm your password</mat-label>
|
||||
<input matInput
|
||||
|
||||
formControlName = "confirmPassword"
|
||||
[type]="hide() ? 'password' : 'text'"
|
||||
[(ngModel)]="data.confirmPassword"
|
||||
/>
|
||||
@if (signUpForm.get("confirmPassword")?.value !== signUpForm.get("password")?.value) {
|
||||
<mat-error>Passwords do not match</mat-error>
|
||||
}
|
||||
<button
|
||||
mat-icon-button
|
||||
matSuffix
|
||||
(click)="clickEvent($event)"
|
||||
[attr.aria-label]="'Hide password'"
|
||||
[attr.aria-pressed]="hide()"
|
||||
>
|
||||
<mat-icon>{{hide() ? 'visibility_off' : 'visibility'}}</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button (click)="login()">Login</button>
|
||||
<span class="menu-spacer"></span>
|
||||
<button mat-button mat-dialog-close (click)="onNoClick()">No Thanks</button>
|
||||
<button mat-button cdkFocusInitial (click)="signup()">Ok</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,7 +0,0 @@
|
||||
.menu-spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.fillField{
|
||||
width: 100%;
|
||||
};
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DialogSignupComponent } from './dialog-signup.component';
|
||||
|
||||
describe('DialogSignupComponent', () => {
|
||||
let component: DialogSignupComponent;
|
||||
let fixture: ComponentFixture<DialogSignupComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [DialogSignupComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(DialogSignupComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,141 +0,0 @@
|
||||
import {Component, CUSTOM_ELEMENTS_SCHEMA, EventEmitter, Inject, inject, OnInit, Output, signal} from '@angular/core';
|
||||
import {
|
||||
AbstractControl,
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
FormGroupDirective,
|
||||
FormsModule,
|
||||
NgForm,
|
||||
ReactiveFormsModule, ValidationErrors, ValidatorFn,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import {MatButtonModule} from '@angular/material/button';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogActions,
|
||||
MatDialogClose,
|
||||
MatDialogContent,
|
||||
MatDialogRef,
|
||||
MatDialogTitle
|
||||
} from '@angular/material/dialog';
|
||||
import {MatFormField, MatInput, MatLabel, MatSuffix} from '@angular/material/input';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||
import {DialogSignupData} from '../../main-module/main.component/main.component';
|
||||
import {ErrorStateMatcher} from '@angular/material/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dialog-signup.component',
|
||||
imports: [
|
||||
FormsModule,
|
||||
MatButtonModule,
|
||||
MatDialogActions,
|
||||
MatDialogClose,
|
||||
MatDialogContent,
|
||||
MatDialogTitle,
|
||||
MatFormField,
|
||||
MatIcon,
|
||||
MatInput,
|
||||
MatLabel,
|
||||
MatSuffix,
|
||||
MatFormField,
|
||||
ReactiveFormsModule,
|
||||
|
||||
],
|
||||
templateUrl: './dialog-signup.component.html',
|
||||
styleUrl: './dialog-signup.component.scss',
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class DialogSignupComponent implements OnInit {
|
||||
readonly dialogRef = inject(MatDialogRef<DialogSignupComponent>);
|
||||
hide = signal(true);
|
||||
|
||||
@Output() signupClicked = new EventEmitter<any>();
|
||||
@Output() loginClicked = new EventEmitter<any>();
|
||||
|
||||
private _snackBar = inject(MatSnackBar);
|
||||
|
||||
durationInSeconds = 5;
|
||||
|
||||
emailFormControl = new FormControl('', [Validators.required, Validators.email]);
|
||||
|
||||
matcher = new MyErrorStateMatcher();
|
||||
|
||||
errorMessage = signal('');
|
||||
|
||||
signUpForm = new FormGroup({
|
||||
username: new FormControl('', [Validators.required]),
|
||||
email: new FormControl('', [Validators.required, Validators.email]),
|
||||
password: new FormControl('', [Validators.required]),
|
||||
confirmPassword: new FormControl('', [Validators.required, this.validateSamePassword]),
|
||||
});
|
||||
minPw = 8;
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) public data:DialogSignupData,
|
||||
private formBuilder: FormBuilder) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
updateErrorMessage() {
|
||||
if (this.emailFormControl.hasError('required')) {
|
||||
this.errorMessage.set('You must enter a value');
|
||||
} else if (this.emailFormControl.hasError('email')) {
|
||||
this.errorMessage.set('Not a valid email');
|
||||
} else {
|
||||
this.errorMessage.set('');
|
||||
}
|
||||
}
|
||||
|
||||
clickEvent(event: MouseEvent) {
|
||||
this.hide.set(!this.hide());
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
onNoClick() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
openSignupFailedSnackBar(errorMessage : string = "Sign up failed.") {
|
||||
this._snackBar.open(errorMessage , "", {
|
||||
duration: this.durationInSeconds * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
openSignupSuccessSnackBar(message : string = "User registered successfully!") {
|
||||
this._snackBar.open(message, "", {
|
||||
duration: this.durationInSeconds * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
signup() {
|
||||
if (!this.signUpForm.invalid) {
|
||||
this.signupClicked.emit(this.data);
|
||||
}
|
||||
}
|
||||
|
||||
login() {
|
||||
this.loginClicked.emit();
|
||||
}
|
||||
|
||||
private validateSamePassword(control: AbstractControl): ValidationErrors | null {
|
||||
const password = control.parent?.get('password');
|
||||
const confirmPassword = control.parent?.get('confirmPassword');
|
||||
return password?.value == confirmPassword?.value ? null : { 'notSame': true };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Error when invalid control is dirty, touched, or submitted. */
|
||||
export class MyErrorStateMatcher implements ErrorStateMatcher {
|
||||
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||
const isSubmitted = form && form.submitted;
|
||||
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<h1 mat-dialog-title>Hi </h1>
|
||||
<div mat-dialog-content>
|
||||
<p>User name</p>
|
||||
<mat-form-field class="fillField">
|
||||
<input matInput [(ngModel)]="data.username">
|
||||
</mat-form-field>
|
||||
<p>Password</p>
|
||||
<mat-form-field class="fillField">
|
||||
<mat-label>Enter your password</mat-label>
|
||||
<input matInput
|
||||
[type]="hide() ? 'password' : 'text'"
|
||||
[(ngModel)]="data.password"
|
||||
/>
|
||||
<button
|
||||
mat-icon-button
|
||||
matSuffix
|
||||
(click)="clickEvent($event)"
|
||||
[attr.aria-label]="'Hide password'"
|
||||
[attr.aria-pressed]="hide()"
|
||||
>
|
||||
<mat-icon>{{hide() ? 'visibility_off' : 'visibility'}}</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button (click)="signup()">Sign Up</button>
|
||||
<span class="menu-spacer"></span>
|
||||
<button mat-button mat-dialog-close (click)="onNoClick()">No Thanks</button>
|
||||
<button mat-button cdkFocusInitial (click)="login()">Ok</button>
|
||||
</div>
|
||||
@@ -1,7 +0,0 @@
|
||||
.menu-spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.fillField{
|
||||
width: 100%;
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DialogComponent } from './dialog.component';
|
||||
|
||||
describe('DialogComponent', () => {
|
||||
let component: DialogComponent;
|
||||
let fixture: ComponentFixture<DialogComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [DialogComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(DialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,74 +0,0 @@
|
||||
import {ChangeDetectionStrategy, Component, EventEmitter, Inject, inject, Output, signal} from '@angular/core';
|
||||
import {MatButtonModule} from "@angular/material/button";
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogActions,
|
||||
MatDialogClose,
|
||||
MatDialogContent,
|
||||
MatDialogRef,
|
||||
MatDialogTitle
|
||||
} from "@angular/material/dialog";
|
||||
|
||||
|
||||
import {MatFormField, MatLabel, MatSuffix} from "@angular/material/form-field";
|
||||
import {MatInput} from "@angular/material/input";
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import {MatIcon} from "@angular/material/icon";
|
||||
import {DialogLoginData} from '../../main-module/main.component/main.component';
|
||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-dialog',
|
||||
imports: [MatButtonModule, MatLabel, MatDialogActions, MatDialogClose, MatDialogTitle, MatDialogContent, MatFormField, MatInput, FormsModule, MatIcon, MatSuffix],
|
||||
|
||||
templateUrl: './dialog.component.html',
|
||||
styleUrl: './dialog.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DialogComponent {
|
||||
readonly dialogRef = inject(MatDialogRef<DialogComponent>);
|
||||
hide = signal(true);
|
||||
|
||||
@Output() loginClicked = new EventEmitter<any>();
|
||||
@Output() signupClicked = new EventEmitter<any>();
|
||||
|
||||
private _snackBar = inject(MatSnackBar);
|
||||
durationInSeconds = 5;
|
||||
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) public data:DialogLoginData) {
|
||||
|
||||
}
|
||||
|
||||
openLoginFailedSnackBar(errorMessage : string = "Login failed.") {
|
||||
this._snackBar.open(errorMessage , "", {
|
||||
duration: this.durationInSeconds * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
onNoClick() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
|
||||
clickEvent(event: MouseEvent) {
|
||||
this.hide.set(!this.hide());
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
login() {
|
||||
this.loginClicked.emit(this.data);
|
||||
|
||||
}
|
||||
|
||||
signup() {
|
||||
this.signupClicked.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-13
@@ -5,7 +5,7 @@ import {MatCard, MatCardActions, MatCardContent, MatCardHeader} from '@angular/m
|
||||
import {MatFormField, MatInput, MatLabel} from '@angular/material/input';
|
||||
import {AsyncPipe} from '@angular/common';
|
||||
import {Image} from '../../models/image';
|
||||
import {ZhipuaiImageService} from '../../services/zhipuai-image.service';
|
||||
import {ZhipuaiImageService} from '../../modules/ai-module/zhipuai-image.service';
|
||||
import {MatProgressSpinner} from '@angular/material/progress-spinner';
|
||||
import {SpinnerService} from '../../services/spinner.service';
|
||||
|
||||
@@ -50,11 +50,6 @@ export class GenerateImageComponent implements OnInit {
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
const img = this.renderer.selectRootElement('img');
|
||||
this.viewer = new Viewer(img, {
|
||||
inline: true,
|
||||
});
|
||||
this.viewer.zoomTo(1);
|
||||
|
||||
}
|
||||
|
||||
@@ -77,11 +72,4 @@ export class GenerateImageComponent implements OnInit {
|
||||
this.viewer.update();
|
||||
})
|
||||
}
|
||||
|
||||
zoomPlus(){
|
||||
this.viewer.zoomTo(5);
|
||||
}
|
||||
zoomMinus(){
|
||||
this.viewer.zoomTo(-5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
<p>dfsdgdsgsdg</p>
|
||||
|
||||
<p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p><p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p><p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p>
|
||||
<p>dfsdgdsgsdg</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
<mat-card appearance="outlined">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Add tutorial</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content *ngIf="!submitted">
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label>Title</mat-label>
|
||||
<input matInput [(ngModel)]="query">
|
||||
</mat-form-field>
|
||||
<!– <kendo-editor [(ngModel)]="tutorial.description" ></kendo-editor>–>
|
||||
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button matButton (click)="generateImage()" >Save</button>
|
||||
<div>
|
||||
<h4>Tutorial was submitted successfully!</h4>
|
||||
|
||||
</div>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
|
||||
|
||||
<div>
|
||||
<angular-image-viewer [src]="images" [(config)]="config" [(index)]="imageIndexOne"
|
||||
[screenHeightOccupied]='0' (customImageEvent)="handleEvent($event)" >
|
||||
</angular-image-viewer>
|
||||
</div>
|
||||
-->
|
||||
@@ -1,23 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HomeComponent } from './home.component';
|
||||
|
||||
describe('HomeComponent', () => {
|
||||
let component: HomeComponent;
|
||||
let fixture: ComponentFixture<HomeComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [HomeComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HomeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,76 +0,0 @@
|
||||
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||
import {MatFormField, MatInput, MatLabel} from '@angular/material/input';
|
||||
import {AngularImageViewerModule, CustomImageEvent, ImageViewerConfig} from '@hreimer/angular-image-viewer';
|
||||
|
||||
import {ZhipuaiImageService} from '../../services/zhipuai-image.service';
|
||||
import {MatButton} from '@angular/material/button';
|
||||
|
||||
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {MatCard, MatCardActions, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||
import {Image} from '../../models/image';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home.component',
|
||||
imports: [
|
||||
|
||||
AngularImageViewerModule,
|
||||
FormsModule
|
||||
],
|
||||
templateUrl: './home.component.html',
|
||||
styleUrl: './home.component.scss',
|
||||
schemas :[CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
|
||||
export class HomeComponent {
|
||||
|
||||
query : string = '';
|
||||
|
||||
images = [];
|
||||
image: Image = {
|
||||
url: ''
|
||||
};
|
||||
imageIndexOne = 0;
|
||||
|
||||
config: ImageViewerConfig = { customBtns: [{ name: 'print', icon: {
|
||||
classes: 'fas fa-paperclip',
|
||||
text: 'link'
|
||||
} }, { name: 'link', icon: {
|
||||
classes: 'fas fa-paperclip',
|
||||
text: 'link'
|
||||
} }] };
|
||||
|
||||
submitted: boolean = false;
|
||||
|
||||
constructor(private zhipuaiImageService: ZhipuaiImageService) {
|
||||
|
||||
}
|
||||
|
||||
handleEvent(event: CustomImageEvent) {
|
||||
console.log(`${event.name} has been click on img ${event.imageIndex + 1}`);
|
||||
|
||||
switch (event.name) {
|
||||
case 'print':
|
||||
console.log('run print logic');
|
||||
break;
|
||||
}
|
||||
}
|
||||
generateImage(){
|
||||
this.zhipuaiImageService.generate(this.query).subscribe(
|
||||
data => {
|
||||
this.image = data;
|
||||
// @ts-ignore
|
||||
this.images = [this.image.url];
|
||||
|
||||
|
||||
console.log(data);
|
||||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<div class="col-md-12">
|
||||
<div class="card card-container">
|
||||
<img
|
||||
id="profile-img"
|
||||
src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
|
||||
class="profile-img-card"
|
||||
/>
|
||||
<form
|
||||
*ngIf="!isLoggedIn"
|
||||
name="form"
|
||||
(ngSubmit)="f.form.valid && onSubmit()"
|
||||
#f="ngForm"
|
||||
novalidate
|
||||
>
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="username"
|
||||
[(ngModel)]="form.username"
|
||||
required
|
||||
#username="ngModel"
|
||||
/>
|
||||
<div
|
||||
class="alert alert-danger"
|
||||
role="alert"
|
||||
*ngIf="username.errors && f.submitted"
|
||||
>
|
||||
Username is required!
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="password"
|
||||
[(ngModel)]="form.password"
|
||||
required
|
||||
minlength="6"
|
||||
#password="ngModel"
|
||||
/>
|
||||
<div
|
||||
class="alert alert-danger"
|
||||
role="alert"
|
||||
*ngIf="password.errors && f.submitted"
|
||||
>
|
||||
<div *ngIf="password.errors['required']">Password is required</div>
|
||||
<div *ngIf="password.errors['minlength']">
|
||||
Password must be at least 6 characters
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button class="btn btn-primary btn-block">
|
||||
Login
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div
|
||||
class="alert alert-danger"
|
||||
role="alert"
|
||||
*ngIf="f.submitted && isLoginFailed"
|
||||
>
|
||||
Login failed: {{ errorMessage }}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="alert alert-success" *ngIf="isLoggedIn">
|
||||
Logged in as {{ roles }}.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
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({
|
||||
declarations: [ LoginComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LoginComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,60 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import {NgIf} from "@angular/common";
|
||||
import {AuthService} from '../../services/auth.service';
|
||||
import {TokenStorageService} from '../../services/token-storage.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
imports: [
|
||||
FormsModule,
|
||||
NgIf
|
||||
],
|
||||
styleUrls: ['./login.component.scss']
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
|
||||
form: any = {
|
||||
username: null,
|
||||
password: null
|
||||
};
|
||||
isLoggedIn = false;
|
||||
isLoginFailed = false;
|
||||
errorMessage = '';
|
||||
roles: string[] = [];
|
||||
|
||||
constructor(private authService: AuthService, private tokenStorage: TokenStorageService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.tokenStorage.getToken()) {
|
||||
this.isLoggedIn = true;
|
||||
this.roles = this.tokenStorage.getUser().roles;
|
||||
}
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
const { username, password } = this.form;
|
||||
|
||||
this.authService.login(username, password).subscribe(
|
||||
data => {
|
||||
this.tokenStorage.saveToken(data.accessToken);
|
||||
this.tokenStorage.saveUser(data);
|
||||
|
||||
this.isLoginFailed = false;
|
||||
this.isLoggedIn = true;
|
||||
this.roles = this.tokenStorage.getUser().roles;
|
||||
this.reloadPage();
|
||||
},
|
||||
err => {
|
||||
this.errorMessage = err.error.message;
|
||||
this.isLoginFailed = true;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
reloadPage(): void {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<div class="container" *ngIf="currentUser; else loggedOut">
|
||||
<header class="jumbotron">
|
||||
<h3>
|
||||
<strong>{{ currentUser.username }}</strong> Profile
|
||||
</h3>
|
||||
</header>
|
||||
<p>
|
||||
<strong>Token:</strong>
|
||||
{{ currentUser.accessToken.substring(0, 20) }} ...
|
||||
{{ currentUser.accessToken.substr(currentUser.accessToken.length - 20) }}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Email:</strong>
|
||||
{{ currentUser.email }}
|
||||
</p>
|
||||
<strong>Roles:</strong>
|
||||
<ul>
|
||||
<li *ngFor="let role of currentUser.roles">
|
||||
{{ role }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<ng-template #loggedOut>
|
||||
Please login.
|
||||
</ng-template>
|
||||
@@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProfileComponent } from './profile.component';
|
||||
|
||||
describe('ProfileComponent', () => {
|
||||
let component: ProfileComponent;
|
||||
let fixture: ComponentFixture<ProfileComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ProfileComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProfileComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,23 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import {TokenStorageService} from '../../services/token-storage.service';
|
||||
import {NgForOf, NgIf} from '@angular/common';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-profile',
|
||||
templateUrl: './profile.component.html',
|
||||
imports: [
|
||||
NgForOf,
|
||||
NgIf
|
||||
],
|
||||
styleUrls: ['./profile.component.scss']
|
||||
})
|
||||
export class ProfileComponent implements OnInit {
|
||||
currentUser: any;
|
||||
|
||||
constructor(private token: TokenStorageService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.currentUser = this.token.getUser();
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
<div class="col-md-12">
|
||||
<div id="register">
|
||||
<img id="foto"
|
||||
id="profile-img"
|
||||
src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
|
||||
class="profile-img-card"
|
||||
/>
|
||||
<form
|
||||
*ngIf="!isSuccessful"
|
||||
name="form"
|
||||
(ngSubmit)="f.form.valid && onSubmit()"
|
||||
#f="ngForm"
|
||||
novalidate
|
||||
>
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="username"
|
||||
[(ngModel)]="form.username"
|
||||
[ngModelOptions]="{standalone: true}"
|
||||
required
|
||||
minlength="3"
|
||||
maxlength="20"
|
||||
#username="ngModel"
|
||||
/>
|
||||
<div class="alert-danger" *ngIf="username.errors && f.submitted">
|
||||
<div *ngIf="username.errors['required']">Username is required</div>
|
||||
<div *ngIf="username.errors['minlength']">
|
||||
Username must be at least 3 characters
|
||||
</div>
|
||||
<div *ngIf="username.errors['maxlength']">
|
||||
Username must be at most 20 characters
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
id="email"
|
||||
[(ngModel)]="form.email"
|
||||
[ngModelOptions]="{standalone: true}"
|
||||
required
|
||||
email
|
||||
#email="ngModel"
|
||||
/>
|
||||
<div class="alert-danger" *ngIf="email.errors && f.submitted">
|
||||
<div *ngIf="email.errors['required']">Email is required</div>
|
||||
<div *ngIf="email.errors['email']">
|
||||
Email must be a valid email address
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="password"
|
||||
[(ngModel)]="form.password"
|
||||
[ngModelOptions]="{standalone: true}"
|
||||
required
|
||||
minlength="6"
|
||||
#password="ngModel"
|
||||
/>
|
||||
<div class="alert-danger" *ngIf="password.errors && f.submitted">
|
||||
<div *ngIf="password.errors['required']">Password is required</div>
|
||||
<div *ngIf="password.errors['minlength']">
|
||||
Password must be at least 6 characters
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button class="btn btn-primary btn-block">Sign Up</button>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning" *ngIf="f.submitted && isSignUpFailed">
|
||||
Signup failed!<br />{{ errorMessage }}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="alert alert-success" *ngIf="isSuccessful">
|
||||
Your registration is successful!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,25 +0,0 @@
|
||||
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({
|
||||
declarations: [ RegisterComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RegisterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,46 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import {AuthService} from '../../services/auth.service';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {NgIf} from '@angular/common';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-register',
|
||||
templateUrl: './register.component.html',
|
||||
imports: [
|
||||
FormsModule,
|
||||
NgIf
|
||||
],
|
||||
styleUrls: ['./register.component.scss']
|
||||
})
|
||||
export class RegisterComponent implements OnInit {
|
||||
form: any = {
|
||||
username: null,
|
||||
email: null,
|
||||
password: null
|
||||
};
|
||||
isSuccessful = false;
|
||||
isSignUpFailed = false;
|
||||
errorMessage = '';
|
||||
|
||||
constructor(private authService: AuthService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
const { username, email, password } = this.form;
|
||||
|
||||
this.authService.register(username, email, password).subscribe(
|
||||
data => {
|
||||
console.log(data);
|
||||
this.isSuccessful = true;
|
||||
this.isSignUpFailed = false;
|
||||
},
|
||||
err => {
|
||||
this.errorMessage = err.error.message;
|
||||
this.isSignUpFailed = true;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||
import {Tutorial} from '../../models/tutorial.model';
|
||||
import {TutorialService} from '../../services/tutorial.service';
|
||||
|
||||
import {MatCard, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||
import {MarkdownComponent} from 'ngx-markdown';
|
||||
import {authInterceptorProviders} from '../../helpers/auth.interceptor';
|
||||
@@ -26,9 +26,9 @@ import {CustomHttpInterceptor} from '../../helpers/custom-http-interceptor';
|
||||
})
|
||||
export class TutorialsComponent {
|
||||
tutorials?: Tutorial[];
|
||||
|
||||
/*
|
||||
constructor(private tutorialService: TutorialService) {
|
||||
this.retrieveTutorials();
|
||||
// this.retrieveTutorials();
|
||||
}
|
||||
|
||||
// ngOnInit(): void {
|
||||
@@ -45,5 +45,5 @@ export class TutorialsComponent {
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user