limoncello

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

app.js (4753B)


      1 'use strict';
      2 
      3 let daysOffset  = 0;
      4 let weekOffset  = 0;
      5 let monthOffset = 0;
      6 
      7 // Labels
      8 
      9 function updateDaysLabel() {
     10   const el  = document.getElementById('days-offset-label');
     11   const fwd = document.getElementById('days-forward-btn');
     12   el.textContent = daysOffset === 0 ? 'Today ±2' : daysOffset + 'd back';
     13   fwd.disabled   = daysOffset <= 0;
     14 }
     15 
     16 function updateWeekLabel() {
     17   const el  = document.getElementById('week-offset-label');
     18   const fwd = document.getElementById('week-forward-btn');
     19   if      (weekOffset === 0) el.textContent = 'This week';
     20   else if (weekOffset === 1) el.textContent = 'Last week';
     21   else                       el.textContent = weekOffset + ' weeks ago';
     22   fwd.disabled = weekOffset <= 0;
     23 }
     24 
     25 function updateMonthLabel() {
     26   const el  = document.getElementById('month-offset-label');
     27   const fwd = document.getElementById('month-forward-btn');
     28   if      (monthOffset === 0) el.textContent = 'This month';
     29   else if (monthOffset === 1) el.textContent = 'Last month';
     30   else                        el.textContent = monthOffset + ' months ago';
     31   fwd.disabled = monthOffset <= 0;
     32 }
     33 
     34 // Tiles
     35 
     36 async function fetchHTML(url, containerId) {
     37   const res  = await fetch(url);
     38   const html = await res.text();
     39   document.getElementById(containerId).innerHTML = html;
     40 }
     41 
     42 async function refreshAllTiles() {
     43   await Promise.all([
     44     fetchHTML('/tiles/days?offset='  + daysOffset,  'days-row'),
     45     fetchHTML('/tiles/week?offset='  + weekOffset,  'week-row'),
     46     fetchHTML('/tiles/month?offset=' + monthOffset, 'month-grid'),
     47   ]);
     48 }
     49 
     50 // Navigation
     51 
     52 async function shiftDays(dir) {
     53   const next = daysOffset + dir;
     54   if (next < 0) return;
     55   daysOffset = next;
     56   updateDaysLabel();
     57   await fetchHTML('/tiles/days?offset=' + daysOffset, 'days-row');
     58 }
     59 
     60 async function shiftWeek(dir) {
     61   const next = weekOffset + dir;
     62   if (next < 0) return;
     63   weekOffset = next;
     64   updateWeekLabel();
     65   await fetchHTML('/tiles/week?offset=' + weekOffset, 'week-row');
     66   document.getElementById('week-label').textContent =
     67     await (await fetch('/label/week?offset=' + weekOffset)).text();
     68 }
     69 
     70 async function shiftMonth(dir) {
     71   const next = monthOffset + dir;
     72   if (next < 0) return;
     73   monthOffset = next;
     74   updateMonthLabel();
     75   await fetchHTML('/tiles/month?offset=' + monthOffset, 'month-grid');
     76   document.getElementById('month-label').textContent =
     77     await (await fetch('/label/month?offset=' + monthOffset)).text();
     78 }
     79 
     80 // Days
     81 
     82 function openDay(date) {
     83   fetch('/modal?date=' + date)
     84     .then(r => r.text())
     85     .then(html => {
     86       document.body.insertAdjacentHTML('beforeend', html);
     87       updatePreview();
     88       document.getElementById('drink-volume').addEventListener('change', updatePreview);
     89       document.getElementById('drink-abv').addEventListener('input', updatePreview);
     90     });
     91 }
     92 
     93 function closeModal(e) {
     94   if (e.target.id === 'day-modal') {
     95     document.getElementById('day-modal').remove();
     96   }
     97 }
     98 
     99 function refreshModal(date) {
    100   const modal = document.getElementById('day-modal');
    101   if (!modal) return;
    102   fetch('/modal?date=' + date)
    103     .then(r => r.text())
    104     .then(html => {
    105       modal.remove();
    106       document.body.insertAdjacentHTML('beforeend', html);
    107       updatePreview();
    108       document.getElementById('drink-volume').addEventListener('change', updatePreview);
    109       document.getElementById('drink-abv').addEventListener('input', updatePreview);
    110     });
    111 }
    112 
    113 function updatePreview() {
    114   const volEl = document.getElementById('drink-volume');
    115   const abvEl = document.getElementById('drink-abv');
    116   const pre   = document.getElementById('abv-preview');
    117   if (!volEl || !abvEl || !pre) return;
    118   const ml  = parseInt(volEl.value, 10);
    119   const abv = parseFloat(abvEl.value);
    120   if (ml > 0 && abv > 0) {
    121     const u = (ml * abv / 1000).toFixed(2);
    122     pre.textContent = `= ${u} unit${u === '1.00' ? '' : 's'}`;
    123   } else {
    124     pre.textContent = '';
    125   }
    126 }
    127 
    128 // Drinks
    129 
    130 function post(url, params) {
    131   return fetch(url, {
    132     method: 'POST',
    133     headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    134     body: new URLSearchParams(params).toString(),
    135   });
    136 }
    137 
    138 async function addDrink(date) {
    139   const ml  = document.getElementById('drink-volume').value;
    140   const abv = document.getElementById('drink-abv').value;
    141   if (!ml || !abv || parseFloat(abv) <= 0) return;
    142   await post('/drink/add', { date, volume_ml: ml, abv });
    143   refreshModal(date);
    144   refreshAllTiles();
    145 }
    146 
    147 async function removeDrink(date, key) {
    148   await post('/drink/remove', { date, key });
    149   refreshModal(date);
    150   refreshAllTiles();
    151 }
    152 
    153 async function adjustDrink(date, key, delta) {
    154   await post('/drink/adjust', { date, key, delta });
    155   refreshModal(date);
    156   refreshAllTiles();
    157 }
    158 
    159 // Init
    160 updateDaysLabel();
    161 updateWeekLabel();
    162 updateMonthLabel();