btc_horse/btc-UI/src/app/login/login.component.ts
2025-07-22 13:24:15 +05:30

559 lines
16 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 } from '@angular/common/http';
// import { 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{6}$/)]],
// });
// }
// 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 >= 6) 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;
// }
// sharedWindow: Window | null = null; // Add this at the top of your class
// onSubmit(): void {
// if (this.loginForm.invalid) {
// this.loginForm.markAllAsTouched();
// return;
// }
// const { email, password } = this.loginForm.value;
// this.btcService.userLogin(email, password).subscribe({
// next: (response: HttpResponse<{ name: string; employeeId: string }>) => {
// const employee = response.body;
// this.passwordStatus = true;
// // Save user info
// localStorage.setItem('userName', employee?.name || 'Unknown User');
// localStorage.setItem('employeeId', employee?.employeeId || email);
// // ✅ Trigger shared display window via Electron
// (window as any).electronAPI?.openSecondScreen?.();
// // ✅ Navigate to home
// this.router.navigate(['/home']);
// },
// error: () => {
// this.loginError = 'Invalid login credentials';
// },
// });
// }
// 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);
// });
// }
// }
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{6}$/)]],
});
}
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 >= 6) 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: HttpResponse<{ name: string; employeeId: string }>) => {
const employee = response.body;
this.passwordStatus = true;
const printData = {
name: employee?.name || 'Unknown User',
employeeId: employee?.employeeId || email,
action: 'login',
};
localStorage.setItem('userName', printData.name);
localStorage.setItem('employeeId', printData.employeeId);
// ✅ Re-enable print logic
this.printAndRedirect(printData);
},
error: () => {
this.loginError = 'Invalid login credentials';
},
});
}
private async printAndRedirect(printData: { name: string; employeeId: string; action: string }) {
try {
const res = await fetch('http://localhost:9100/print', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(printData),
});
if (!res.ok) throw new Error('Print failed');
console.log('🖨️ Print successful');
// ✅ Open second screen
(window as any).electronAPI?.openSecondScreen?.();
// ✅ Navigate to home screen
this.router.navigate(['/home']);
} catch (err) {
console.error('‼️ Print failed', err);
this.loginError = 'Login OK, but printing failed. Please check the printer.';
}
}
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);
});
}
}