UNPKG

ng-payment-card

Version:

Customizable component with zero external dependencies.

2 lines 20.1 kB
!function(r,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("@angular/core"),require("@angular/forms"),require("@angular/common")):"function"==typeof define&&define.amd?define("ng-payment-card",["exports","@angular/core","@angular/forms","@angular/common"],e):e(r["ng-payment-card"]={},r.ng.core,r.ng.forms,r.ng.common)}(this,function(r,t,e,n){"use strict";var o=function(){function c(){}return c.numbersOnly=function(r){var e=r.value;return new RegExp(/^[0-9]+$/).test(e)?null:c.NUMBERS_ONLY_ERR},c.checksum=function(r){for(var e=r.value,t=[0,2,4,6,8,1,3,5,7,9],n=e?e.length:0,o=0,a=!0;n;){var i=parseInt(e.charAt(--n),10);o+=(a=!a)?t[i]:i}return o&&o%10==0?null:c.CHECKSUM_INVALID},c.expiration=function(r){var e=Number(r.get("expirationMonth").value),t=Number(r.get("expirationYear").value),n=new Date(t,e+1,0);return(new Date).getTime()>n.getTime()?c.CARD_EXPIRED:null},c.NUMBERS_ONLY_ERR={numbersOnly:!0},c.CHECKSUM_INVALID={checksum:!0},c.CARD_EXPIRED={expiration:!0},c}();function d(r){var e="function"==typeof Symbol&&r[Symbol.iterator],t=0;return e?e.call(r):{next:function(){return r&&t>=r.length&&(r=void 0),{value:r&&r[t++],done:!r}}}}function m(r,e){var t="function"==typeof Symbol&&r[Symbol.iterator];if(!t)return r;var n,o,a=t.call(r),i=[];try{for(;(void 0===e||0<e--)&&!(n=a.next()).done;)i.push(n.value)}catch(c){o={error:c}}finally{try{n&&!n.done&&(t=a["return"])&&t.call(a)}finally{if(o)throw o.error}}return i}var a="American Express",i="Diners",c="Diners Carte Blanche",s="Discover Club",l="China UnionPay",p="JCB",u="Laser",f="Maestro",g="Mastercard",h="Visa Electron",b="VISA",x=new Map;x.set(a,new RegExp("^3[47]")),x.set(i,new RegExp("^36")),x.set(c,new RegExp("^30[0-5]")),x.set(s,new RegExp("^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)")),x.set(l,new RegExp("^(62[0-9]{14,17})$")),x.set(p,new RegExp("^35(2[89]|[3-8][0-9])")),x.set(u,new RegExp("^(6304|6706|6709|6771)[0-9]{12,15}$")),x.set(f,new RegExp("^(50|5[6-8]|6)[0-9]{12,19}$")),x.set(g,new RegExp("^(5[1-5][0-9]{14}|2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12}))$")),x.set(h,new RegExp("^(4026|417500|4508|4844|491([37]))")),x.set(b,new RegExp("^4"));var _={JANUARY:"01",FEBRUARY:"02",MARCH:"03",APRIL:"04",MAY:"05",JUNE:"06",JULY:"07",AUGUST:"08",SEPTEMBER:"09",OCTOBER:"10",NOVEMBER:"11",DECEMBER:"12"},v=function(){function l(){}return l.getCardType=function(r){var e,t;try{for(var n=d(Array.from(l.cardTypes.entries())),o=n.next();!o.done;o=n.next()){var a=m(o.value,2),i=a[0],c=a[1];if(r.split(new RegExp("[ \\-]")).join("").match(c))return i}}catch(s){e={error:s}}finally{try{o&&!o.done&&(t=n["return"])&&t.call(n)}finally{if(e)throw e.error}}return null},l.getMonths=function(){var r,e,t=[];try{for(var n=d(Object.keys(_)),o=n.next();!o.done;o=n.next()){var a=o.value;t.push(_[a])}}catch(i){r={error:i}}finally{try{o&&!o.done&&(e=n["return"])&&e.call(n)}finally{if(r)throw r.error}}return t},l.getYears=function(){for(var r=[],e=(new Date).getFullYear(),t=-2;t<5;t++)r.push(e+t);return r},l.cardTypes=x,l.decorators=[{type:t.Injectable}],l}(),y=function(){function r(r,e){this._ccService=r,this._fb=e,this.months=[],this.years=[],this.ccNumMissingTxt="Card number is required",this.ccNumTooShortTxt="Card number is too short",this.ccNumTooLongTxt="Card number is too long",this.ccNumContainsLettersTxt="Card number can contain digits only",this.ccNumChecksumInvalidTxt="Provided card number is invalid",this.cardHolderMissingTxt="Card holder name is required",this.cardHolderTooLongTxt="Card holder name is too long",this.expirationMonthMissingTxt="Expiration month is required",this.expirationYearMissingTxt="Expiration year is required",this.ccvMissingTxt="CCV number is required",this.ccvNumTooShortTxt="CCV number is too short",this.ccvNumTooLongTxt="CCV number is too long",this.ccvContainsLettersTxt="CCV number can contain digits only",this.cardExpiredTxt="Card has expired",this.validateCCNum=!0,this.validateCardHolder=!0,this.validateExpirationMonth=!0,this.validateExpirationYear=!0,this.validateCardExpiration=!0,this.validateCCV=!0,this.formSaved=new t.EventEmitter}return r.prototype.ngOnInit=function(){this.buildForm(),this.assignDateValues()},r.prototype.assignDateValues=function(){this.months=v.getMonths(),this.years=v.getYears()},r.prototype.buildForm=function(){this.ccForm=this._fb.group({cardNumber:["",e.Validators.compose([e.Validators.required,e.Validators.minLength(12),e.Validators.maxLength(19),o.numbersOnly,o.checksum])],cardHolder:["",e.Validators.compose([e.Validators.required,e.Validators.maxLength(22)])],expirationMonth:["",e.Validators.required],expirationYear:["",e.Validators.required],ccv:["",e.Validators.compose([e.Validators.required,e.Validators.minLength(3),e.Validators.maxLength(4),o.numbersOnly])]},{validator:o.expiration})},r.prototype.getCardType=function(r){return v.getCardType(r)},r.prototype.emitSavedCard=function(){var r=this.ccForm.value;this.formSaved.emit(r)},r.decorators=[{type:t.Component,args:[{selector:"ng-payment-card",template:'<section class="cc-wrapper">\r\n <div class="cc-box">\r\n <div #ccBoxFlip class="cc-box--flip">\r\n <div class="cc-box__front">\r\n <div class="cc-box__logo">\r\n <p>{{getCardType(ccNumber.value) | uppercase}}</p>\r\n </div>\r\n <div class="cc-box__element">\r\n <label class="cc-form__label" for="cc-card-number-display"></label>\r\n <input class="cc-form__input cc-form__input--transparent cc-form__input--embosed" id="cc-card-number-display"\r\n aria-label="Payment card number" disabled="disabled"\r\n [value]="ccForm.get(\'cardNumber\').value | paymentCardNumber">\r\n </div>\r\n <div class="cc-box__element">\r\n <label class="cc-form__label" for="cc-holder-display">CARD HOLDER</label>\r\n <input class="cc-form__input cc-form__input--transparent cc-form__input--embosed" id="cc-holder-display"\r\n aria-label="Card holder" disabled="disabled" [value]="ccForm.get(\'cardHolder\').value | uppercase">\r\n </div>\r\n <div class="cc-box__element">\r\n <label class="cc-form__label" for="cc-valid-date-display">VALID THRU</label>\r\n <input class="cc-form__input cc-form__input--left-align cc-form__input--transparent cc-form__input--embosed"\r\n id="cc-valid-date-display" aria-label="Card holder" disabled="disabled"\r\n [value]="ccForm.get(\'expirationMonth\').value + \'/\' + ccForm.get(\'expirationYear\').value | validThru">\r\n </div>\r\n <div class="cc-box__chip"></div>\r\n </div>\r\n <div class="cc-box__back">\r\n <div class="cc-box__strip">&nbsp;</div>\r\n <div class="cc-box__element">\r\n <input class="cc-form__input cc-form__input--cursive cc-form__input--right-align" id="cc-ccv-display"\r\n aria-label="CCV" disabled="disabled"\r\n [value]="\'CCV: \' + ccForm.get(\'ccv\').value" title="CCV">\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <form class="cc-form" [formGroup]="ccForm" autocomplete="off">\r\n <div class="cc-form__wrapper--long">\r\n <label for="cc-number" class="cc-form__label cc-form__label--first">Card number</label>\r\n <input #ccNumber class="cc-form__input" id="cc-number" aria-label="Card number"\r\n type="text" title="Card number" maxlength="19" formControlName="cardNumber"\r\n (focus)="ccBoxFlip.classList.remove(\'hover\')">\r\n <div class="cc-form__error"\r\n *ngIf="validateCCNum && ccForm.get(\'cardNumber\').touched && ccForm.get(\'cardNumber\').hasError(\'required\')">\r\n {{ccNumMissingTxt}}\r\n </div>\r\n <div class="cc-form__error"\r\n *ngIf="validateCCNum && ccForm.get(\'cardNumber\').touched && ccForm.get(\'cardNumber\').hasError(\'minlength\')">\r\n {{ccNumTooShortTxt}}\r\n </div>\r\n <div class="cc-form__error"\r\n *ngIf="validateCCNum && ccForm.get(\'cardNumber\').touched && ccForm.get(\'cardNumber\').hasError(\'maxlength\')">\r\n {{ccNumTooLongTxt}}\r\n </div>\r\n <div class="cc-form__error"\r\n *ngIf="validateCCNum && ccForm.get(\'cardNumber\').touched && ccForm.get(\'cardNumber\').hasError(\'numbersOnly\')">\r\n {{ccNumContainsLettersTxt}}\r\n </div>\r\n <div class="cc-form__error"\r\n *ngIf="validateCCNum && ccForm.get(\'cardNumber\').touched && ccForm.get(\'cardNumber\').hasError(\'checksum\')">\r\n {{ccNumChecksumInvalidTxt}}\r\n </div>\r\n </div>\r\n <div class="cc-form__wrapper--long">\r\n <label for="cc-holder-name" class="cc-form__label">Card Holder name</label>\r\n <input class="cc-form__input" id="cc-holder-name" aria-label="Card holder name" type="text"\r\n title="Card holder name" maxlength="22" formControlName="cardHolder"\r\n (focus)="ccBoxFlip.classList.remove(\'hover\')">\r\n <div class="cc-form__error"\r\n *ngIf="validateCardHolder && ccForm.get(\'cardHolder\').touched &&\r\n ccForm.get(\'cardHolder\').hasError(\'required\')">\r\n {{cardHolderMissingTxt}}\r\n </div>\r\n <div class="cc-form__error"\r\n *ngIf="validateCardHolder && ccForm.get(\'cardHolder\').touched &&\r\n ccForm.get(\'cardHolder\').hasError(\'maxlength\')">\r\n {{cardHolderTooLongTxt}}\r\n </div>\r\n </div>\r\n <div class="cc-form--inline">\r\n <div class="cc-form__wrapper cc-form__wrapper--short">\r\n <label for="cc-expiration-month" class="cc-form__label">Expiration month</label>\r\n <select id="cc-expiration-month" class="cc-form__select" aria-label="Expiration month"\r\n formControlName="expirationMonth">\r\n <option *ngFor="let month of months" value="{{month}}"\r\n (click)="ccBoxFlip.classList.remove(\'hover\')">{{month}}\r\n </option>\r\n </select>\r\n </div>\r\n <div class="cc-form__wrapper cc-form__wrapper--short">\r\n <label for="cc-expiration-year" class="cc-form__label">Expiration year</label>\r\n <select id="cc-expiration-year" class="cc-form__select" aria-label="Expiration year"\r\n formControlName="expirationYear">\r\n <option *ngFor="let year of years" value="{{year}}"\r\n (click)="ccBoxFlip.classList.remove(\'hover\')">{{year}}\r\n </option>\r\n </select>\r\n </div>\r\n <div class="cc-form__wrapper cc-form__wrapper--short cc-form__wrapper--last">\r\n <label for="cc-ccv" class="cc-form__label">ccv</label>\r\n <input class="cc-form__input cc-form__input--short" id="cc-ccv" aria-label="CCV" type="text" title="CCV"\r\n minlength="3" maxlength="4" formControlName="ccv" (focus)="ccBoxFlip.classList.add(\'hover\')">\r\n </div>\r\n </div>\r\n <div class="cc-form__error"\r\n *ngIf="validateExpirationMonth && ccForm.get(\'expirationMonth\').touched &&\r\n ccForm.get(\'expirationMonth\').hasError(\'required\')">\r\n {{expirationMonthMissingTxt}}\r\n </div>\r\n <div class="cc-form__error"\r\n *ngIf="validateExpirationMonth && ccForm.get(\'expirationYear\').touched &&\r\n ccForm.get(\'expirationYear\').hasError(\'required\')">\r\n {{expirationYearMissingTxt}}\r\n </div>\r\n <div class="cc-form__error" *ngIf="validateCardExpiration && ccForm.get(\'expirationMonth\').touched &&\r\n ccForm.get(\'expirationYear\').touched && ccForm.hasError(\'expiration\')">\r\n {{cardExpiredTxt}}\r\n </div>\r\n <div class="cc-form__error"\r\n *ngIf="validateCCV && ccForm.get(\'ccv\').touched && ccForm.get(\'ccv\').hasError(\'required\')">\r\n {{ccvMissingTxt}}\r\n </div>\r\n <div class="cc-form__error"\r\n *ngIf="validateCCV && ccForm.get(\'ccv\').touched && ccForm.get(\'ccv\').hasError(\'minlength\')">\r\n {{ccvNumTooShortTxt}}\r\n </div>\r\n <div class="cc-form__error"\r\n *ngIf="validateCCV && ccForm.get(\'ccv\').touched && ccForm.get(\'ccv\').hasError(\'maxlength\')">\r\n {{ccvNumTooLongTxt}}\r\n </div>\r\n <div class="cc-form__error"\r\n *ngIf="validateCCV && ccForm.get(\'ccv\').touched && ccForm.get(\'ccv\').hasError(\'numbersOnly\')">\r\n {{ccvContainsLettersTxt}}\r\n </div>\r\n <button type="submit" class="cc-form__button cc-form__button--ripple" aria-label="submit" (click)="emitSavedCard()"\r\n (keydown.enter)="emitSavedCard()">Submit\r\n </button>\r\n </form>\r\n</section>\r\n',encapsulation:t.ViewEncapsulation.None,styles:["@import url(https://fonts.googleapis.com/css?family=Inconsolata);.cc-form{align-items:center;display:flex;flex-flow:column;flex-wrap:wrap;height:100%;justify-content:center;width:100%}.cc-form--inline{align-items:inherit;display:inherit;flex-flow:row;flex-wrap:inherit;height:100%;justify-content:flex-end;margin-bottom:5%;width:100%}@media only screen and (max-width:1279px){.cc-form--inline{align-items:inherit;display:inherit;flex-flow:row;flex-wrap:inherit;height:100%;justify-content:flex-end;margin-bottom:5%;width:100%}}@media only screen and (max-width:599px){.cc-form--inline{align-items:center;display:inherit;flex-flow:column;flex-wrap:wrap;height:100%;justify-content:center;width:100%}}input[type=number]{-moz-appearance:textfield}input::-webkit-inner-spin-button,input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}@media only screen and (max-width:1919px){.cc-form__wrapper{margin-right:5%;margin-top:5%}.cc-form__wrapper--long{width:60%}.cc-form__wrapper--short{width:15%}.cc-form__wrapper--last{margin-left:5%;margin-right:20%;margin-top:30px}}@media only screen and (max-width:1279px){.cc-form__wrapper{margin-right:5%;margin-top:5%}.cc-form__wrapper--long{width:60%}.cc-form__wrapper--short{width:15%}.cc-form__wrapper--last{margin-left:5%;margin-right:20%}}@media only screen and (max-width:599px){.cc-form__wrapper{margin-right:0;margin-top:0}.cc-form__wrapper--long,.cc-form__wrapper--short{width:80%}.cc-form__wrapper--last{margin-left:0;margin-right:0}}.cc-form__label{color:rgba(0,0,0,.6);display:block;font-family:Inconsolata,Serif,serif;font-size:.7em;font-weight:400;letter-spacing:1px;line-height:10px;margin-bottom:5px;margin-top:5%;text-align:left;text-shadow:none;text-transform:uppercase;width:100%}.cc-form__label--first{margin-top:20%}.cc-form__select{-webkit-appearance:listbox;-moz-appearance:listbox;appearance:listbox}.cc-form__input,.cc-form__select{border:1px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:inset 0 1px 4px rgba(0,0,0,.2);color:#333;display:block;font-size:1.2em;height:38px;margin:0;outline:0;padding:0;text-align:left;width:100%}.cc-form__input--transparent{background:0 0;border:none;border-radius:0;box-shadow:none}.cc-form__input--embosed{color:#fff;font-family:Inconsolata,monospace;font-size:2vw;text-shadow:0 2px 1px rgba(0,0,0,.3)}@media only screen and (max-width:1279px){.cc-form__input--embosed{font-size:2.5vw}}@media only screen and (max-width:599px){.cc-form__input--embosed{font-size:3vw}}.cc-form__input--cursive{font-size:.7em;font-style:italic;left:0;margin:0 auto;position:absolute}.cc-form__input--right-align{padding-right:5%;text-align:right}.cc-form__input--left-align{text-align:left}.cc-form__input:focus,.cc-form__select:focus{border-color:#41acf4}.cc-form__error{color:#ff5b5f;font-size:.7em}.cc-form__button{background:#41acf4;border:0;border-radius:3px;color:#fff;cursor:pointer;margin-bottom:5%;margin-top:1%;outline:0;overflow:hidden;padding:1%;position:relative;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle;white-space:nowrap;width:60%}.cc-form__button:hover{box-shadow:0 6px 8px -3px rgba(0,0,0,.3)}.cc-form__button:focus{background:#0e91ea}.cc-form__button--ripple{overflow:hidden;position:relative}.cc-form__button--ripple:after{background:rgba(255,255,255,.3);border-radius:80%;content:'';display:block;height:120px;left:50%;margin-left:-50%;margin-top:-60px;position:absolute;top:50%;-webkit-transform:scale(0);transform:scale(0);width:100%}.cc-form__button--ripple:not(:active):after{-webkit-animation:2s ease-out button-ripple;animation:2s ease-out button-ripple}@-webkit-keyframes button-ripple{0%{-webkit-transform:scale(0);transform:scale(0)}20%{-webkit-transform:scale(1);transform:scale(1)}100%{opacity:0;-webkit-transform:scale(1);transform:scale(1)}}@keyframes button-ripple{0%{-webkit-transform:scale(0);transform:scale(0)}20%{-webkit-transform:scale(1);transform:scale(1)}100%{opacity:0;-webkit-transform:scale(1);transform:scale(1)}}.cc-wrapper{background-color:#fff;border-radius:20px;height:100%;margin:0;padding:0;width:100%}.cc-box{height:100px;margin:0 auto;padding:0;position:relative;-webkit-transform:translateY(-100%);transform:translateY(-100%);width:70%;z-index:1}@media only screen and (max-width:1279px){.cc-box{-webkit-transform:translateY(-115%);transform:translateY(-115%)}}@media only screen and (max-width:599px){.cc-box{-webkit-transform:translateY(-130%);transform:translateY(-130%)}}.cc-box--flip{-webkit-transform-style:preserve-3d;transform-style:preserve-3d;transition:.6s}.cc-box--flip.hover,.cc-box--flip:hover{-webkit-transform:rotateY(180deg);transform:rotateY(180deg)}.cc-box__element{padding:0;width:80%}.cc-box__logo{align-items:center;color:#fff;display:flex;flex-flow:row nowrap;font-size:1.2em;font-style:italic;font-weight:700;justify-content:flex-end;margin-right:10%;width:100%}.cc-box__strip{background:linear-gradient(135deg,#404040,#1a1a1a);font-size:1.7em;margin:0;padding:0;position:relative;-webkit-transform:translateY(-90%);transform:translateY(-90%);width:100%}.cc-box__back,.cc-box__front{align-items:center;-webkit-backface-visibility:hidden;backface-visibility:hidden;background:linear-gradient(135deg,#bd6772,#53223f);border-radius:15px;display:flex;flex-direction:column;flex-flow:column nowrap;height:250px;justify-content:center;left:0;position:absolute;top:0;width:100%}.cc-box__front{-webkit-transform:rotateY(0);transform:rotateY(0)}.cc-box__back{-webkit-transform:rotateY(180deg);transform:rotateY(180deg)}.ng-invalid.ng-touched{border-color:#ff5b5f}.ng-valid.ng-touched{border-color:#b2b2b2}"]}]}],r.ctorParameters=function(){return[{type:v},{type:e.FormBuilder}]},r.propDecorators={ccNumMissingTxt:[{type:t.Input}],ccNumTooShortTxt:[{type:t.Input}],ccNumTooLongTxt:[{type:t.Input}],ccNumContainsLettersTxt:[{type:t.Input}],ccNumChecksumInvalidTxt:[{type:t.Input}],cardHolderMissingTxt:[{type:t.Input}],cardHolderTooLongTxt:[{type:t.Input}],expirationMonthMissingTxt:[{type:t.Input}],expirationYearMissingTxt:[{type:t.Input}],ccvMissingTxt:[{type:t.Input}],ccvNumTooShortTxt:[{type:t.Input}],ccvNumTooLongTxt:[{type:t.Input}],ccvContainsLettersTxt:[{type:t.Input}],cardExpiredTxt:[{type:t.Input}],validateCCNum:[{type:t.Input}],validateCardHolder:[{type:t.Input}],validateExpirationMonth:[{type:t.Input}],validateExpirationYear:[{type:t.Input}],validateCardExpiration:[{type:t.Input}],validateCCV:[{type:t.Input}],formSaved:[{type:t.Output}]},r}(),w=function(){function r(){}return r.prototype.transform=function(r){switch(r.length){case 15:return r=(r=r.replace(/\b(\d{4})/,"$1-")).replace(/-(\d{6})/,"-$1-");case 16:return r.match(/.{4}/g).join("-");default:return r}},r.decorators=[{type:t.Pipe,args:[{name:"paymentCardNumber"}]}],r}(),C=function(){function r(){}return r.prototype.transform=function(r){return r&&7===r.length?r.substr(0,3)+r.substr(5):"/"},r.decorators=[{type:t.Pipe,args:[{name:"validThru"}]}],r}(),E=function(){function r(){}return r.decorators=[{type:t.NgModule,args:[{imports:[e.ReactiveFormsModule,n.CommonModule],declarations:[y,w,C],providers:[v],exports:[y]}]}],r}();r.PaymentCardComponent=y,r.NgPaymentCardModule=E,r.ɵb=w,r.ɵc=C,r.ɵa=v,Object.defineProperty(r,"__esModule",{value:!0})}); //# sourceMappingURL=ng-payment-card.umd.min.js.map