File size: 6,010 Bytes
ffc4f43 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | <!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>
|