How to build a PIN code widget in a mini app

Views:376

In this case study, Saifulla Khusikhanov explains how to build a PIN code widget in a mini app using puzzlebot.
This widget lets users enter a PIN code to access certain app features, which improves data protection and makes interacting with your bot more secure.

Why do you need a PIN code widget?

A PIN code in a mini app can be useful in the following scenarios: - Protecting user data. A PIN code adds an extra layer of security and lets users control access to their data. - Restricting access to specialized features of your bot. For example, you can create content that's available only to users who have entered the correct PIN code. - Raising awareness of security and privacy. Having a PIN code helps users realize how important data security is.

Let's walk through the HTML, CSS and JavaScript code that implements the PIN code input widget.

I'll explain the main attributes used and point out which part validates the PIN code input.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PIN code widget</title>
<style>
/* CSS styles for the widget */
</style>
</head>
<body>
<div class="pin-widget">
<div class="pin-input">
<div class="circle" id="circle1"></div>
<div class="circle" id="circle2"></div>
<div class="circle" id="circle3"></div>
<div class="circle" id="circle4"></div>
</div>
<input type="tel" id="pin" maxlength="4" style="opacity: 0; position: absolute;" autofocus />
<a id="continueLink" goto_web_page="86d9caeba79a216b" style="display: none;">Go to the next page</a>
<button id="continueBtn" disabled>ㅤ</button>
</div>

<script>
// JavaScript for handling PIN code input
</script>
</body>
</html>

Attributes and elements explained

  • Indicates that the document is HTML5.

  • The main container for the PIN code widget.

  • The container that displays the entered PIN code.

  • Circles representing the entered PIN code digits.

  • Each circle has a unique id.

  • A hidden text field for entering the PIN code.

A link to the next page, hidden from the user. goto_web_page: a custom attribute that stores the ID of the page to go to.

PIN code validation

The PIN code input is validated in JavaScript:

const pinInput = document.getElementById('pin');
const circles = [
document.getElementById('circle1'),
document.getElementById('circle2'),
document.getElementById('circle3'),
document.getElementById('circle4')
];
const continueBtn = document.getElementById('continueBtn');
const continueLink = document.getElementById('continueLink');
const correctPin = '{{pin}}'; // Set the correct PIN code here

pinInput.addEventListener('input', () => {
const value = pinInput.value;
for (let i = 0; i < circles.length; i++) {
circles[i].textContent = i < value.length ? '●' : '';
}

if (value.length === 4) {
if (value === correctPin) {
continueBtn.disabled = false;
continueLink.click(); // Automatic redirect
} else {
alert('Incorrect PIN code. Please try again.');
pinInput.value = '';
circles.forEach(circle => circle.textContent = '');
}
}
});

  • pinInput.addEventListener('input', ...): Adds an event handler that fires when data is entered in the field.

  • const value = pinInput.value;: Gets the current value entered by the user.

  • circles[i].textContent = i < value.length ? '●' : '';: Updates the circles depending on the characters entered.

  • if (value.length === 4): Checks whether all 4 characters have been entered.

  • if (value === correctPin): Compares the entered PIN code with the correct value.

  • continueBtn.disabled = false;: If the PIN code is correct, the user is automatically redirected to the next page.

  • alert('Incorrect PIN code. Please try again.');: If the PIN code is incorrect, an error message is shown in a popup.

alert('Неверный PIN-код. Попробуйте еще раз.');

alert('Incorrect PIN code. Please try again.')

In short, the code creates an interactive PIN code input widget with visual feedback and input validation

Widget code:

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PIN code widget</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f7f7f7;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Rob "Helvetica Neue", Arial, sans-serif;
}

.pin-widget {
display: flex;
flex-direction: column;
align-items: center;
background: #f3f2f8;
padding: 20px;
border-radius: 10px;
}

.pin-input {
display: flex;
justify-content: space-between;
width: 110px;
margin-bottom: 20px;
}

.circle {
width: 15px;
height: 15px;
border: 1px solid #000000;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
background-color: #f3f2f8;
}

/* Removing the button styles */
/* button {
padding: 10px 110px;
background-color: #f3f2f8;
color: white;
border: none;
border-radius: 9px;
cursor: pointer;
font-size: 16px;
}

button:disabled {
background-color: #f3f2f8;
} */
</style>
</head>
<body>
<div class="pin-widget">
<div class="pin-input">
<div class="circle" id="circle1"></div>
<div class="circle" id="circle2"></div>
<div class="circle" id="circle3"></div>
<div class="circle" id="circle4"></div>
</div>
<input type="tel" id="pin" maxlength="4" style="opacity: 0; position: absolute;" autofocus />
<a id="continueLink" goto_web_page="86d9caeba79a216b" style="display: none;">Go to the next page</a>
<!-- You can add a button if you like -->
<!-- <button id="continueBtn" disabled>ㅤ</button> -->
</div>

<script>
const pinInput = document.getElementById('pin');
const circles = [
document.getElementById('circle1'),
document.getElementById('circle2'),
document.getElementById('circle3'),
document.getElementById('circle4')
];

// const continueBtn = document.getElementById('continueBtn');
const continueLink = document.getElementById('continueLink');
const correctPin = '{{pin}}'; // Set the correct PIN code here

pinInput.addEventListener('input', () => {
const value = pinInput.value;
for (let i = 0; i < circles.length; i++) {
circles[i].textContent = i < value.length ? '●' : '';
}

if (value.length === 4) {
if (value === correctPin) {
// Removing the button check
// continueBtn.disabled = false;
continueLink.click(); // Automatic redirect
} else {
alert('Incorrect PIN code. Please try again.');
pinInput.value = '';
circles.forEach(circle => circle.textContent = '');
}
}
});


// continueBtn.addEventListener('click', () => {
// gotoWebPage(continueLink.getAttribute('goto_web_page'));
// });

function gotoWebPage(id, openInBrowser = false) {
const url = getWebPageUrl(id);
if (openInBrowser) {
window.open(url, '_blank');
} else {
window.location.href = url;
}
}

function getWebPageUrl(id) {
return `https://example.com/${id}`; // Replace with the URL you need
}
</script>
</body>
</html>

Want to ask an expert a question? Leave it in the comments under the latest post in our channel — the most interesting ones will get a detailed breakdown.

Was this page helpful?