btc_horse/btc-UI/src/app/login/login.component.ts

303 lines
8.2 KiB
TypeScript
Executable File

import {
Component,
ElementRef,
ViewChild,
ChangeDetectorRef,
OnInit,
OnDestroy,
} from '@angular/core';
import {
FormBuilder,
FormGroup,
Validators,
ReactiveFormsModule,
} from '@angular/forms';
import { CommonModule } from '@angular/common';
import { Router } from '@angular/router';
import { BtcService } from '../service/btc.service';
import { HttpClientModule, HttpResponse } from '@angular/common/http';
@Component({
selector: 'app-login',
standalone: true,
imports: [CommonModule, ReactiveFormsModule, HttpClientModule],
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
})
export class LoginComponent implements OnInit, OnDestroy {
loginForm: FormGroup;
focusedField: 'email' | 'password' | null = null;
loginError: string | null = null;
passwordStatus: boolean = true;
scanningEnabled: boolean = true;
@ViewChild('emailInput', { static: true })
emailInputRef!: ElementRef<HTMLInputElement>;
@ViewChild('passwordInput', { static: true })
passwordInputRef!: ElementRef<HTMLInputElement>;
private barcodeBuffer = '';
private scanStartedAt = 0;
private readonly SCAN_GAP_MS = 100;
constructor(
private fb: FormBuilder,
private cdRef: ChangeDetectorRef,
private router: Router,
private btcService: BtcService
) {
this.loginForm = this.fb.group({
email: ['', Validators.required],
password: ['', [Validators.required, Validators.pattern(/^\d{7}$/)]],
});
}
ngOnInit(): void {
window.addEventListener('keydown', this.handleScan);
}
ngOnDestroy(): void {
window.removeEventListener('keydown', this.handleScan);
}
toggleScan(): void {
this.scanningEnabled = !this.scanningEnabled;
}
handleScan = (event: KeyboardEvent): void => {
if (this.focusedField !== 'email') return;
if (!this.scanningEnabled) {
const ctrl = this.loginForm.get('email')!;
let val = ctrl.value || '';
if (event.key >= '0' && event.key <= '9') {
if (val.length < 12) {
val += event.key;
ctrl.setValue(val);
this.emailInputRef.nativeElement.value = val;
}
event.preventDefault();
} else if (event.key === 'Backspace') {
val = val.slice(0, -1);
ctrl.setValue(val);
this.emailInputRef.nativeElement.value = val;
event.preventDefault();
} else if (event.key === 'Delete') {
ctrl.setValue('');
this.emailInputRef.nativeElement.value = '';
event.preventDefault();
}
return;
}
const now = Date.now();
if (now - this.scanStartedAt > this.SCAN_GAP_MS) {
this.barcodeBuffer = '';
}
this.scanStartedAt = now;
if (event.key === 'Enter') {
this.commitScan();
return;
}
const ch = this.toPrintableChar(event);
if (ch) this.barcodeBuffer += ch;
};
private toPrintableChar(ev: KeyboardEvent): string {
if (ev.key.length === 1) return ev.key;
if (ev.key === 'Process') {
if (ev.keyCode >= 48 && ev.keyCode <= 57)
return String.fromCharCode(ev.keyCode);
if (ev.keyCode >= 65 && ev.keyCode <= 90)
return String.fromCharCode(ev.keyCode);
}
return '';
}
private commitScan(): void {
if (!this.barcodeBuffer) return;
this.loginForm.get('email')!.setValue(this.barcodeBuffer);
this.emailInputRef.nativeElement.value = this.barcodeBuffer;
this.setFocus('password');
setTimeout(() => this.passwordInputRef.nativeElement.focus(), 0);
this.barcodeBuffer = '';
}
removeReadonly(input: HTMLInputElement): void {
input.removeAttribute('readonly');
setTimeout(() => input.setAttribute('readonly', 'true'), 100);
}
setFocus(field: 'email' | 'password'): void {
this.focusedField = field;
}
formatUsernameDisplay(raw: string): string {
return /^\d+$/.test(raw) ? raw.replace(/(\d{4})(?=\d)/g, '$1-') : raw;
}
onNumpadClick(value: string): void {
if (this.focusedField === 'password') {
const ctrl = this.loginForm.get('password')!;
const current = ctrl.value || '';
if (current.length >= 7) return;
const newVal = current + value;
ctrl.setValue(newVal);
this.passwordInputRef.nativeElement.value = newVal;
setTimeout(() => {
this.passwordInputRef.nativeElement.focus();
this.passwordInputRef.nativeElement.setSelectionRange(
newVal.length,
newVal.length
);
}, 0);
this.cdRef.detectChanges();
} else if (this.focusedField === 'email' && !this.scanningEnabled) {
const ctrl = this.loginForm.get('email')!;
let val = ctrl.value || '';
if (val.length < 12) {
val += value;
ctrl.setValue(val);
this.emailInputRef.nativeElement.value = val;
}
setTimeout(() => {
this.emailInputRef.nativeElement.focus();
this.emailInputRef.nativeElement.setSelectionRange(
val.length,
val.length
);
}, 0);
this.cdRef.detectChanges();
}
}
onBackspace(): void {
if (this.focusedField === 'password') {
const ctrl = this.loginForm.get('password')!;
const current = ctrl.value || '';
const newVal = current.slice(0, -1);
ctrl.setValue(newVal);
this.passwordInputRef.nativeElement.value = newVal;
setTimeout(() => {
this.passwordInputRef.nativeElement.focus();
this.passwordInputRef.nativeElement.setSelectionRange(
newVal.length,
newVal.length
);
}, 0);
this.cdRef.detectChanges();
} else if (this.focusedField === 'email' && !this.scanningEnabled) {
const ctrl = this.loginForm.get('email')!;
let val = ctrl.value || '';
val = val.slice(0, -1);
ctrl.setValue(val);
this.emailInputRef.nativeElement.value = val;
setTimeout(() => {
this.emailInputRef.nativeElement.focus();
this.emailInputRef.nativeElement.setSelectionRange(
val.length,
val.length
);
}, 0);
this.cdRef.detectChanges();
}
}
resetUserPassMessage() {
this.passwordStatus = true;
}
onSubmit(): void {
if (this.loginForm.invalid) {
this.loginForm.markAllAsTouched();
return;
}
const { email, password } = this.loginForm.value;
this.btcService.userLogin(email, password).subscribe({
next: (response) => {
const employee = response.body;
console.log('🧠 Raw employee response:', employee);
const userName = employee?.userName || 'Unknown User';
const employeeId = employee?.userIdNumber || email;
console.log('✅ Parsed name:', userName);
console.log('✅ Parsed ID:', employeeId);
this.passwordStatus = true;
// Prepare print data
const printData = {
name: userName,
employeeId: employeeId,
action: 'login',
type: 'login' // ← ADD THIS
};
// Store in localStorage
localStorage.setItem('userName', userName);
localStorage.setItem('employeeId', employeeId);
localStorage.setItem('password', password);
// Optional print logic
fetch('http://localhost:9100/print', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(printData),
})
.then((res) => {
if (!res.ok) throw new Error('Print failed');
console.log('🖨️ Print successful');
// Open second screen
(window as any).electronAPI?.openSecondScreen?.();
// // Navigate to home
this.router.navigate(['/home']);
})
.catch((err) => {
console.error('‼️ Print failed', err);
this.loginError = 'Login OK, but printing failed.';
});
},
error: () => {
this.loginError = 'Invalid login credentials';
},
});
}
showConfirmModal : boolean = false;
confirmShutdown() : void{
this.showConfirmModal = false;
this.shutdownSystem();
}
shutdownSystem(): void {
fetch('http://localhost:3000/shutdown', {
method: 'POST',
})
.then((res) => {
if (!res.ok) throw new Error('Shutdown failed');
console.log('🛑 Shutdown triggered');
})
.catch((err) => {
console.error('‼️ Failed to shutdown', err);
});
}
}