begin auth

This commit is contained in:
eneller
2026-03-07 00:43:40 +01:00
parent 80a260f515
commit 3300622191
11 changed files with 200 additions and 37 deletions

View File

@@ -2,6 +2,7 @@ import { Routes } from '@angular/router';
import { ScreenSend } from './screens/screen-send/screen-send'; import { ScreenSend } from './screens/screen-send/screen-send';
import { ScreenReceive } from './screens/screen-receive/screen-receive'; import { ScreenReceive } from './screens/screen-receive/screen-receive';
import { ScreenProfile } from './screens/screen-profile/screen-profile'; import { ScreenProfile } from './screens/screen-profile/screen-profile';
import { ScreenLogin } from './screens/screen-login/screen-login';
export const routes: Routes = [ export const routes: Routes = [
{ {
@@ -9,6 +10,10 @@ export const routes: Routes = [
pathMatch:'full', pathMatch:'full',
redirectTo: '/send' redirectTo: '/send'
}, },
{
path: 'login',
component: ScreenLogin,
},
{ {
path:'send', path:'send',
component: ScreenSend, component: ScreenSend,

View 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>

View 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();
});
});

View 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
View File

@@ -5564,6 +5564,25 @@
"node": ">= 0.6" "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": { "node_modules/cookie-signature": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
@@ -7243,10 +7262,9 @@
} }
}, },
"node_modules/jose": { "node_modules/jose": {
"version": "6.1.3", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.0.tgz",
"integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", "integrity": "sha512-xsfE1TcSCbUdo6U07tR0mvhg0flGxU8tPLbF03mirl2ukGQENhUg4ubGYQnhVH0b5stLlPM+WOqDkEl1R1y5sQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/panva" "url": "https://github.com/sponsors/panva"
@@ -10442,6 +10460,18 @@
"node": ">= 14.0.0" "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": { "node_modules/ts-node": {
"version": "10.9.2", "version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
@@ -11261,6 +11291,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"cookie-parser": "^1.4.7",
"cors": "^2.8.6", "cors": "^2.8.6",
"dotenv": "^17.3.1", "dotenv": "^17.3.1",
"express": "^5.2.1", "express": "^5.2.1",
@@ -11269,6 +11300,7 @@
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"sequelize": "^6.37.7", "sequelize": "^6.37.7",
"sequelize-typescript": "^2.1.6", "sequelize-typescript": "^2.1.6",
"ts-jose": "^6.2.0",
"winston": "^3.19.0" "winston": "^3.19.0"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -13,8 +13,7 @@
}, },
"workspaces": [ "workspaces": [
"client", "client",
"server", "server"
"shared"
], ],
"devDependencies": { "devDependencies": {
"@types/node": "^25.3.2", "@types/node": "^25.3.2",

View File

@@ -17,6 +17,7 @@
"dev": "npm run setup && npm run node; npm run teardown" "dev": "npm run setup && npm run node; npm run teardown"
}, },
"dependencies": { "dependencies": {
"cookie-parser": "^1.4.7",
"cors": "^2.8.6", "cors": "^2.8.6",
"dotenv": "^17.3.1", "dotenv": "^17.3.1",
"express": "^5.2.1", "express": "^5.2.1",
@@ -25,6 +26,7 @@
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"sequelize": "^6.37.7", "sequelize": "^6.37.7",
"sequelize-typescript": "^2.1.6", "sequelize-typescript": "^2.1.6",
"ts-jose": "^6.2.0",
"winston": "^3.19.0" "winston": "^3.19.0"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -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": {}
}

View File

@@ -1,8 +0,0 @@
export interface Transaction {
id: string;
partner: string;
amount: number;
date: Date;
type: 'Sent' | 'Received';
}

View File

@@ -1,10 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../dist/out-tsc/shared",
"declaration": true,
"module": "es2020"
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}