| Server IP : 173.209.174.21 / Your IP : 216.73.216.89 Web Server : Apache/2.4.58 (Ubuntu) System : Linux wcfs-server 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64 User : nodor ( 1000) PHP Version : 8.3.6 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/wifi-wcfs/public/ |
Upload File : |
<?php
require __DIR__ . '/../lib.php';
$mac = client_mac_from_request();
$clientIp = $_SERVER['REMOTE_ADDR'] ?? null;
$plans = plans();
$logoPath = __DIR__ . '/assets/logo.png';
$hasLogo = file_exists($logoPath);
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Wilson Creek Farm Supply Wi-Fi</title>
<style>
* { box-sizing: border-box; }
html, body { min-height: 100%; }
body {
font-family: Arial, Helvetica, sans-serif;
margin: 0;
background: #eef1ea;
color: #142019;
}
body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
background:
linear-gradient(135deg, rgba(39, 103, 73, .13), transparent 38%),
linear-gradient(315deg, rgba(161, 96, 42, .14), transparent 36%);
}
main {
position: relative;
width: 100%;
max-width: 1040px;
margin: 0 auto;
padding: 28px 16px 44px;
}
.shell {
display: grid;
gap: 18px;
}
.brand {
display: flex;
align-items: center;
gap: 14px;
padding: 18px;
background: rgba(255, 255, 255, .82);
border: 1px solid #d7ddce;
border-radius: 8px;
box-shadow: 0 16px 36px rgba(24, 39, 30, .08);
}
.brand-logo {
width: 74px;
height: 74px;
flex: 0 0 74px;
border-radius: 8px;
background: #276749;
color: white;
display: grid;
place-items: center;
font-weight: 800;
font-size: 24px;
letter-spacing: 0;
overflow: hidden;
}
.brand-logo img {
width: 100%;
height: 100%;
object-fit: contain;
padding: 7px;
background: white;
}
h1 {
margin: 0;
font-size: clamp(27px, 5vw, 42px);
line-height: 1.06;
letter-spacing: 0;
}
.subtitle {
margin: 8px 0 0;
color: #4f5d50;
font-size: 17px;
line-height: 1.35;
}
.content {
display: grid;
grid-template-columns: minmax(280px, 380px) 1fr;
gap: 18px;
align-items: start;
}
.plans-panel,
#checkout-wrap {
background: rgba(255, 255, 255, .9);
border: 1px solid #d7ddce;
border-radius: 8px;
box-shadow: 0 16px 36px rgba(24, 39, 30, .08);
}
.plans-panel {
padding: 16px;
}
.panel-title {
margin: 0 0 12px;
font-size: 20px;
line-height: 1.2;
}
.plans {
display: grid;
gap: 10px;
}
.plan {
background: white;
border: 1px solid #dbe1d4;
border-radius: 8px;
padding: 14px;
display: grid;
grid-template-columns: 1fr auto;
gap: 12px;
align-items: center;
}
.plan strong {
display: block;
font-size: 18px;
line-height: 1.2;
}
.plan span {
display: block;
margin-top: 4px;
color: #5e6b5c;
font-size: 16px;
}
button {
background: #276749;
color: white;
border: 0;
border-radius: 6px;
padding: 13px 16px;
min-width: 94px;
font-size: 16px;
font-weight: 700;
cursor: pointer;
white-space: nowrap;
box-shadow: inset 0 -2px 0 rgba(0, 0, 0, .12);
}
button:disabled {
opacity: .65;
cursor: wait;
}
.fine-print {
margin: 14px 0 0;
color: #647060;
font-size: 13px;
line-height: 1.35;
}
#checkout-wrap {
display: none;
padding: 12px;
width: 100%;
min-height: 900px;
}
#checkout-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 10px;
color: #4f5d50;
font-size: 14px;
}
#north-checkout {
width: 100%;
min-height: 850px;
}
#north-checkout iframe {
width: 100% !important;
min-height: 850px !important;
}
#message {
margin-top: 14px;
font-weight: 700;
color: #273827;
line-height: 1.35;
}
@media (max-width: 860px) {
main {
padding: 14px 8px 28px;
}
.brand {
align-items: flex-start;
padding: 14px;
}
.brand-logo {
width: 60px;
height: 60px;
flex-basis: 60px;
font-size: 20px;
}
.content {
grid-template-columns: 1fr;
}
.plans-panel {
padding: 12px;
}
.plan {
padding: 13px;
}
#checkout-wrap {
padding: 6px;
min-height: 980px;
}
#north-checkout,
#north-checkout iframe {
min-height: 940px !important;
}
}
</style>
<script src="https://checkout.north.com/checkout.js"></script>
</head>
<body>
<main>
<div class="shell">
<header class="brand">
<div class="brand-logo" aria-hidden="true">
<?php if ($hasLogo): ?>
<img src="/assets/logo.png" alt="">
<?php else: ?>
WC
<?php endif; ?>
</div>
<div>
<h1>Wilson Creek Farm Supply Wi-Fi</h1>
<p class="subtitle">Choose a pass and pay securely to get online.</p>
</div>
</header>
<section class="content">
<div class="plans-panel">
<h2 class="panel-title">Wi-Fi Passes</h2>
<div class="plans">
<?php foreach ($plans as $plan): ?>
<div class="plan">
<div>
<strong><?= htmlspecialchars($plan['name']) ?></strong>
<span>$<?= number_format((float) $plan['price'], 2) ?></span>
</div>
<button data-plan="<?= htmlspecialchars($plan['id']) ?>">Buy Pass</button>
</div>
<?php endforeach; ?>
</div>
<p class="fine-print">Payment is processed securely through North. Access starts after approval.</p>
<div id="message"></div>
</div>
<div id="checkout-wrap">
<div id="checkout-head">
<strong>Secure checkout</strong>
<span>Powered by North</span>
</div>
<div id="north-checkout"></div>
</div>
</section>
</div>
</main>
<script>
const clientMac = <?= json_encode($mac) ?>;
const clientIp = <?= json_encode($clientIp) ?>;
const portalParams = new URLSearchParams(window.location.search);
const message = document.getElementById('message');
const checkoutWrap = document.getElementById('checkout-wrap');
const checkoutTarget = document.getElementById('north-checkout');
document.querySelectorAll('button[data-plan]').forEach((button) => {
button.addEventListener('click', async () => {
document.querySelectorAll('button[data-plan]').forEach((btn) => btn.disabled = true);
message.textContent = 'Opening secure checkout...';
checkoutTarget.innerHTML = '';
try {
const response = await fetch('/api/create-checkout-session.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
plan_id: button.dataset.plan,
client_mac: clientMac,
client_ip: portalParams.get('uip') || clientIp,
sip: portalParams.get('sip') || '',
start_url: portalParams.get('url') || ''
})
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Could not start checkout.');
}
const sessionToken = data.sessionToken || data.token;
if (!sessionToken) {
throw new Error('North did not return a session token.');
}
if (!window.checkout || typeof checkout.mount !== 'function') {
throw new Error('North checkout script did not load.');
}
checkoutWrap.style.display = 'block';
message.textContent = '';
await checkout.mount(sessionToken, 'north-checkout');
checkoutWrap.scrollIntoView({behavior: 'smooth', block: 'start'});
checkout.onPaymentComplete(() => {
window.location.href = '/complete.php?session=' + encodeURIComponent(data.localSessionId);
});
} catch (error) {
checkoutWrap.style.display = 'none';
message.textContent = 'Checkout failed to open: ' + error.message;
document.querySelectorAll('button[data-plan]').forEach((btn) => btn.disabled = false);
}
});
});
</script>
</body>
</html>