Skip to content

Commit 6ddcac4

Browse files
committed
Add creditcard validators
1 parent 1a6372f commit 6ddcac4

File tree

3 files changed

+85
-5
lines changed

3 files changed

+85
-5
lines changed

lib/l10n/intl_en.arb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@
1818
"numericErrorText": "Value must be numeric.",
1919
"requiredErrorText": "This field cannot be empty.",
2020
"urlErrorText": "This field requires a valid URL address.",
21-
"phoneErrorText": "This field requires a valid phone number."
21+
"phoneErrorText": "This field requires a valid phone number.",
22+
"creditCardExpirationDateErrorText": "This field requires a valid expiration date.",
23+
"creditCardExpiredErrorText": "This credit card has expired.",
24+
"creditCardCVCErrorText": "This field requires a valid CVC code."
2225
}

lib/src/form_builder_validators.dart

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,40 @@ class FormBuilderValidators {
295295
? errorText ?? FormBuilderLocalizations.current.creditCardErrorText
296296
: null;
297297

298+
/// [FormFieldValidator] that requires the field's value to be a valid credit card expiration date.
299+
static FormFieldValidator<String> creditCardExpirationDate({
300+
String? errorText,
301+
}) =>
302+
(valueCandidate) => true == valueCandidate?.isNotEmpty &&
303+
!isCreditCardExpirationDate(valueCandidate!)
304+
? errorText ??
305+
FormBuilderLocalizations.current.creditCardExpirationDateErrorText
306+
: null;
307+
308+
/// [FormFieldValidator] that requires the field's value to be a valid credit card expiration date and not expired.
309+
static FormFieldValidator<String> creditCardExpirationDateNotExpired({
310+
String? errorText,
311+
}) =>
312+
(valueCandidate) => true == valueCandidate?.isNotEmpty &&
313+
!isCreditCardExpirationDate(valueCandidate!) &&
314+
!isNotExpiredCreditCardDate(valueCandidate)
315+
? errorText ??
316+
FormBuilderLocalizations.current.creditCardExpiredErrorText
317+
: null;
318+
319+
/// [FormFieldValidator] that requires the field's value to be a valid credit card CVC.
320+
static FormFieldValidator<String> creditCardCVC({
321+
String? errorText,
322+
}) =>
323+
compose<String>(
324+
[
325+
minLength(3,
326+
errorText: errorText ?? FormBuilderLocalizations.current.creditCardCVCErrorText),
327+
maxLength(4,
328+
errorText: errorText ?? FormBuilderLocalizations.current.creditCardCVCErrorText),
329+
],
330+
);
331+
298332
/// [FormFieldValidator] that requires the field's value to be a valid IP address.
299333
/// * [version] is a `String` or an `int`.
300334
static FormFieldValidator<String> ip({
@@ -319,8 +353,8 @@ class FormBuilderValidators {
319353
static FormFieldValidator<String> phoneNumber({
320354
String? errorText,
321355
}) =>
322-
(valueCandidate) => true == valueCandidate?.isNotEmpty &&
323-
!isPhoneNumber(valueCandidate!)
324-
? errorText ?? FormBuilderLocalizations.current.phoneErrorText
325-
: null;
356+
(valueCandidate) =>
357+
true == valueCandidate?.isNotEmpty && !isPhoneNumber(valueCandidate!)
358+
? errorText ?? FormBuilderLocalizations.current.phoneErrorText
359+
: null;
326360
}

lib/src/utils/validators.dart

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ RegExp _creditCard = RegExp(
1414

1515
RegExp _phoneNumber = RegExp(r'^(\+?\d{0,1})?\(?\d{3}\)?[-.\s]\d{3}[-.\s]\d{4}$');
1616

17+
RegExp _creditCardExpirationDate = RegExp(r'^[0-1][0-9]/\d{2}$');
18+
1719
int _maxUrlLength = 2083;
1820

1921
/// check if the string [str] is an email
@@ -241,3 +243,44 @@ bool isDate(String str) {
241243
bool isPhoneNumber(String str) {
242244
return _phoneNumber.hasMatch(str);
243245
}
246+
247+
/// check if the string is a valid credit card expiration date
248+
bool isCreditCardExpirationDate(String str) {
249+
// Check if the format matches MM/YY
250+
if (!_creditCardExpirationDate.hasMatch(str)) {
251+
return false;
252+
}
253+
254+
// Extract month and year from the value
255+
final parts = str.split('/').map(int.parse).toList();
256+
final month = parts[0];
257+
final year = parts[1];
258+
259+
// Check for valid month (1-12)
260+
if (month < 1 || month > 12) {
261+
return false;
262+
}
263+
264+
return year > 0;
265+
}
266+
267+
/// check if the string is not a expired credit card date
268+
bool isNotExpiredCreditCardDate(String str) {
269+
final parts = str.split('/').map(int.parse).toList();
270+
final month = parts[0];
271+
final year = parts[1];
272+
273+
final now = DateTime.now();
274+
final currentYear = now.year % 100;
275+
final currentMonth = now.month;
276+
277+
if (year < currentYear) {
278+
return false;
279+
}
280+
281+
if (year == currentYear && month < currentMonth) {
282+
return false;
283+
}
284+
285+
return true;
286+
}

0 commit comments

Comments
 (0)