// Page Code import wixData from 'wix-data'; import wixUsers from 'wix-users'; let parByHole = Array(18).fill(null); let scoreByHole = Array(18).fill(null); let scorecardUrl = ''; $w.onReady(() => { // Build 18 rows for the repeater const holes = Array.from({ length: 18 }, (_, i) => ({ _id: String(i+1), hole: i + 1 })); $w('#holesRepeater').data = holes; $w('#holesRepeater').onItemReady(($item, itemData) => { const idx = itemData.hole - 1; $item('#holeLabel').text = `Hole ${itemData.hole}`; // Keep inputs numeric $item('#parInput').placeholder = 'Par'; $item('#scoreInput').placeholder = 'Score'; // Initialize from arrays (if user navigates back, etc.) if (parByHole[idx] !== null) $item('#parInput').value = String(parByHole[idx]); if (scoreByHole[idx] !== null) $item('#scoreInput').value = String(scoreByHole[idx]); // Update arrays on change $item('#parInput').onInput(() => { parByHole[idx] = toNum($item('#parInput').value); }); $item('#scoreInput').onInput(() => { scoreByHole[idx] = toNum($item('#scoreInput').value); updateFinalScore(); }); }); // Handle file upload $w('#scorecardUpload').onChange(async () => { if ($w('#scorecardUpload').value.length === 0) return; setStatus('Uploading scorecard...', false); try { const file = await $w('#scorecardUpload').startUpload(); scorecardUrl = file.url; // public URL setStatus('Scorecard uploaded ✅', false); } catch (e) { setStatus('Upload failed. Try again.', true); scorecardUrl = ''; } }); // Submit handler $w('#submitBtn').onClick(async () => { clearStatus(); // Must be logged in (optional—remove if you want public) const user = wixUsers.currentUser; if (!user.loggedIn) { setStatus('Please sign in to submit a round.', true); return; } // Validate const dateVal = $w('#roundDate').value; const course = ($w('#courseName').value || '').trim(); if (!dateVal || !course) { setStatus('Add a date and course name.', true); return; } // Ensure 18 scores present if (!all18(scoreByHole)) { setStatus('Please enter a score for all 18 holes.', true); return; } // Optional: require par too if (!all18(parByHole)) { setStatus('Please enter par for all 18 holes.', true); return; } const finalScore = sumArray(scoreByHole); // Build record const email = await user.getEmail() .catch(() => ''); const toSave = { memberId: user.id, memberEmail: email || '', roundDate: dateVal, courseName: course, parByHole: parByHole.map(n => n ?? 0), scoreByHole: scoreByHole.map(n => n ?? 0), finalScore, scorecardUrl }; // Save try { await wixData.insert('GolfRounds', toSave); setStatus(`Saved! Final Score: ${finalScore}`, false); resetForm(); } catch (e) { setStatus('Could not save. Please try again.', true); console.error(e); } }); }); // Helpers function toNum(v) { const n = Number(String(v).replace(/[^\d.-]/g, '')); return Number.isFinite(n) ? n : null; } function sumArray(arr) { return arr.reduce((a, b) => a + (Number.isFinite(b) ? b : 0), 0); } function all18(arr) { return arr.length === 18 && arr.every(n => Number.isFinite(n)); } function updateFinalScore() { const total = sumArray(scoreByHole); $w('#finalScoreText').text = Number.isFinite(total) && total > 0 ? `Running Total: ${total}` : 'Running Total: —'; } function setStatus(msg, isError) { $w('#statusText').text = msg; $w('#statusText').show(); $w('#statusText').style.color = isError ? '#B00020' : '#146C43'; } function clearStatus() { $w('#statusText').text = ''; $w('#statusText').hide(); } function resetForm() { $w('#roundDate').value = null; $w('#courseName').value = ''; parByHole = Array(18).fill(null); scoreByHole = Array(18).fill(null); scorecardUrl = ''; $w('#scorecardUpload').value = []; // clears UI $w('#holesRepeater').forEachItem(($item, itemData) => { $item('#parInput').value = ''; $item('#scoreInput').value = ''; }); updateFinalScore(); }
top of page
  • Instagram

2025 LEADERBOARD

League_Ranking August.png

LEAGUE FORMAT

1. 7-month long season with one official score submitted each month per player. Opening round is held in person to set initial scores and set initial vibes! Next five months are played at each player's discretion as long as they play with another club member to verify scores. Final month is the in-person championship to finalize the club champion and solidify the season's success!

2. Only legit courses allowed —must have a slope rating of 118 or higher. No short tracks or par-3 courses where even your grandma could go low.

3. Each player earns points for each monthly round based on a hole-by-hole stableford scoring:

    o Triple+ Bogey: 0 pts

    o Double Bogey: 1 pt

    o Bogey: 2 pts 

    o Par: 3 pts

    o Birdie: 4 pts

    o Eagle: 5 pts

    o Albatross: 8 pts

    o Hole-In-One: 10 pts

4. Average of all players' net scores will set the handicap baseline for the following month's round (e.g. If the average score of all golfers is 100 and you scored 101, your handicap the following month will be a 1, meaning you earn one stroke less on the following month's score to help push you up the standings.

5. Bonus points awarded for players who place in the top 3 each month:

    o 1st Place: +15 pts

    o 2nd Place: +10 pts

    o 3rd Place: +5 pts

6. Handicaps update monthly based on how you stack up to the rest of the crew. Ties = same adjustment. No round? No update.

Dirty_Birdie_Lettering_2-nobg.png

                                                             © 2025 by Dirty Birdie Golf Club

bottom of page