futbol / admin.html
jaynesmax's picture
Upload 4 files
ffc4f43 verified
Raw History Blame Contribute Delete
6.01 kB
<!doctype html>
<html lang="sw"><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Admin β€” FUTBOL PICKS</title>
<link rel="stylesheet" href="styles.css">
</head><body>
<header id="nav"></header>
<main>
<p id="denied" class="err" hidden>Huna ruhusa ya kuona ukurasa huu. <a href="login.html">Ingia</a></p>
<div id="panel" hidden>
<div class="card">
<h1>1. Ongeza mechi</h1>
<form id="matchForm">
<div class="grid2">
<div><label>Ligi / Mashindano</label><input id="mComp" required></div>
<div><label>Nchi (hiari)</label><input id="mCountry"></div>
<div><label>Timu ya nyumbani</label><input id="mHome" required></div>
<div><label>Timu ya ugenini</label><input id="mAway" required></div>
<div><label>Muda wa kuanza</label><input type="datetime-local" id="mKick" required></div>
</div>
<button type="submit" style="margin-top:1rem">Hifadhi mechi</button>
</form>
<p class="msg" id="mMsg"></p>
</div>
<div class="card">
<h1>2. Ongeza utabiri</h1>
<form id="predForm">
<label>Mechi</label><select id="pMatch" required></select>
<div class="grid2">
<div><label>Soko</label><input id="pMarket" placeholder="Mfano: Matokeo, Over 2.5, BTTS" required></div>
<div><label>Uchaguzi</label><input id="pSelection" placeholder="Mfano: Nyumbani, Ndiyo" required></div>
</div>
<label>Maelezo ya uchambuzi</label><textarea id="pExpl" rows="3"></textarea>
<label class="row" style="margin-top:.8rem"><input type="checkbox" id="pPub" style="width:auto"> Chapisha sasa</label>
<button type="submit" style="margin-top:1rem">Hifadhi utabiri</button>
</form>
<p class="msg" id="pMsg"></p>
</div>
<div class="card" style="overflow-x:auto">
<h1>3. Utabiri wote</h1>
<table>
<thead><tr><th>Mechi</th><th>Soko / Uchaguzi</th><th>Chapisha</th><th>Matokeo</th></tr></thead>
<tbody id="rows"></tbody>
</table>
<p class="msg" id="rMsg"></p>
</div>
</div>
</main>
<script type="module">
import { sb, esc, fmtDate, renderNav, currentProfile } from "./common.js";
const $ = id => document.getElementById(id);
const { session, profile } = await currentProfile();
renderNav("admin", profile);
const say = (id, text, ok = true) => { $(id).className = "msg " + (ok ? "ok" : "err"); $(id).textContent = text; };
const isAdmin = !!session && profile?.role === "admin";
if (!isAdmin) {
$("denied").hidden = false;
} else {
$("panel").hidden = false;
await loadMatches();
await loadPredictions();
}
async function loadMatches() {
const { data, error } = await sb.from("matches").select("*").order("kickoff_at", { ascending: false });
if (error) return say("mMsg", error.message, false);
$("pMatch").innerHTML = data.map(m =>
`<option value="${m.id}">${esc(m.home_team)} vs ${esc(m.away_team)} β€” ${fmtDate(m.kickoff_at)}</option>`).join("");
}
$("matchForm").onsubmit = async e => {
e.preventDefault();
const { error } = await sb.from("matches").insert({
competition: $("mComp").value.trim(),
country: $("mCountry").value.trim() || null,
home_team: $("mHome").value.trim(),
away_team: $("mAway").value.trim(),
kickoff_at: new Date($("mKick").value).toISOString()
});
if (error) return say("mMsg", error.message, false);
e.target.reset();
say("mMsg", "Mechi imehifadhiwa βœ”");
loadMatches();
};
$("predForm").onsubmit = async e => {
e.preventDefault();
const published = $("pPub").checked;
const { error } = await sb.from("predictions").insert({
match_id: $("pMatch").value,
market: $("pMarket").value.trim(),
selection: $("pSelection").value.trim(),
explanation: $("pExpl").value.trim() || null,
published,
published_at: published ? new Date().toISOString() : null,
created_by: session.user.id
});
if (error) return say("pMsg", error.message, false);
e.target.reset();
say("pMsg", "Utabiri umehifadhiwa βœ”");
loadPredictions();
};
async function loadPredictions() {
const { data, error } = await sb.from("predictions")
.select("*, matches(home_team,away_team)")
.order("created_at", { ascending: false });
if (error) return say("rMsg", error.message, false);
$("rows").innerHTML = data.length ? data.map(p => `
<tr>
<td>${esc(p.matches.home_team)} vs ${esc(p.matches.away_team)}</td>
<td>${esc(p.market)}: <b>${esc(p.selection)}</b></td>
<td><button class="${p.published ? "ghost" : "gold"}" data-pub="${p.id}" data-on="${p.published}">
${p.published ? "Ficha" : "Chapisha"}</button></td>
<td>
<select data-res="${p.id}" style="width:auto">
${["pending", "won", "lost", "void"].map(r =>
`<option value="${r}" ${p.result === r ? "selected" : ""}>${r}</option>`).join("")}
</select>
</td>
</tr>`).join("") : `<tr><td colspan="4">Hakuna utabiri bado.</td></tr>`;
}
$("rows").onclick = async e => {
const btn = e.target.closest("[data-pub]");
if (!btn) return;
const id = btn.dataset.pub;
const nowPublished = btn.dataset.on !== "true";
const { data: current } = await sb.from("predictions").select("published_at").eq("id", id).single();
const { error } = await sb.from("predictions").update({
published: nowPublished,
// Tarehe ya kwanza ya kuchapisha inabaki, haibadilishwi
published_at: nowPublished ? (current.published_at || new Date().toISOString()) : current.published_at
}).eq("id", id);
if (error) return say("rMsg", error.message, false);
loadPredictions();
};
$("rows").onchange = async e => {
const sel = e.target.closest("[data-res]");
if (!sel) return;
const { error } = await sb.from("predictions").update({ result: sel.value }).eq("id", sel.dataset.res);
if (error) return say("rMsg", error.message, false);
say("rMsg", "Matokeo yamehifadhiwa βœ”");
};
</script>
</body></html>