diff --git a/.changeset/spicy-mayflies-give.md b/.changeset/spicy-mayflies-give.md new file mode 100644 index 000000000..354f309c4 --- /dev/null +++ b/.changeset/spicy-mayflies-give.md @@ -0,0 +1,7 @@ +--- +"@evervault/card-validator": minor +"@evervault/ui-components": patch +--- + +- Adds `reason` to CVC validation failures +- Fixes bug where failed card validation forces a failed CVC validation diff --git a/packages/card-validator/index.ts b/packages/card-validator/index.ts index db6f9e767..9c238e9f9 100644 --- a/packages/card-validator/index.ts +++ b/packages/card-validator/index.ts @@ -114,12 +114,13 @@ export function validateCVC( return { cvc: null, isValid: false, + reason: "invalid_cvc", }; } if (!cardNumber) { return { - cvc: cvc, + cvc, isValid: true, }; } @@ -129,6 +130,7 @@ export function validateCVC( return { cvc: null, isValid: false, + reason: "invalid_number", }; } @@ -146,9 +148,17 @@ export function validateCVC( return brand.securityCodeValidationRules.lengths.includes(cvc.length); }); + if (!isCVCValid) { + return { + cvc: null, + isValid: false, + reason: "invalid_brand_cvc", + }; + } + return { - cvc: isCVCValid ? cvc : null, - isValid: isCVCValid, + cvc, + isValid: true, }; } diff --git a/packages/card-validator/test/validate-cvc.test.ts b/packages/card-validator/test/validate-cvc.test.ts index 584cb702b..6db2b4084 100644 --- a/packages/card-validator/test/validate-cvc.test.ts +++ b/packages/card-validator/test/validate-cvc.test.ts @@ -14,31 +14,31 @@ const testCases: TestCase[] = [ scope: "Invalid card number", cardNumber: "123", cvc: "123", - expectedResult: { cvc: null, isValid: false }, + expectedResult: { cvc: null, isValid: false, reason: "invalid_number" }, }, { scope: "Non digit CVC", cardNumber: "4242424242424242", cvc: "abc", - expectedResult: { cvc: null, isValid: false }, + expectedResult: { cvc: null, isValid: false, reason: "invalid_cvc" }, }, { scope: "CVC with spaces", cardNumber: "4242424242424242", cvc: "123 ", - expectedResult: { cvc: null, isValid: false }, + expectedResult: { cvc: null, isValid: false, reason: "invalid_cvc" }, }, { scope: "CVC with wrong length mastercard", cardNumber: "5555555555554444", cvc: "1234", - expectedResult: { cvc: null, isValid: false }, + expectedResult: { cvc: null, isValid: false, reason: "invalid_brand_cvc" }, }, { scope: "CVC with wrong length amex", cardNumber: "378282246310005", cvc: "12", - expectedResult: { cvc: null, isValid: false }, + expectedResult: { cvc: null, isValid: false, reason: "invalid_cvc" }, }, { scope: "Valid CVC Mastercard", @@ -86,13 +86,13 @@ const testCases: TestCase[] = [ scope: "2 digit CVC", cardNumber: "", cvc: "12", - expectedResult: { cvc: null, isValid: false }, + expectedResult: { cvc: null, isValid: false, reason: "invalid_cvc" }, }, { scope: "5 digit CVC", cardNumber: "", cvc: "12345", - expectedResult: { cvc: null, isValid: false }, + expectedResult: { cvc: null, isValid: false, reason: "invalid_cvc" }, }, ]; diff --git a/packages/card-validator/types.ts b/packages/card-validator/types.ts index 946189672..e239989fe 100644 --- a/packages/card-validator/types.ts +++ b/packages/card-validator/types.ts @@ -35,7 +35,13 @@ export type CardExpiryValidationResult = { isValid: boolean; }; -export type CardCVCValidationResult = { - cvc: string | null; - isValid: boolean; -}; +export type CardCVCValidationResult = + | { + cvc: string; + isValid: true; + } + | { + cvc: null; + isValid: false; + reason: "invalid_cvc" | "invalid_number" | "invalid_brand_cvc"; + }; diff --git a/packages/ui-components/src/Card/index.tsx b/packages/ui-components/src/Card/index.tsx index afc1ada8f..b25e5684a 100644 --- a/packages/ui-components/src/Card/index.tsx +++ b/packages/ui-components/src/Card/index.tsx @@ -106,8 +106,15 @@ export function Card({ config }: { config: CardConfig }) { const cardValidation = validateNumber(values.number); const cvcValidation = validateCVC(values.cvc, values.number); - if (!cvcValidation.isValid) { + // Skip CVC validation if failed because of invalid card number + if ( + cvcValidation.reason === "invalid_number" && + !cardValidation.isValid + ) { + return undefined; + } + return "invalid"; }