begin auth
This commit is contained in:
@@ -2,6 +2,7 @@ import { Routes } from '@angular/router';
|
||||
import { ScreenSend } from './screens/screen-send/screen-send';
|
||||
import { ScreenReceive } from './screens/screen-receive/screen-receive';
|
||||
import { ScreenProfile } from './screens/screen-profile/screen-profile';
|
||||
import { ScreenLogin } from './screens/screen-login/screen-login';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
@@ -9,6 +10,10 @@ export const routes: Routes = [
|
||||
pathMatch:'full',
|
||||
redirectTo: '/send'
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
component: ScreenLogin,
|
||||
},
|
||||
{
|
||||
path:'send',
|
||||
component: ScreenSend,
|
||||
|
||||
79
client/src/app/screens/screen-login/screen-login.html
Normal file
79
client/src/app/screens/screen-login/screen-login.html
Normal file
@@ -0,0 +1,79 @@
|
||||
<div class="d-flex align-items-center min-vh-100 bg-light">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-4 col-md-6 col-sm-8">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body p-4">
|
||||
<div class="text-center mb-4">
|
||||
<i class="bi bi-lock-fill fs-1 text-primary"></i>
|
||||
<h3 class="mt-2">Sign In</h3>
|
||||
</div>
|
||||
|
||||
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()" novalidate>
|
||||
<!-- Email -->
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
class="form-control"
|
||||
formControlName="username"
|
||||
placeholder="Enter your username"
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<div class="input-group">
|
||||
<input
|
||||
[type]="showPassword ? 'text' : 'password'"
|
||||
id="password"
|
||||
class="form-control"
|
||||
formControlName="password"
|
||||
placeholder="Enter your password"
|
||||
>
|
||||
<button
|
||||
class="btn btn-outline-secondary"
|
||||
type="button"
|
||||
(click)="showPassword = !showPassword"
|
||||
>
|
||||
<i class="bi" [class.bi-eye-fill]="showPassword" [class.bi-eye-slash-fill]="!showPassword"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary w-100 mb-3"
|
||||
>
|
||||
@if (loading) {
|
||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true">
|
||||
Signing In...
|
||||
</span>
|
||||
}@else {
|
||||
<span>Sign In</span>
|
||||
}
|
||||
</button>
|
||||
|
||||
|
||||
<!-- Error Alert -->
|
||||
<ngb-alert
|
||||
*ngIf="error"
|
||||
type="danger"
|
||||
(closed)="error = null"
|
||||
[dismissible]="true"
|
||||
>
|
||||
{{ error }}
|
||||
</ngb-alert>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
22
client/src/app/screens/screen-login/screen-login.spec.ts
Normal file
22
client/src/app/screens/screen-login/screen-login.spec.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ScreenLogin } from './screen-login';
|
||||
|
||||
describe('ScreenLogin', () => {
|
||||
let component: ScreenLogin;
|
||||
let fixture: ComponentFixture<ScreenLogin>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ScreenLogin],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ScreenLogin);
|
||||
component = fixture.componentInstance;
|
||||
await fixture.whenStable();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
55
client/src/app/screens/screen-login/screen-login.ts
Normal file
55
client/src/app/screens/screen-login/screen-login.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component } from '@angular/core';
|
||||
import { Validators, FormBuilder, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
@Component({
|
||||
selector: 'app-screen-login',
|
||||
imports: [FormsModule, NgbModule, ReactiveFormsModule, CommonModule],
|
||||
templateUrl: './screen-login.html',
|
||||
styleUrl: './screen-login.less',
|
||||
})
|
||||
export class ScreenLogin {
|
||||
loginForm: FormGroup;
|
||||
submitted = false;
|
||||
loading = false;
|
||||
showPassword = false;
|
||||
error: string | null = null;
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private router: Router
|
||||
) {
|
||||
this.loginForm = this.fb.group({
|
||||
email: ['', [Validators.required, Validators.email]],
|
||||
password: ['', [Validators.required, Validators.minLength(6)]],
|
||||
rememberMe: [false]
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.submitted = true;
|
||||
this.error = null;
|
||||
|
||||
if (this.loginForm.invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
const { email, password, rememberMe } = this.loginForm.value;
|
||||
|
||||
/*
|
||||
this.authService.login(email, password, rememberMe).subscribe({
|
||||
next: () => {
|
||||
this.router.navigate(['/dashboard']); // Redirect after login
|
||||
},
|
||||
error: (err) => {
|
||||
this.error = err.error?.message || 'Login failed. Please try again.';
|
||||
this.loading = false;
|
||||
}
|
||||
});
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
40
package-lock.json
generated
40
package-lock.json
generated
@@ -5564,6 +5564,25 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-parser": {
|
||||
"version": "1.4.7",
|
||||
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
|
||||
"integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie": "0.7.2",
|
||||
"cookie-signature": "1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-parser/node_modules/cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cookie-signature": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
|
||||
@@ -7243,10 +7262,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jose": {
|
||||
"version": "6.1.3",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz",
|
||||
"integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==",
|
||||
"dev": true,
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-6.2.0.tgz",
|
||||
"integrity": "sha512-xsfE1TcSCbUdo6U07tR0mvhg0flGxU8tPLbF03mirl2ukGQENhUg4ubGYQnhVH0b5stLlPM+WOqDkEl1R1y5sQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
@@ -10442,6 +10460,18 @@
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-jose": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-jose/-/ts-jose-6.2.0.tgz",
|
||||
"integrity": "sha512-KbuVu70utxPDrfjbPyjEs63GLA6ogBZlr7joyFmO/IvNWjwINa4LoZa5LhG/lp9Y8zb8HEkSTaAOCdnqIeMGqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jose": "6.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node": {
|
||||
"version": "10.9.2",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
|
||||
@@ -11261,6 +11291,7 @@
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.6",
|
||||
"dotenv": "^17.3.1",
|
||||
"express": "^5.2.1",
|
||||
@@ -11269,6 +11300,7 @@
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"sequelize": "^6.37.7",
|
||||
"sequelize-typescript": "^2.1.6",
|
||||
"ts-jose": "^6.2.0",
|
||||
"winston": "^3.19.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
},
|
||||
"workspaces": [
|
||||
"client",
|
||||
"server",
|
||||
"shared"
|
||||
"server"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.3.2",
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"dev": "npm run setup && npm run node; npm run teardown"
|
||||
},
|
||||
"dependencies": {
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.6",
|
||||
"dotenv": "^17.3.1",
|
||||
"express": "^5.2.1",
|
||||
@@ -25,6 +26,7 @@
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"sequelize": "^6.37.7",
|
||||
"sequelize-typescript": "^2.1.6",
|
||||
"ts-jose": "^6.2.0",
|
||||
"winston": "^3.19.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"name": "shared",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"license": "GPL-3.0",
|
||||
"author": "",
|
||||
"type": "commonjs",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
export interface Transaction {
|
||||
id: string;
|
||||
partner: string;
|
||||
amount: number;
|
||||
date: Date;
|
||||
type: 'Sent' | 'Received';
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../dist/out-tsc/shared",
|
||||
"declaration": true,
|
||||
"module": "es2020"
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user