Added ability to generate and copy identity card number.
This commit was merged in pull request #3.
This commit is contained in:
@@ -11,6 +11,7 @@ import { PeselComponent } from './components/pesel/pesel.component';
|
||||
import { NipComponent } from './components/nip/nip.component';
|
||||
import { RegonComponent } from './components/regon/regon.component';
|
||||
import { IbanComponent } from './components/iban/iban.component';
|
||||
import { IdentityCardComponent } from './components/identitycard/identitycard.component';
|
||||
import {NgOptimizedImage} from "@angular/common";
|
||||
|
||||
@NgModule({
|
||||
@@ -20,7 +21,8 @@ import {NgOptimizedImage} from "@angular/common";
|
||||
PeselComponent,
|
||||
NipComponent,
|
||||
RegonComponent,
|
||||
IbanComponent
|
||||
IbanComponent,
|
||||
IdentityCardComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
<app-regon></app-regon>
|
||||
<app-nip></app-nip>
|
||||
<app-pesel></app-pesel>
|
||||
<app-identity-card></app-identity-card>
|
||||
<app-iban></app-iban>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
17
src/app/components/identitycard/identitycard.component.html
Normal file
17
src/app/components/identitycard/identitycard.component.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<div class="generator">
|
||||
<div class="title">
|
||||
<span>DOWÓD OSOBISTY</span>
|
||||
</div>
|
||||
<div class="container">
|
||||
<input type="text" [formControl]="valueField" />
|
||||
|
||||
<div class="buttons">
|
||||
<img id="identityCardGenerateButton" ngSrc="assets/autorenew_black_24dp.svg" title="Generuj numer dowodu" alt="Generuj numer dowodu" style="margin-left: 1em;" (click)="generate()"
|
||||
height="24" width="24"/>
|
||||
<img id="identityCardCopyButton" ngSrc="assets/content_copy_black_24dp.svg" title="Skopiuj numer dowodu do schowka" alt="Skopiuj numer dowodu do schowka" style="margin: auto 1em;" (click)="copyToClipboard()"
|
||||
height="24" width="24"/>
|
||||
<img id="identityCardHelpButton" ngSrc="assets/info_black_24dp.svg" title="Szczegóły dotyczące numeru dowodu" alt="Definicja numeru dowodu na Wikipedii" (click)="navigateToDocs()"
|
||||
height="24" width="24"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
35
src/app/components/identitycard/identitycard.component.ts
Normal file
35
src/app/components/identitycard/identitycard.component.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AbstractControl, FormControl } from '@angular/forms';
|
||||
import { IdentityCardService } from 'src/app/service/identity-card.service';
|
||||
import { ClipboardService } from 'src/app/service/gui/clipboard.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-identity-card',
|
||||
templateUrl: './identitycard.component.html',
|
||||
styleUrls: ['./identitycard.component.scss'],
|
||||
standalone: false
|
||||
})
|
||||
export class IdentityCardComponent implements OnInit {
|
||||
public valueField: FormControl;
|
||||
|
||||
constructor(private identityCardService: IdentityCardService, private clipboardService: ClipboardService) {
|
||||
this.valueField = new FormControl('');
|
||||
this.valueField.setValidators([(control: AbstractControl) => this.identityCardService.validateIdentityCard(control.value)]);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.generate();
|
||||
}
|
||||
|
||||
generate(): void {
|
||||
this.valueField.setValue(this.identityCardService.generateIdentityCard());
|
||||
}
|
||||
|
||||
copyToClipboard(): void {
|
||||
this.clipboardService.copyToClipboard(this.valueField.value);
|
||||
}
|
||||
|
||||
navigateToDocs(): void {
|
||||
window.open('https://pl.wikipedia.org/wiki/Dow%C3%B3d_osobisty_w_Polsce#Numer_dowodu_osobistego', "_blank");
|
||||
}
|
||||
}
|
||||
85
src/app/service/identity-card.service.ts
Normal file
85
src/app/service/identity-card.service.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ValidationErrors } from '@angular/forms';
|
||||
import { CommonService } from './common.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class IdentityCardService {
|
||||
private static readonly weights: number[] = [7, 3, 1, 0, 7, 3, 1, 7, 3];
|
||||
private static readonly letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
constructor(private common: CommonService) { }
|
||||
|
||||
public generateIdentityCard(): string {
|
||||
let result = "";
|
||||
// Generate 3 letters
|
||||
for (let i = 0; i < 3; i++) {
|
||||
result += IdentityCardService.letters.charAt(this.common.getRandomInt(0, 25));
|
||||
}
|
||||
// Generate 5 digits (for positions 4-8)
|
||||
let digits = "";
|
||||
for (let i = 0; i < 5; i++) {
|
||||
digits += this.common.getRandomInt(0, 9).toString();
|
||||
}
|
||||
|
||||
// Calculate sum
|
||||
let sum = 0;
|
||||
// Letters
|
||||
for (let i = 0; i < 3; i++) {
|
||||
sum += this.letterToValue(result.charAt(i)) * IdentityCardService.weights[i];
|
||||
}
|
||||
// Digits
|
||||
for (let i = 0; i < 5; i++) {
|
||||
sum += parseInt(digits.charAt(i), 10) * IdentityCardService.weights[i + 4];
|
||||
}
|
||||
|
||||
const controlDigit = sum % 10;
|
||||
|
||||
return result + controlDigit + digits;
|
||||
}
|
||||
|
||||
public validateIdentityCard(id: string): ValidationErrors | null {
|
||||
const errors: ValidationErrors = {};
|
||||
if (!id) {
|
||||
errors.required = true;
|
||||
return errors;
|
||||
}
|
||||
|
||||
const upperId = id.toUpperCase();
|
||||
|
||||
if (upperId.length !== 9) {
|
||||
if (upperId.length < 9) errors.tooShort = true;
|
||||
else errors.tooLong = true;
|
||||
}
|
||||
|
||||
const pattern = /^[A-Z]{3}[0-9]{6}$/;
|
||||
if (!pattern.test(upperId)) {
|
||||
errors.invalidPattern = true;
|
||||
}
|
||||
|
||||
if (Object.keys(errors).length > 0) return errors;
|
||||
|
||||
// Control digit validation
|
||||
let sum = 0;
|
||||
for (let i = 0; i < 9; i++) {
|
||||
if (i === 3) continue; // skip control digit
|
||||
const char = upperId.charAt(i);
|
||||
const val = i < 3 ? this.letterToValue(char) : parseInt(char, 10);
|
||||
sum += val * IdentityCardService.weights[i];
|
||||
}
|
||||
|
||||
const calculatedControl = sum % 10;
|
||||
const actualControl = parseInt(upperId.charAt(3), 10);
|
||||
|
||||
if (calculatedControl !== actualControl) {
|
||||
errors.invalidControlDigit = true;
|
||||
}
|
||||
|
||||
return Object.keys(errors).length > 0 ? errors : null;
|
||||
}
|
||||
|
||||
private letterToValue(letter: string): number {
|
||||
return IdentityCardService.letters.indexOf(letter.toUpperCase()) + 10;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user