-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
credit-card-number.pipe.ts
64 lines (53 loc) · 1.8 KB
/
credit-card-number.pipe.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import { Pipe, PipeTransform } from "@angular/core";
interface CardRuleEntry {
cardLength: number;
blocks: number[];
}
// See https://baymard.com/checkout-usability/credit-card-patterns for
// all possible credit card spacing patterns. For now, we just handle
// the below.
const numberFormats: Record<string, CardRuleEntry[]> = {
Visa: [{ cardLength: 16, blocks: [4, 4, 4, 4] }],
Mastercard: [{ cardLength: 16, blocks: [4, 4, 4, 4] }],
Maestro: [
{ cardLength: 16, blocks: [4, 4, 4, 4] },
{ cardLength: 13, blocks: [4, 4, 5] },
{ cardLength: 15, blocks: [4, 6, 5] },
{ cardLength: 19, blocks: [4, 4, 4, 4, 3] },
],
Discover: [{ cardLength: 16, blocks: [4, 4, 4, 4] }],
"Diners Club": [{ cardLength: 14, blocks: [4, 6, 4] }],
JCB: [{ cardLength: 16, blocks: [4, 4, 4, 4] }],
UnionPay: [
{ cardLength: 16, blocks: [4, 4, 4, 4] },
{ cardLength: 19, blocks: [6, 13] },
],
Amex: [{ cardLength: 15, blocks: [4, 6, 5] }],
Other: [{ cardLength: 16, blocks: [4, 4, 4, 4] }],
};
@Pipe({ name: "creditCardNumber" })
export class CreditCardNumberPipe implements PipeTransform {
transform(creditCardNumber: string, brand: string): string {
let rules = numberFormats[brand];
if (rules == null) {
rules = numberFormats["Other"];
}
const cardLength = creditCardNumber.length;
let matchingRule = rules.find((r) => r.cardLength == cardLength);
if (matchingRule == null) {
matchingRule = rules[0];
}
const blocks = matchingRule.blocks;
const chunks: string[] = [];
let total = 0;
blocks.forEach((c) => {
chunks.push(creditCardNumber.slice(total, total + c));
total += c;
});
// Append the remaining part
if (cardLength > total) {
chunks.push(creditCardNumber.slice(total));
}
return chunks.join(" ");
}
}