Skip to content

Instantly share code, notes, and snippets.

@winni4eva
Created August 8, 2019 10:20
Show Gist options
  • Save winni4eva/175e771e5f4afeffed619b178c88f174 to your computer and use it in GitHub Desktop.
Save winni4eva/175e771e5f4afeffed619b178c88f174 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport"
content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Mini App</title>
<style>
body {
margin: 0;
padding: 1em;
background: white;
}
[data-cart-info],
[data-credit-card] {
transform: scale(0.78);
margin-left: -3.4em;
}
[data-cc-info] input:focus,
[data-cc-digits] input:focus {
outline: none;
}
.mdc-card__primary-action,
.mdc-card__primary-action:hover {
cursor: auto;
padding: 20px;
min-height: inherit;
}
[data-credit-card] [data-card-type] {
transition: width 1.5s;
margin-left: calc(100% - 130px);
}
[data-credit-card].is-visa {
background: linear-gradient(135deg, #622774 0%, #c53364 100%);
}
[data-credit-card].is-mastercard {
background: linear-gradient(135deg, #65799b 0%, #5e2563 100%);
}
.is-visa [data-card-type],
.is-mastercard [data-card-type] {
width: auto;
}
input.is-invalid,
.is-invalid input {
text-decoration: line-through;
}
::placeholder {
color: #fff;
}
/* Add Your CSS From Here */
div[data-cart-info] span {
display: inline-block;
vertical-align: middle;
}
div[data-cart-info] h3 span.material-icons {
font-size: 150px;
}
div[data-credit-card] {
width: 435px;
min-height: 240px;
border-radius: 10px;
background-color: #5d6874;
}
img[data-card-type] {
display: block;
width: 120px;
height: 60px;
}
div[data-cc-digits] {
margin-top: 2em;
}
div[data-cc-digits] input {
color: white;
font-size: 2em;
line-height: 2em;
border: none;
background: transparent;
margin-right: 0.5em;
}
div[data-cc-info] {
margin-top: 1em;
}
div[data-cc-info] input {
color: white;
font-size: 1.2em;
border: none;
background: none;
}
div[data-cc-info] input:nth-child(2) {
padding-right: 10px;
float: right;
}
button[data-pay-btn] {
position: fixed;
width: 90%;
border: 1px solid;
bottom: 20px;
}
</style>
</head>
<body>
<!-- your HTML goes here -->
<div data-cart-info>
<h3 class="mdc-typography--headline4">
<span class="material-icons">
shopping_cart
</span>
<span data-bill></span>
</h3>
</div>
<div data-credit-card class="mdc-card mdc-card--outlined">
<div class="mdc-card__primary-action">
<img data-card-type src="https://placehold.it/120x60.png?text=card">
<div data-cc-digits>
<input type="text" size="4" placeholder="----">
<input type="text" size="4" placeholder="----">
<input type="text" size="4" placeholder="----">
<input type="text" size="4" placeholder="----">
</div>
<div data-cc-info>
<input type="text" size="20" placeholder="Name Surname">
<input type="text" size="6" placeholder="MM/YY">
</div>
</div>
</div>
<button class="mdc-button" data-pay-btn>Pay Now</button>
<script>
const supportedCards = {
visa, mastercard
};
const countries = [
{
code: "US",
currency: "USD",
currencyName: '',
country: 'United States'
},
{
code: "NG",
currency: "NGN",
currencyName: '',
country: 'Nigeria'
},
{
code: 'KE',
currency: 'KES',
currencyName: '',
country: 'Kenya'
},
{
code: 'UG',
currency: 'UGX',
currencyName: '',
country: 'Uganda'
},
{
code: 'RW',
currency: 'RWF',
currencyName: '',
country: 'Rwanda'
},
{
code: 'TZ',
currency: 'TZS',
currencyName: '',
country: 'Tanzania'
},
{
code: 'ZA',
currency: 'ZAR',
currencyName: '',
country: 'South Africa'
},
{
code: 'CM',
currency: 'XAF',
currencyName: '',
country: 'Cameroon'
},
{
code: 'GH',
currency: 'GHS',
currencyName: '',
country: 'Ghana'
}
];
const billHype = () => {
const billDisplay = document.querySelector('.mdc-typography--headline4');
if (!billDisplay) return;
billDisplay.addEventListener('click', () => {
const billSpan = document.querySelector("[data-bill]");
if (billSpan &&
appState.bill &&
appState.billFormatted &&
appState.billFormatted === billSpan.textContent) {
window.speechSynthesis.speak(
new SpeechSynthesisUtterance(appState.billFormatted)
);
}
});
};
const appState = {};
const formatAsMoney = (amount, buyerCountry) => {
const selectedCountry = countries.filter(country => {
return country.country === buyerCountry;
});
const selectedCountryCode = selectedCountry[0].code || countries[0].code;
const selectedCountryCurrency = selectedCountry[0].currency || countries[0].currency;
return amount.toLocaleString(
`en-${selectedCountryCode}`,
{style:"currency", currency: selectedCountryCurrency}
);
};
const flagIfInvalid = (field, isValid) => {
if (isValid)
field.classList.remove("is-invalid");
field.classList.add("is-invalid");
}
const expiryDateFormatIsValid = (field) => {
const regEx = new RegExp(/^(0?[1-9]|1[012])[//]\d{2}$/);
return regEx.test(field);
}
const detectCardType = first4Digits => {};
const validateCardExpiryDate = () => {
const dateInput = document.querySelector("div[data-cc-info] input:nth-child(2)");
if (expiryDateFormatIsValid(dateInput.value)) {
const dateArr = dateInput.value.split("/"),
cardMonth = dateArr[0],
cardYear = `20${dateArr[1]}`,
expiry = new Date(`${cardYear}-${cardMonth}-01`);
if(expiry > new Date()) {
flagIfInvalid(dateInput, true);
return true;
}
}
flagIfInvalid(dateInput, false);
return false;
};
const validateCardHolderName = () => {
const cardNameInput = document.querySelector('div[data-cc-info] input:nth-child(1)');
const names = cardNameInput.value.split(" ");
if (names.length !== 2 || names[0].length < 3 || names[1].length < 3) {
flagIfInvalid(cardNameInput, false);
return false;
}
flagIfInvalid(cardNameInput, true);
return true;
};
const validateCardNumber = () => {};
const validatePayment = () => {
validateCardNumber();
validateCardHolderName();
validateCardExpiryDate();
};
const acceptCardNumbers = (event, fieldIndex) => {};
const smartInput = (event, fieldIndex, fields) => {
const allowedkeysCodes = [9,8,16,46,37,38,39,40];
if((fieldIndex >= 0 && fieldIndex < 4) || fieldIndex === 5) {
if(~allowedkeysCodes.indexOf(event.keyCode) || !isNaN(event.key)) {
if(fieldIndex !== 5 && fields[fieldIndex].value.length === 4) {
console.log(fields[fieldIndex++]);
fields[fieldIndex++].focus();
}
return true;
}
event.preventDefault();
return false;
}
if(fieldIndex === 4) {
if(~allowedkeysCodes.indexOf(event.keyCode) || isNaN(event.key)) {
return true;
}
event.preventDefault();
return false;
}
};
const smartCursor = (event, fieldIndex, fields) => {
//
};
const enableSmartTyping = () => {
const fields = document.querySelectorAll("input");
[].forEach.call(fields, (field, index) => {
//field.addEventListener("keyup", (event) => {
//smartInput(event, index, fields);
//});
field.addEventListener("keydown", (event) => {
return smartInput(event, index, fields);
});
});
};
const uiCanInteract = () => {
document.querySelector("div[data-cc-digits] input:nth-child(1)").focus();
document.querySelector("button[data-pay-btn]").addEventListener("click", validatePayment);
billHype();
enableSmartTyping();
};
const displayCartTotal = ({results}) => {
const [data] = results;
const {itemsInCart, buyerCountry} = data;
appState.items = itemsInCart;
appState.country = buyerCountry;
const initialValue = 0;
appState.bill = itemsInCart.reduce(
(totalPrice, cartItem) => {
return totalPrice + (cartItem.price * cartItem.qty)
},
initialValue
);
appState.billFormatted = formatAsMoney(appState.bill, appState.country);
document.querySelector("[data-bill]").textContent = appState.billFormatted;
appState.cardDigits = [];
uiCanInteract();
};
const fetchBill = () => {
const apiHost = 'https://randomapi.com/api';
const apiKey = '006b08a801d82d0c9824dcfdfdfa3b3c';
const apiEndpoint = `${apiHost}/${apiKey}`;
fetch(apiEndpoint)
.then(response => response.json())
.then(displayCartTotal)
.catch(error => console.warn(error));
};
const startApp = () => {
fetchBill();
};
startApp();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment