Add files via upload
This commit is contained in:
parent
b1a8bd7d6d
commit
4a49e7e18b
162
ASAshop.html
162
ASAshop.html
|
|
@ -338,10 +338,7 @@
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h1>BESTWCOAST Shop</h1>
|
<h1>BESTWCOAST Shop</h1>
|
||||||
<a class="cart-btn"
|
<a class="cart-btn" href="https://discord.gg/kQrAQSSrez" id="loginDiscord">Login to our Discord</a>
|
||||||
href="#"
|
|
||||||
id="loginDiscord"
|
|
||||||
data-client-id="1423370765578797126">Login to our Discord</a>
|
|
||||||
<span id="whoami" class="muted"></span>
|
<span id="whoami" class="muted"></span>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<nav class="links" aria-label="Primary">
|
<nav class="links" aria-label="Primary">
|
||||||
|
|
@ -375,64 +372,6 @@
|
||||||
<section id="grid" class="grid"></section>
|
<section id="grid" class="grid"></section>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<script>
|
|
||||||
const API = "https://affiliated-lets-automatic-oak.trycloudflare.com"; // unchanged
|
|
||||||
|
|
||||||
// ---- whoami banner (unchanged logic) ----
|
|
||||||
async function getWhoAmI() {
|
|
||||||
try {
|
|
||||||
const r = await fetch(`${API}/api/inventory`, { credentials: 'include' });
|
|
||||||
if (!r.ok) return null;
|
|
||||||
const j = await r.json();
|
|
||||||
const u = j?.user ?? j;
|
|
||||||
const label = u?.global_name ?? u?.username ?? (u?.id ? `User ${u.id}` : null);
|
|
||||||
return label ? { label, raw: u } : null;
|
|
||||||
} catch { return null; }
|
|
||||||
}
|
|
||||||
(async () => {
|
|
||||||
const who = await getWhoAmI();
|
|
||||||
document.getElementById('whoami').textContent =
|
|
||||||
who ? `Signed in as ${who.label}` : 'Not signed in';
|
|
||||||
})();
|
|
||||||
|
|
||||||
// ---- FIXED Discord login button ----
|
|
||||||
document.getElementById('loginDiscord').addEventListener('click', async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const backTo = encodeURIComponent(location.href);
|
|
||||||
const clientId = document.getElementById('loginDiscord').dataset.clientId;
|
|
||||||
const backendStart = `${API}/api/auth/discord?redirect=${backTo}`;
|
|
||||||
const callback = encodeURIComponent(`${API}/api/auth/discord/callback`);
|
|
||||||
const direct = `https://discord.com/oauth2/authorize?client_id=${clientId}&redirect_uri=${callback}&response_type=code&scope=identify`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// If backend is reachable, use the backend start route
|
|
||||||
const ping = await fetch(`${API}/healthz`, { mode: 'no-cors' }).catch(() => null);
|
|
||||||
// no-cors fetch won’t throw on 200, but if DNS/route fails we hit catch above
|
|
||||||
location.href = backendStart;
|
|
||||||
} catch {
|
|
||||||
// Fallback: go straight to Discord’s authorize page
|
|
||||||
location.href = direct;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
document.getElementById('checkoutBtn').addEventListener('click', async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const entries = Object.entries(state.cart || {});
|
|
||||||
if (!entries.length) return alert('Your cart is empty.');
|
|
||||||
|
|
||||||
alert("⚠️ IMPORTANT: After checkout, you must contact a team member to receive your order.\n\nPlease open a ticket in Discord once payment is complete.");
|
|
||||||
|
|
||||||
const items = entries.map(([id, qty]) => {
|
|
||||||
const p = products.find(p => p.id === id);
|
|
||||||
return { id, name: p?.name || id, qty: Number(qty || 1), price: p?.price || 0 };
|
|
||||||
});
|
|
||||||
|
|
||||||
await checkout(items);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Drawer (Cart) -->
|
<!-- Drawer (Cart) -->
|
||||||
<aside id="drawer" aria-hidden="true">
|
<aside id="drawer" aria-hidden="true">
|
||||||
|
|
@ -528,63 +467,36 @@
|
||||||
let remaining = 12;
|
let remaining = 12;
|
||||||
|
|
||||||
/* ===== Login banner (whoami) ===== */
|
/* ===== Login banner (whoami) ===== */
|
||||||
/* ===== Login banner (whoami) + Discord OAuth ===== */
|
|
||||||
async function getWhoAmI() {
|
async function getWhoAmI() {
|
||||||
try {
|
try {
|
||||||
// inventory endpoint should set/return session if already logged in
|
const r = await fetch(`${API}/api/inventory`, { credentials: 'include' })
|
||||||
const r = await fetch(`${API}/api/inventory`, { credentials: 'include' });
|
|
||||||
if (!r.ok) return null;
|
if (!r.ok) return null;
|
||||||
const j = await r.json();
|
return await r.json();
|
||||||
|
} catch { return null; }
|
||||||
// Some backends return user data nested (e.g., { user: {...} })
|
|
||||||
const u = j?.user ?? j;
|
|
||||||
|
|
||||||
// Prefer global_name, fall back to username, then to Discord ID
|
|
||||||
const label =
|
|
||||||
u?.global_name ??
|
|
||||||
u?.username ??
|
|
||||||
(u?.id ? `User ${u.id}` : null);
|
|
||||||
|
|
||||||
return label ? { label, raw: u } : null;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
getWhoAmI().then(u => {
|
||||||
|
if (u) document.getElementById('whoami').textContent =
|
||||||
// Show status next to the button
|
`Signed in as ${u.global_name || u.username}`;
|
||||||
(async () => {
|
|
||||||
const who = await getWhoAmI();
|
|
||||||
document.getElementById('whoami').textContent =
|
|
||||||
who ? `Signed in as ${who.label}` : 'Not signed in';
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Clicking the button should start Discord OAuth on your server.
|
|
||||||
// Adjust the path if your backend uses a different route.
|
|
||||||
document.getElementById('loginDiscord').addEventListener('click', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const redirect = encodeURIComponent(location.href);
|
|
||||||
location.href = `${API}/api/auth/discord?redirect=${redirect}`;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/* ===== Products (unique IDs) ===== */
|
/* ===== Products (unique IDs) ===== */
|
||||||
const products = [
|
const products = [
|
||||||
{ id: 'server1', name: 'Server Class 1', price: 25.00, category: 'servers', tag: 'Server monthly', img: 'img/PrivateServerCLASS01.png' },
|
{ id: 'server1', name: 'Server Class 1', price: 25.00, category: 'servers', tag: 'Server monthly', img: 'img/PrivateServerCLASS01.png'},
|
||||||
{ id: 'server2', name: 'Server Class 2', price: 50.00, category: 'servers', tag: 'Server monthly', img: 'img/PrivateServerCLASS02.png' },
|
{ id: 'server2', name: 'Server Class 2', price: 50.00, category: 'servers', tag: 'Server monthly', img: 'img/PrivateServerCLASS02.png'},
|
||||||
{ id: 'server3', name: 'Server Class 3', price: 75.00, category: 'servers', tag: 'Server monthly', img: 'img/PrivateServerCLASS03.png' },
|
{ id: 'server3', name: 'Server Class 3', price: 75.00, category: 'servers', tag: 'Server monthly', img: 'img/PrivateServerCLASS03.png' },
|
||||||
|
|
||||||
{ id: 'slot30', name: 'ASA Server Slot x30 days', price: 5.00, category: 'perks', tag: 'Server Perk monthly', img: 'img/ServerSlotX30.png' },
|
{ id: 'slot30', name: 'ASA Server Slot x30 days', price: 5.00, category: 'perks', tag: 'Server Perk monthly', img: 'img/ServerSlotX30.png' },
|
||||||
{ id: 'mutants', name: 'Mutated Creatures', price: 1.50, category: 'bundles', tag: 'Dino Pack One Time Payment 10 non-breedable', img: 'img/MutatedCretures.png' },
|
{ id: 'mutants', name: 'Mutated Creatures', price: 1.50, category: 'bundles', tag: 'Dino Pack One Time Payment 10 non-breedable', img: 'img/MutatedCretures.png'},
|
||||||
{ id: 'starter', name: 'Starter Pack', price: 1.50, category: 'bundles', tag: 'Starter Pack One Time Payment', img: 'img/StarterPack.png' },
|
{ id: 'starter', name: 'Starter Pack', price: 1.50, category: 'bundles', tag: 'Starter Pack One Time Payment', img: 'img/StarterPack.png'},
|
||||||
|
|
||||||
{ id: 'supporter1', name: 'ASA Server Supporter Pack 1', price: 5.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 50,000 Points every week🎁 50,000 Bonus Points at the start of each wipe 🏅 Exclusive VIP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP1.png' },
|
{ id: 'supporter1', name: 'ASA Server Supporter Pack 1', price: 5.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 50,000 Points every week🎁 50,000 Bonus Points at the start of each wipe 🏅 Exclusive VIP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP1.png' },
|
||||||
{ id: 'supporter2', name: 'ASA Server Supporter Pack 2', price: 10.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 100,000 Points every week🎁 100,000 Bonus Points at the start of each wipe 🏅 Exclusive VIP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP2.png' },
|
{ id: 'supporter2', name: 'ASA Server Supporter Pack 2', price: 10.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 100,000 Points every week🎁 100,000 Bonus Points at the start of each wipe 🏅 Exclusive VIP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP2.png' },
|
||||||
{ id: 'supporter3', name: 'ASA Server Supporter Pack 3', price: 15.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 150,000 Points every week🎁 150,000 Bonus Points at the start of each wipe 🏅 Exclusive VIP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP3.png' },
|
{ id: 'supporter3', name: 'ASA Server Supporter Pack 3', price: 15.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 150,000 Points every week🎁 150,000 Bonus Points at the start of each wipe 🏅 Exclusive VIP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP3.png'},
|
||||||
{ id: 'supporter4', name: 'ASA Server Supporter Pack 4', price: 20.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 500,000 Points every week🎁 500,000 Bonus Points at the start of each wipe 🏅 Exclusive MVP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP4.png' },
|
{ id: 'supporter4', name: 'ASA Server Supporter Pack 4', price: 20.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 500,000 Points every week🎁 500,000 Bonus Points at the start of each wipe 🏅 Exclusive MVP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP4.png'},
|
||||||
{ id: 'supporter5', name: 'ASA Server Supporter Pack 5', price: 25.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 1,000,000 Points every week🎁 1,000,000 Bonus Points at the start of each wipe 🏅 Exclusive MVP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP5.png' },
|
{ id: 'supporter5', name: 'ASA Server Supporter Pack 5', price: 25.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 1,000,000 Points every week🎁 1,000,000 Bonus Points at the start of each wipe 🏅 Exclusive MVP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP5.png'},
|
||||||
{ id: 'supporter6', name: 'ASA Server Supporter Pack 6', price: 35.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 1,500,000 Points every week🎁 1,500,000 Bonus Points at the start of each wipe 🏅 Exclusive MVP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP6.png' },
|
{ id: 'supporter6', name: 'ASA Server Supporter Pack 6', price: 35.00, category: 'vip', tag: 'Server Perk monthly <br> ✨ Perks Included ✨ 💎 1,500,000 Points every week🎁 1,500,000 Bonus Points at the start of each wipe 🏅 Exclusive MVP Role on Discord 🔒 Access to the Donator - Only Chat', img: 'img/SP6.png'},
|
||||||
|
|
||||||
{ id: 'map-small', name: 'Small Map manipulation', price: 5.00, category: 'maps', tag: 'Small Map manipulation Pack One Time Payment', img: 'img/SmallMap.png' },
|
{ id: 'map-small', name: 'Small Map manipulation', price: 5.00, category: 'maps', tag: 'Small Map manipulation Pack One Time Payment', img: 'img/SmallMap.png'},
|
||||||
{ id: 'map-medium', name: 'Medium Map manipulation', price: 10.00, category: 'maps', tag: 'Medium Map manipulation Pack One Time Payment', img: 'img/MediumMap.png' },
|
{ id: 'map-medium', name: 'Medium Map manipulation', price: 10.00, category: 'maps', tag: 'Medium Map manipulation Pack One Time Payment', img: 'img/MediumMap.png' },
|
||||||
{ id: 'map-large', name: 'Large Map manipulation', price: 15.00, category: 'maps', tag: 'Large Map manipulation Pack One Time Payment', img: 'img/LargeMap.png' },
|
{ id: 'map-large', name: 'Large Map manipulation', price: 15.00, category: 'maps', tag: 'Large Map manipulation Pack One Time Payment', img: 'img/LargeMap.png' },
|
||||||
];
|
];
|
||||||
|
|
@ -768,68 +680,34 @@
|
||||||
|
|
||||||
|
|
||||||
async function checkout(cart) {
|
async function checkout(cart) {
|
||||||
let user = null;
|
// 1) reserve
|
||||||
try {
|
|
||||||
const r = await fetch(`${API}/api/inventory`, { credentials: 'include' });
|
|
||||||
if (r.ok) user = await r.json();
|
|
||||||
} catch { }
|
|
||||||
|
|
||||||
// reserve
|
|
||||||
const r1 = await fetch(`${API}/api/reserve`, {
|
const r1 = await fetch(`${API}/api/reserve`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ items: cart, user })
|
body: JSON.stringify({ items: cart })
|
||||||
});
|
});
|
||||||
const j1 = await r1.json();
|
const j1 = await r1.json();
|
||||||
if (!j1.ok) { alert(j1.error || 'reserve failed'); return; }
|
if (!j1.ok) { alert(j1.error || 'reserve failed'); return; }
|
||||||
|
|
||||||
// create checkout with Discord user
|
// 2) create checkout
|
||||||
const r2 = await fetch(`${API}/api/create-checkout`, {
|
const r2 = await fetch(`${API}/api/create-checkout`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
resKey: j1.resKey,
|
resKey: j1.resKey,
|
||||||
items: [],
|
items: [],
|
||||||
discordUser: user, // <— this flows to metadata
|
|
||||||
success_url: location.origin + location.pathname + '?ok=1',
|
success_url: location.origin + location.pathname + '?ok=1',
|
||||||
cancel_url: location.origin + location.pathname + '?cancel=1'
|
cancel_url: location.origin + location.pathname + '?cancel=1'
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
const j2 = await r2.json();
|
const j2 = await r2.json();
|
||||||
if (!j2.url) { alert(j2.error || 'create-checkout failed'); return; }
|
if (!j2.url) { alert(j2.error || 'create-checkout failed'); return; }
|
||||||
location.href = j2.url;
|
location.href = j2.url; // redirect to Stripe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Single, unified checkout click handler (shows warning, then proceeds)
|
|
||||||
document.getElementById('checkoutBtn').addEventListener('click', async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const entries = Object.entries(state.cart || {});
|
|
||||||
if (!entries.length) return alert('Your cart is empty.');
|
|
||||||
|
|
||||||
alert("⚠️ IMPORTANT: After checkout, you must contact a team member to receive your order.\n\nPlease open a ticket in Discord once payment is complete.");
|
|
||||||
|
|
||||||
const items = entries.map(([id, qty]) => {
|
|
||||||
const p = products.find(p => p.id === id);
|
|
||||||
return { id, name: p?.name || id, qty: Number(qty || 1), price: p?.price || 0 };
|
|
||||||
});
|
|
||||||
|
|
||||||
await checkout(items);
|
|
||||||
});
|
|
||||||
|
|
||||||
// === Checkout warning ===
|
|
||||||
document.getElementById('checkoutBtn').addEventListener('click', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
alert("⚠️ IMPORTANT: After checkout, you must contact a team member to receive your order.\n\nPlease open a ticket in Discord once payment is complete.");
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('checkoutBtn').addEventListener('click', async () => {
|
document.getElementById('checkoutBtn').addEventListener('click', async () => {
|
||||||
const entries = Object.entries(state.cart || {});
|
const entries = Object.entries(state.cart || {});
|
||||||
if (!entries.length) return alert('Your cart is empty.');
|
if (!entries.length) return alert('Your cart is empty.');
|
||||||
|
|
||||||
alert("⚠️ IMPORTANT: After checkout, you must contact a team member to receive your order.\n\nPlease open a ticket in Discord once payment is complete.");
|
|
||||||
|
|
||||||
const items = entries.map(([id, qty]) => {
|
const items = entries.map(([id, qty]) => {
|
||||||
const p = products.find(p => p.id === id);
|
const p = products.find(p => p.id === id);
|
||||||
return { id, name: p?.name || id, qty: Number(qty || 1), price: p?.price || 0 };
|
return { id, name: p?.name || id, qty: Number(qty || 1), price: p?.price || 0 };
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue