Update login.html

Signed-off-by: nestict <icttechnest@gmail.com>
This commit is contained in:
nestict 2025-05-14 16:57:57 +02:00
parent 268cc7f84a
commit 5b3b3a1b4e

View File

@ -3,146 +3,122 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>yatmack</title> <title> HOTSPOT WIFI MBSA</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/3.8.3/core.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link href='https://fonts.googleapis.com/css2?family=Lexend:wght@300;400;500;600;700&display=swap' rel='stylesheet'>
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
tailwind.config = { <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/glider-js@1.7.7/glider.min.css" />
theme: { <script src="https://cdn.jsdelivr.net/npm/glider-js@1.7.7/glider.min.js"></script>
extend: { <link rel="preconnect" href="https://cdn.jsdelivr.net">
colors: { <link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin>
navy: { <link rel="stylesheet" href="https://rsms.me/inter/inter.css">
DEFAULT: '#023047', <!-- <link rel="stylesheet" type="text/css" href="styles.css"> -->
50: '#e6f0f5',
100: '#cce1eb',
200: '#99c3d7',
300: '#66a5c3',
400: '#3387af',
500: '#023047',
600: '#022640',
700: '#011d39',
800: '#011332',
900: '#010a2b'
},
orange: {
DEFAULT: '#fb8500',
50: '#fff4e6',
100: '#ffe9cc',
200: '#ffd399',
300: '#ffbd66',
400: '#ffa733',
500: '#fb8500',
600: '#cc6d00',
700: '#995200',
800: '#663600',
900: '#331b00'
}
},
fontFamily: {
'lexend': ['Lexend', 'sans-serif'],
},
animation: {
'spin-fast': 'spin 0.5s linear infinite',
'fade-in': 'fadeIn 0.3s ease-in-out',
'slide-up': 'slideUp 0.3s ease-out'
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' }
},
slideUp: {
'0%': { transform: 'translateY(10px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' }
}
}
}
}
}
</script>
</head> </head>
<body class="font-lexend min-h-screen bg-gradient-to-b from-navy to-navy/95 text-gray-100"> <body class="font-sans antialiased text-gray-900 bg-gray-900 font-inter">
<div class="container mx-auto px-2 py-4 max-w-3xl"> <!-- Main Content -->
<div class="bg-white/10 backdrop-blur-lg rounded-2xl shadow-xl mb-6 overflow-hidden border border-white/10"> <div class="mx-auto max-w-screen-2xl px-4 md:px-4">
<div class="p-3 relative"> <div class="max-h-34 relative mx-auto mt-4 flex max-w-lg flex-1 shrink-0 items-center justify-center overflow-hidden shadow-lg rounded-lg bg-red-100">
<h1 class="text-2xl font-bold text-center text-orange mb-3">YATMACK HOTSPOT</h1> <!-- overlay - start -->
<p class="text-gray-100/90 text-center text-sm mb-4"> <!-- <div class="absolute inset-0 mix-blend-multiply"></div> -->
Select package ? Enter M-Pesa number ? Complete payment <!-- overlay - end -->
</p> <!-- text start -->
<div class="flex items-center justify-center gap-2 py-2 px-4 bg-white/5 rounded-xl"> <div class="relative flex flex-col items-center p-4 sm:max-w-xl">
<i class="fas fa-headset text-orange"></i> <p class="mb-4 text-center text-2xl font-bold text-gray-800 sm:text-xl md:mb-2 "> HOTSPOT WIFI MBSA HOTSPOT LOGIN </p>
<p class="text-sm font-medium">Support: 254705042522</p> <ol class="text-base text-left text-gray-800 mb-1 list-decimal pl-6">
<li>Click on your preferred package</li>
<li>Enter Mpesa No.</li>
<li>Enter pin</li>
<li>Wait to be connected</li>
</ol>
<p class="mb-4 text-center text-lg font-medium text-gray-700 sm:text-1xl md:mb-1 md:text-xl"> For any enquiries contact : 0700000000</p>
</div> </div>
<!-- text end -->
</div> </div>
</div> </div>
<div class="py-2 sm:py-1 lg:py-1"> <div class="py-2 sm:py-4 lg:py-4">
<div class="mx-auto max-w-screen-2xl px-1 md:px-1"> <div class="mx-auto max-w-screen-2xl px-4 md:px-4">
<div class="mx-auto max-w-lg grid grid-cols-2 sm:grid-cols-2 md:grid-cols-3 gap-4 p-1" id="cards-container"> <div class="mx-auto max-w-lg">
</div> <div class="flex flex-col gap-4">
</div> <button type="button" class="flex items-center justify-center gap-2 rounded-lg bg-red-500 px-8 py-3 text-center text-sm font-semibold text-white outline-none ring-red-300 transition duration-100 hover:bg-red-600 focus-visible:ring active:bg-red-700 md:text-base" onclick="redeemVoucher()">
</div> <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<button onclick="redeemVoucher()" class="w-full bg-orange hover:bg-orange/90 text-white font-medium py-4 px-6 rounded-xl shadow-lg transition duration-200 flex items-center justify-center gap-3 mb-6"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v13m0-13V6a2 2 0 112 2h-2zm0 0V5.5A2.5 2.5 0 109.5 8H12zm-7 4h14M5 12a2 2 0 110-4h14a2 2 0 110 4M5 12v7a2 2 0 002 2h10a2 2 0 002-2v-7"></path>
<i class="fas fa-ticket-alt"></i> </svg>
<span>Redeem Voucher</span> Click here to Redeem Voucher
</button> </button>
<div class="bg-white/10 backdrop-blur-lg rounded-2xl shadow-xl overflow-hidden border border-white/10 mb-6">
<div class="p-6 space-y-8">
<!-- Reconnect with M-Pesa -->
<div class="space-y-4">
<h3 class="text-lg font-semibold text-orange">Reconnect with M-Pesa</h3>
<div class="flex flex-col sm:flex-row gap-3">
<input id="mpesaCodeInput" type="text" placeholder="Enter M-Pesa code (e.g., SCK15SKB4Z)" class="flex-grow px-4 py-3 bg-white/5 border border-white/10 rounded-xl focus:outline-none focus:ring-2 focus:ring-orange/50 text-white placeholder:text-gray-400">
<button id="reconnectBtn" class="bg-orange hover:bg-orange/90 text-white font-medium py-3 px-6 rounded-xl transition duration-200">Reconnect</button>
</div> </div>
</div> </div>
<div class="space-y-4"> </div>
<h3 class="text-lg font-semibold text-orange">Active Package Login</h3> </div>
<form id="loginForm" action="$(link-login-only)" method="post" $(if chap-id)onSubmit="return doLogin()" $(endif)> <div class="py-2 sm:py-4 lg:py-6">
<input type="hidden" name="dst" value="$(link-orig)"> <div class="mx-auto max-w-screen-2xl px-4 md:px-8">
<input type="hidden" name="popup" value="true"> <div class="mx-auto max-w-lg grid grid-cols-2 sm:grid-cols-3 gap-1 p-1" id="cards-container">
<input type="hidden" name="mac" id="mac" value="$(mac)">
<div class="flex flex-col sm:flex-row gap-3">
<input id="usernameInput" name="username" type="text" placeholder="Enter Username (e.g., ACC123456)" class="flex-grow px-4 py-3 bg-white/5 border border-white/10 rounded-xl focus:outline-none focus:ring-2 focus:ring-orange/50 text-white placeholder:text-gray-400">
<button id="submitBtn" type="button" onclick="submitLogin()" class="bg-orange hover:bg-orange/90 text-white font-medium py-3 px-6 rounded-xl transition duration-200">Connect</button>
</div>
<input type="hidden" name="password" value="1234">
</form>
</div> </div>
</div> </div>
</div> </div>
<div class="text-center"> <div class="container mx-auto px-4 mb-2">
<p class="text-sm text-gray-400">&copy; 2025 yatmack. Created by Smartisp</p> <div class="max-w-md mx-auto bg-white rounded-lg overflow-hidden md:max-w-lg">
<div class="p-3">
<h3 class="text-2xl font-semibold text-gray-900 mb-3 text-center">Enter Mpesa code to reconnect</h3>
<div class="mb-6">
<label for="mpesaCodeInput" class="block text-gray-700 text-sm font-bold mb-2">Mpesa Code or Mpesa message:</label>
<input type="text" id="mpesaCodeInput" name="mpesa_code" placeholder="Enter Mpesa Code or Full Mpesa Message" class="w-full rounded-lg border bg-gray-50 px-3 py-2 text-gray-800 outline-none ring-indigo-300 transition duration-100 focus:ring">
<button id="reconnectBtn" class="w-full mt-3 rounded-lg bg-red-500 px-4 py-2 text-white font-semibold hover:bg-red-600 transition duration-100">Reconnect</button>
</div>
</div>
<div class="p-1">
<div class="w-full p-3">
<div class="text-center">
<h3 class="text-2xl text-gray-900">Already Have an Active Package?</h3>
</div>
<form id="loginForm" class="form" name="login" action="$(link-login-only)" method="post" $(if chap-id)onSubmit="return doLogin()" $(endif)>
<input type="hidden" name="dst" value="$(link-orig)" />
<input type="hidden" name="popup" value="true" />
<div class="mb-4">
<label class="block text-gray-700 text-sm font-bold mb-2" for="username">enter username or account number.</label>
<div>
<input id="usernameInput" name="username" type="text" value="" placeholder="eg. ACC123456" class="w-full rounded-lg border bg-gray-50 px-3 py-2 text-gray-800 outline-none ring-indigo-300 transition duration-100 focus:ring" />
<button id="submitBtn" class="w-full mt-3 flex items-center justify-center gap-2 rounded-lg bg-red-500 px-8 py-3 text-center text-sm font-semibold text-white outline-none ring-red-300 transition duration-100 hover:bg-red-600 focus-visible:ring active:bg-red-700 md:text-base" type="button" onclick="submitLogin()">
Connect
</button>
</div>
</div>
<input type="hidden" name="password" value="1234">
</form>
</div>
</div>
</div>
</div> </div>
</div> <div class="mx-auto max-w-screen-2xl px-4 md:px-8">
<div class="mx-auto mb-4 max-w-lg">
<div class="border-t py-4">
<p class="text-xs text-red-700 text-center">&copy; 2025. Powered by <a href="https://www.nestict.africa/" target="_blank">NestICT</a></p> </div>
</div>
</div>
</body>
<script>
</script>
<script> <script>
function fetchData() { function fetchData() {
var domain = 'https://yatmack2.smartisp.co.ke/'; let domain = 'https://mbsa.nestict.net/';
var siteUrl = domain + "/index.php?_route=plugin/hotspot_plan"; let siteUrl = domain + "/index.php?_route=plugin/hotspot_plan";
var routerName = encodeURIComponent("yatmack"); let request = new XMLHttpRequest();
var dataparams = `routername=${routerName}`; const routerName = encodeURIComponent("MBSA-CHAN");
fetch(siteUrl, { const dataparams = `routername=${routerName}`;
method: 'POST', request.open("POST", siteUrl, true);
headers: { request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
'Content-Type': 'application/x-www-form-urlencoded' request.onload = () => {
}, if (request.readyState === XMLHttpRequest.DONE) {
body: dataparams if (request.status === 200) {
}) let fetchedData = JSON.parse(request.responseText);
.then(response => { populateCards(fetchedData);
if (!response.ok) { } else {
throw new Error(`Error ${response.status}: ${response.statusText}`); console.log(`Error ${request.status}: ${request.statusText}`);
}
} }
return response.json(); };
}) request.onerror = () => {
.then(data => { console.error("Network error");
populateCards(data); };
}) request.send(dataparams);
.catch(error => {
console.error('Fetch error:', error);
});
} }
function populateCards(data) { function populateCards(data) {
var cardsContainer = document.getElementById('cards-container'); var cardsContainer = document.getElementById('cards-container');
@ -155,13 +131,13 @@ function populateCards(data) {
var cardDiv = document.createElement('div'); var cardDiv = document.createElement('div');
cardDiv.className = 'bg-white border border-black rounded-lg shadow-md overflow-hidden transition duration-300 hover:shadow-lg flex flex-col items-center justify-between mx-auto mb-4 w-40'; cardDiv.className = 'bg-white border border-black rounded-lg shadow-md overflow-hidden transition duration-300 hover:shadow-lg flex flex-col items-center justify-between mx-auto mb-4 w-40';
cardDiv.innerHTML = ` cardDiv.innerHTML = `
<div class="bg-blue-500 text-white w-full py-1"> <div class="bg-red-500 text-white w-full py-1">
<h2 class="text-sm font-medium uppercase text-center" style="font-size: clamp(0.75rem, 1.5vw, 1rem); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"> <h2 class="text-sm font-medium uppercase text-center" style="font-size: clamp(0.75rem, 1.5vw, 1rem); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
${item.planname} ${item.planname}
</h2> </h2>
</div> </div>
<div class="px-4 py-2 flex-grow"> <div class="px-4 py-2 flex-grow">
<p class="text-2xl font-bold text-blue-600 mb-1"> <p class="text-2xl font-bold text-red-600 mb-1">
<span class="text-lg font-medium text-black">${item.currency}</span> <span class="text-lg font-medium text-black">${item.currency}</span>
${item.price} ${item.price}
</p> </p>
@ -171,7 +147,7 @@ function populateCards(data) {
<hr class="border-black mb-2"> <hr class="border-black mb-2">
</div> </div>
<div class="px-4 py-2 flex-shrink-0"> <div class="px-4 py-2 flex-shrink-0">
<a href="#" class="inline-block bg-gray-900 text-white hover:bg-blue-600 font-semibold py-1 px-4 rounded-lg transition duration-300 text-md" <a href="#" class="inline-block bg-gray-900 text-white hover:bg-red-600 font-semibold py-1 px-4 rounded-lg transition duration-300 text-md"
onclick="handlePhoneNumberSubmission('${item.planId}', '${item.routerId}'); return false;" onclick="handlePhoneNumberSubmission('${item.planId}', '${item.routerId}'); return false;"
data-plan-id="${item.planId}" data-plan-id="${item.planId}"
data-router-id="${item.routerId}"> data-router-id="${item.routerId}">
@ -184,281 +160,171 @@ function populateCards(data) {
}); });
} }
fetchData(); fetchData();
function getMacAddress() { </script>
return "$(mac)"; // MikroTik replaces this with the user's MAC address <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
} <script>
function formatPhoneNumber(phoneNumber) {
function getOrCreateAccountId() { if (phoneNumber.startsWith('+')) {
var radiaxid = localStorage.getItem('radiaxid'); phoneNumber = phoneNumber.substring(1);
if (!radiaxid) {
radiaxid = getMacAddress();
localStorage.setItem('radiaxid', radiaxid);
setCookie('radiaxid', radiaxid, 365);
}
return radiaxid;
}
function getAccountId() {
return localStorage.getItem('radiaxid') || getCookie('radiaxid') || getMacAddress();
}
function formatPhoneNumber(phoneNumber) {
if (phoneNumber.startsWith('+')) {
phoneNumber = phoneNumber.substring(1);
}
if (phoneNumber.startsWith('0')) {
phoneNumber = '254' + phoneNumber.substring(1);
}
if (phoneNumber.match(/^(7|1)/)) {
phoneNumber = '254' + phoneNumber;
}
return phoneNumber;
}
function setCookie(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
var loginTimeout;
function handlePhoneNumberSubmission(planId, routerId, price) {
var accountId = getOrCreateAccountId();
var modalHtml = `
<div id="paymentModal" class='fixed inset-0 bg-black/30 backdrop-blur-sm z-50 animate-fade-in'>
<div class="fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-md">
<div class="bg-white text-black rounded-lg shadow-xl">
<div class="flex items-center justify-between p-4 border-b border-gray-300">
<h5 class="text-xl font-semibold">
Enter Your Mpesa Number
</h5>
<button class="text-gray-500 hover:text-black" onclick="closeModal('paymentModal')">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="p-4">
<div class="bg-navy-50 border-l-4 border-navy-400 p-4 rounded-md mb-4"> <div class="flex"> <div class="flex-shrink-0"> <svg class="h-5 w-5 text-navy-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1 4v.01m6.938-2.162A9 9 0 1111 3v0a9 9 0 018.938 10.838z" /> </svg> </div> <div class="ml-3"> <p class="text-sm text-navy-700"> You are about to initiate M-pesa payment. Enter phone number below and click Pay Now to initialize payment. </p> </div> </div></div> <input type="text" class="w-full px-4 py-3 border border-orange-300 rounded-lg focus:ring-2 focus:ring-navy-400 focus:border-blue-500 text-black" id="phoneNumberInput" required placeholder="e.g. 0712345678">
<div class="text-red-500 mt-1 hidden" id="invalidPhone">Please enter a valid phone number!</div>
</div>
<div class="flex justify-end space-x-2 p-4 border-t border-gray-300">
<button onclick="closeModal('paymentModal')" class="px-4 py-2 bg-orange text-black rounded-lg hover:bg-gray-300">Close</button>
<button id="payNowBtn" class="px-4 py-2 bg-navy text-white font-semibold hover:from-blue-600 hover:to-blue-500 flex items-center rounded-lg">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 9V7a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2m2 4h10a2 2 0 002-2v-6a2 2 0 00-2-2H9a2 2 0 00-2 2v6a2 2 0 002 2zm7-5a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
Pay Now
</button>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', modalHtml);
var modal = document.getElementById('paymentModal');
modal.classList.remove('hidden');
var payNowBtn = document.getElementById('payNowBtn');
var phoneInput = document.getElementById('phoneNumberInput');
phoneInput.focus();
payNowBtn.addEventListener('click', function() { handlePayment(); });
function handlePayment() {
if (!phoneInput.value) {
document.getElementById('invalidPhone').classList.remove('hidden');
return;
} }
payNowBtn.disabled = true; if (phoneNumber.startsWith('0')) {
payNowBtn.innerHTML = ` phoneNumber = '254' + phoneNumber.substring(1);
<svg class='animate-spin -ml-1 mr-3 h-5 w-5 text-white' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'> }
<circle class='opacity-25' cx='12' cy='12' r='10' stroke='currentColor' stroke-width='4'></circle> if (phoneNumber.match(/^(7|1)/)) {
<path class='opacity-75' fill='currentColor' d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z'></path> phoneNumber = '254' + phoneNumber;
</svg> }
Processing... return phoneNumber;
`; }
var formattedPhoneNumber = formatPhoneNumber(phoneInput.value);
document.getElementById('usernameInput').value = accountId;
fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/CreateHotspotuser&type=grant', { function setCookie(name, value, days) {
method: 'POST', var expires = "";
headers: {'Content-Type': 'application/json'}, if (days) {
body: JSON.stringify({ var date = new Date();
phone_number: formattedPhoneNumber, date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
plan_id: planId, expires = "; expires=" + date.toUTCString();
router_id: routerId, }
account_id: accountId document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
function generateAccountId() {
return 'ACC' + Math.floor(10000 + Math.random() * 90000); // Generate a random number between 10000 and 99999
}
var loginTimeout; // Variable to store the timeout ID
function handlePhoneNumberSubmission(planId, routerId, price) {
var msg = "You are about to pay Kes: . Enter phone number below and click pay now to initialize payment";
const regexp = /\${([^{}]+)}/g;
let result = msg.replace(regexp, function(ignore, key) {
return eval(key);
});
swal.fire({
title: 'Enter Your Mpesa Number',
input: 'number',
inputAttributes: {
required: 'true'
},
inputValidator: function(value) {
if (value === '') {
return 'You need to write your phonenumber!';
}
},
text: result,
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Pay Now',
showLoaderOnConfirm: true,
preConfirm: (phoneNumber) => {
var formattedPhoneNumber = formatPhoneNumber(phoneNumber);
var accountId = getCookie('accountId');
if (!accountId) {
accountId = generateAccountId(); // Generate a new account ID
setCookie('accountId', accountId, 7); // Set account ID as a cookie
}
document.getElementById('usernameInput').value = accountId; // Use account ID as the new username
console.log("Phone number for autofill:", formattedPhoneNumber);
return fetch('https://mbsa.nestict.net/index.php?_route=plugin/CreateHotspotuser&type=grant', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({phone_number: formattedPhoneNumber, plan_id: planId, router_id: routerId, account_id: accountId}),
}) })
}) .then(response => {
.then(response => response.json()) if (!response.ok) throw new Error('Network response was not ok');
.then(data => { return response.json();
if (data.status === 'error') throw new Error(data.message); })
closeModal('paymentModal'); .then(data => {
showProcessingModal(); if (data.status === 'error') throw new Error(data.message);
checkPaymentStatus(formattedPhoneNumber); Swal.fire({
}) icon: 'info',
.catch(error => { title: 'Processing..',
closeModal('paymentModal'); html: `A payment request has been sent to your phone. Please wait while we process your payment.`,
showErrorModal(error.message); showConfirmButton: false,
}); allowOutsideClick: false,
} didOpen: () => {
} Swal.showLoading();
checkPaymentStatus(formattedPhoneNumber);
function showProcessingModal() { }
var processingModalHtml = ` });
<div id='processingModal' class='fixed inset-0 bg-black/30 backdrop-blur-sm z-50 animate-fade-in'> return formattedPhoneNumber;
<div class='fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-md animate-slide-up'> })
<div class='bg-gradient-to-br from-white to-gray-50 shadow-2xl rounded-2xl p-8 text-center border border-gray-100'> .catch(error => {
<div class='flex justify-center'> Swal.fire({
<svg class='animate-spin h-20 w-20 text-navy-500' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'> icon: 'error',
<circle class='opacity-25' cx='12' cy='12' r='10' stroke='currentColor' stroke-width='4'></circle> title: 'Oops...',
<path class='opacity-75' fill='currentColor' d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z'></path> text: error.message,
</svg> });
</div> });
<div class="mt-6 bg-navy-50/50 backdrop-blur-xs border border-navy-200 rounded-xl p-6 shadow-lg"> <div class="flex items-center space-x-4"> <svg class="h-8 w-8 text-navy-400 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1 4v.01m6.938-2.162A9 9 0 1111 3v0a9 9 0 018.938 10.838z" /> </svg> <div class="flex-1"> <h2 class="text-xl font-semibold text-navy-600 font-lexend">Initializing Payment</h2> <p class="text-navy-500 mt-2">A payment request has been sent to your phone. Please wait while we process your payment.</p> </div> </div> <div class="mt-4 h-2 w-full bg-navy-100 rounded-full overflow-hidden"> <div class="h-2 bg-navy-400 rounded-full animate-pulse"></div> </div> </div> </div> },
</div> allowOutsideClick: () => !Swal.isLoading()
</div> });
`;
document.body.insertAdjacentHTML('beforeend', processingModalHtml);
}
function closeModal(modalId) {
var modal = document.getElementById(modalId);
if (modal) {
modal.classList.add('hidden');
setTimeout(function() { modal.remove(); }, 300);
}
}
function showSuccessModal() {
var successModalHtml = `
<div id='successModal' class='fixed inset-0 bg-black/60 backdrop-blur-sm z-50 transition-all duration-300'>
<div class='fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-lg transition-all duration-300 ease-out'>
<div class='bg-white/95 backdrop-blur-md shadow-2xl rounded-3xl p-8 text-center border border-gray-200/50 ring-1 ring-gray-900/5'>
<div class='flex justify-center mb-6'>
<div class='relative'>
<div class='absolute inset-0 rounded-full bg-green-500/20 animate-pulse'></div>
<svg class='h-16 w-16 text-green-500' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z'/>
</svg>
</div>
</div>
<div class='space-y-4'>
<h2 class='text-2xl font-semibold text-gray-900'>Payment Successful</h2>
<div class='bg-green-50 rounded-2xl p-6 border border-green-100'>
<div class='flex items-center gap-4'>
<svg class='h-6 w-6 text-green-500 flex-shrink-0' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 12l2 2 4-4'/>
</svg>
<p class='text-sm text-green-700'>Your transaction has been completed successfully. You will be redirected shortly.</p>
</div>
</div>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', successModalHtml);
setTimeout(function() { closeModal('successModal'); }, 2000);
}
function showErrorModal(errorMsg) {
var errorModalHtml = `
<div id='errorModal' class='fixed inset-0 bg-black/60 backdrop-blur-sm z-50 transition-all duration-300'>
<div class='fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-lg transition-all duration-300 ease-out'>
<div class='bg-white/95 backdrop-blur-md shadow-2xl rounded-3xl p-8 text-center border border-gray-200/50 ring-1 ring-gray-900/5'>
<div class='flex justify-center mb-6'>
<div class='relative'>
<div class='absolute inset-0 rounded-full bg-red-500/20 animate-pulse'></div>
<svg class='h-16 w-16 text-red-500' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 18L18 6M6 6l12 12'/>
</svg>
</div>
</div>
<div class='space-y-4'>
<h2 class='text-2xl font-semibold text-gray-900'>Payment Failed</h2>
<div class='bg-red-50 rounded-2xl p-6 border border-red-100'>
<div class='flex items-center gap-4'>
<svg class='h-6 w-6 text-red-500 flex-shrink-0' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z'/>
</svg>
<p class='text-sm text-red-700'>An error occurred while processing your payment. Please try again.</p>
</div>
</div>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', errorModalHtml);
setTimeout(function() { closeModal('errorModal'); }, 2000);
} }
function checkPaymentStatus(phoneNumber) { function checkPaymentStatus(phoneNumber) {
var accountId = getOrCreateAccountId(); let checkInterval = setInterval(() => {
var checkInterval = setInterval(function() { $.ajax({
fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/CreateHotspotuser&type=verify', { url: 'https://mbsa.nestict.net/index.php?_route=plugin/CreateHotspotuser&type=verify',
method: 'POST', method: 'POST',
headers: {'Content-Type': 'application/json'}, data: JSON.stringify({account_id: document.getElementById('usernameInput').value}),
body: JSON.stringify({account_id: accountId}) contentType: 'application/json',
}) dataType: 'json',
.then(function(response) { return response.json(); }) success: function(data) {
.then(function(data) { console.log('Raw Response:', data); // Debugging
console.log('Raw Response:', data); if (data.Resultcode === '3') { // Success
if (data.Resultcode === '3') { clearInterval(checkInterval);
clearInterval(checkInterval); Swal.fire({
closeModal('processingModal'); icon: 'success',
showSuccessModal(); title: 'Payment Successful',
if (loginTimeout) clearTimeout(loginTimeout); text: data.Message,
loginTimeout = setTimeout(function() { document.getElementById('loginForm').submit(); }, 2000); showConfirmButton: false
} else if (data.Resultcode === '2') { });
clearInterval(checkInterval); if (loginTimeout) {
closeModal('processingModal'); clearTimeout(loginTimeout);
showErrorModal(data.Message); }
} else { loginTimeout = setTimeout(function() {
console.error('Unexpected result code:', data.Resultcode); document.getElementById('loginForm').submit();
}, 2000);
} else if (data.Resultcode === '2') { // Error
clearInterval(checkInterval);
let iconType = data.Status === 'danger' ? 'error' : data.Status;
Swal.fire({
icon: iconType,
title: 'Payment Issue',
text: data.Message,
});
} else if (data.Resultcode === '1') { // Primary
// Continue checking
}
},
error: function(xhr, textStatus, errorThrown) {
console.log('Error: ' + errorThrown);
} }
})
.catch(function(error) {
console.error('Error during fetch request:', error);
clearInterval(checkInterval);
closeModal('processingModal');
showErrorModal('An error occurred while checking payment status.');
}); });
}, 1000); }, 2000);
setTimeout(function() { setTimeout(() => {
clearInterval(checkInterval); clearInterval(checkInterval);
closeModal('processingModal'); Swal.fire({
showErrorModal('Timeout while waiting for payment confirmation.'); icon: 'warning',
}, 300000); // 5 minutes title: 'Timeout',
} text: 'Payment verification timed out. Please try again.',
document.addEventListener('DOMContentLoaded', function() {
var accountId = getOrCreateAccountId();
var usernameInput = document.getElementById('usernameInput');
if (usernameInput && !usernameInput.value) {
usernameInput.value = accountId;
}
var submitBtn = document.getElementById('submitBtn');
if (submitBtn) {
submitBtn.addEventListener('click', function() {
document.getElementById('loginForm').submit();
}); });
} }, 600000); // Stop checking after 60 seconds
}); }
</script>
</script>
<script>
var loginTimeout; // Variable to store the timeout ID var loginTimeout; // Variable to store the timeout ID
function redeemVoucher() { function redeemVoucher() {
Swal.fire({ Swal.fire({
@ -476,7 +342,11 @@ function redeemVoucher() {
showLoaderOnConfirm: true, showLoaderOnConfirm: true,
preConfirm: (voucherCode) => { preConfirm: (voucherCode) => {
var accountId = voucherCode; var accountId = voucherCode;
return fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/CreateHotspotuser&type=voucher', { if (!accountId) {
accountId = voucherCode;
setCookie('accountId', accountId, 7);
}
return fetch('https://mbsa.nestict.net/index.php?_route=plugin/CreateHotspotuser&type=voucher', {
method: 'POST', method: 'POST',
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: JSON.stringify({voucher_code: voucherCode, account_id: accountId}), body: JSON.stringify({voucher_code: voucherCode, account_id: accountId}),
@ -539,105 +409,94 @@ function redeemVoucher() {
}); });
}); });
} }
</script>
<script>
var loginTimeout; // Variable to store the timeout ID
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
var reconnectBtn = document.getElementById('reconnectBtn'); document.getElementById('reconnectBtn').addEventListener('click', function() {
var mpesaCodeInput = document.getElementById('mpesaCodeInput'); var mpesaCode = document.getElementById('mpesaCodeInput').value;
var macInput = document.getElementById('mac'); var firstWord = mpesaCode.split(' ')[0]; // Get the first word in the MPESA code
var loginForm = document.getElementById('loginForm'); fetch('https://mbsa.nestict.net/index.php?_route=plugin/CreateHotspotuser&type=reconnect', {
if (reconnectBtn) { method: 'POST',
reconnectBtn.addEventListener('click', function() { headers: {'Content-Type': 'application/json'},
// Validate inputs before processing body: JSON.stringify({mpesa_code: firstWord}),
if (!mpesaCodeInput || !macInput || !loginForm) { })
.then(response => response.json())
.then(data => {
if (data.Status === 'success') {
Swal.fire({ Swal.fire({
icon: 'error', icon: 'success',
title: 'Error', title: 'Reconnection Successful',
text: 'Required form elements are missing' text: data.Message,
}); showConfirmButton: false,
return; allowOutsideClick: false,
} didOpen: () => {
var mpesaCode = mpesaCodeInput.value.trim().split(' ')[0]; Swal.showLoading();
var mac = macInput.value.trim(); var username = data.username; // Replace with actual JSON field name
fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/ReconnectUser', { console.log('Received username from server:', username);
method: 'POST', var usernameInput = document.querySelector('input[name="username"]');
headers: {'Content-Type': 'application/json'}, if (usernameInput) {
body: JSON.stringify({ mpesa_code: mpesaCode, mac: mac }), console.log('Found username input element.');
}) usernameInput.value = username;
.then(response => { loginTimeout = setTimeout(function() {
if (!response.ok) { var loginForm = document.getElementById('loginForm');
throw new Error('Network response was not ok'); if (loginForm) {
} loginForm.submit();
return response.json(); } else {
}) console.error('Login form not found.');
.then(data => { Swal.fire({
console.log('Response data:', data); icon: 'error',
var resultCode = data.Resultcode; title: 'Error',
var message = data.Message; text: 'Login form not found. Please try again.',
var status = data.Status; });
var username = data.username; }
if (resultCode === '1') { }, 2000);
Swal.fire({ } else {
icon: 'error', console.error('Username input element not found.');
title: 'Invalid Code', Swal.fire({
text: message icon: 'error',
}); title: 'Error',
} text: 'Username input not found. Please try again.',
else if (resultCode === '3') { });
Swal.fire({
icon: 'error',
title: 'Expired Package',
text: message
});
}
else if (resultCode === '2') {
Swal.fire({
icon: 'success',
title: status,
text: message,
showConfirmButton: false,
allowOutsideClick: false,
didOpen: () => {
Swal.showLoading();
console.log('Received username from server:', username);
var usernameInput = document.querySelector('input[name="username"]');
if (usernameInput) {
console.log('Found username input element.');
usernameInput.value = username;
setTimeout(function() {
var loginForm = document.getElementById('loginForm');
if (loginForm) {
loginForm.submit();
} else {
console.error('Login form not found.');
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Login form not found. Please try again.',
});
}
}, 2000);
} else {
console.error('Username input element not found.');
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Username input not found. Please try again.',
});
}
} }
}); }
} });
}) } else {
.catch(error => {
Swal.fire({ Swal.fire({
icon: 'error', icon: 'error',
title: 'Oops...', title: 'Reconnection Failed',
text: error.message text: data.Message,
}); });
}
})
.catch(error => {
console.error('Error:', error);
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Failed to reconnect. Please try again later.',
}); });
}); });
} else { });
console.error('Reconnect button not found'); });
} </script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Ensure the button is correctly targeted by its ID.
var submitBtn = document.getElementById('submitBtn');
// Add a click event listener to the "Login Now" button.
submitBtn.addEventListener('click', function(event) {
event.preventDefault(); // Prevent the default button action.
// Optional: Log to console for debugging purposes.
console.log("Login Now button clicked.");
// Direct form submission, bypassing the doLogin function for simplicity.
var form = document.getElementById('loginForm');
form.submit(); // Submit the form directly.
});
}); });
</script> </script>
</html> </html>