Changeset 015ce46 in Klonkt


Ignore:
Timestamp:
06/21/2026 04:32:54 PM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
9effb80
Parents:
5a394e5
Message:

fix(inplannen): scheduled posts never went live + timezone bug

(1) Scheduler compared publish_at (ISO 'T..Z') string-wise with SQLite
CURRENT_TIMESTAMP ('YYYY-MM-DD HH:MM:SS'); because 'T' > space the condition
was never true → scheduled posts NEVER flipped to published. Now
datetime(publish_at) <= datetime('now') (both UTC, same format).
(2) datetime-local was stored as UTC without timezone → 18:10 CEST became
18:10 UTC (= 20:10 local). Now: client converts local input to UTC ISO on save,
pre-fills the field from UTC→local, and shows "Scheduled for" in readable local
time instead of raw UTC ISO.

Co-Authored-By: Claude <noreply@…>

Location:
src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/services/Scheduler.js

    r5a394e5 r015ce46  
    1616      SELECT p.id, p.title, p.content, u.username
    1717      FROM posts p JOIN users u ON u.id = p.author_id
    18       WHERE p.status = 'scheduled' AND p.publish_at IS NOT NULL AND p.publish_at <= CURRENT_TIMESTAMP
     18      WHERE p.status = 'scheduled' AND p.publish_at IS NOT NULL AND datetime(p.publish_at) <= datetime('now')
    1919    `).all();
    2020    if (!due.length) return 0;
  • src/services/i18n.js

    r5a394e5 r015ce46  
    729729    'pedit.publish_at_label': 'Datum & tijd',
    730730    'pedit.scheduled_for': 'Ingepland voor {d}',
     731    'pedit.scheduled_prefix': 'Ingepland voor',
    731732    'pedit.cancel': 'Annuleren',
    732733    'pedit.publish': 'Publish',
     
    16871688    'pedit.publish_at_label': 'Date & time',
    16881689    'pedit.scheduled_for': 'Scheduled for {d}',
     1690    'pedit.scheduled_prefix': 'Scheduled for',
    16891691    'pedit.cancel': 'Cancel',
    16901692    'pedit.publish': 'Publish',
     
    26452647    'pedit.publish_at_label': 'Datum & Uhrzeit',
    26462648    'pedit.scheduled_for': 'Geplant für {d}',
     2649    'pedit.scheduled_prefix': 'Geplant für',
    26472650    'pedit.cancel': 'Abbrechen',
    26482651    'pedit.publish': 'Veröffentlichen',
  • src/views/pages/post-edit.ejs

    r5a394e5 r015ce46  
    215215          <div id="pe-sched-fields" style="margin-top:6px;<%= _scheduled ? '' : 'display:none' %>">
    216216            <label style="display:block;font-size:12.5px;opacity:.8;margin-bottom:4px"><%= t('pedit.publish_at_label') %></label>
    217             <input type="datetime-local" name="publish_at" <%= _scheduled ? '' : 'disabled' %> value="<%= post.publish_at ? String(post.publish_at).replace(' ','T').slice(0,16) : '' %>" style="padding:8px 10px;border-radius:8px;border:1px solid var(--rule,rgba(128,128,128,.4));background:transparent;color:inherit">
    218             <% if (post.status === 'scheduled' && post.publish_at) { %><div style="font-size:12px;opacity:.7;margin-top:4px">⏳ <%= t('pedit.scheduled_for', { d: post.publish_at }) %></div><% } %>
     217            <input type="datetime-local" id="pe-publish-at" name="publish_at" <%= _scheduled ? '' : 'disabled' %> data-iso="<%= post.publish_at || '' %>" value="" style="padding:8px 10px;border-radius:8px;border:1px solid var(--rule,rgba(128,128,128,.4));background:transparent;color:inherit">
     218            <% if (post.status === 'scheduled' && post.publish_at) { %><div style="font-size:12px;opacity:.7;margin-top:4px"><span id="pe-sched-when" data-iso="<%= post.publish_at %>" data-label="<%= t('pedit.scheduled_prefix') %>">⏳ <%= t('pedit.scheduled_for', { d: post.publish_at }) %></span></div><% } %>
    219219            <div style="font-size:11.5px;opacity:.65;margin-top:4px"><%= t('pedit.schedule_hint') %></div>
    220220          </div>
     
    224224              var box = document.getElementById('pe-sched-fields');
    225225              if (!cb || !box) return;
    226               var inp = box.querySelector('input[name="publish_at"]');
     226              var inp = document.getElementById('pe-publish-at');
     227              var pad = function (n) { return String(n).padStart(2, '0'); };
     228              // Prefill: opgeslagen UTC → lokale datetime-local-waarde (zodat je je
     229              // eigen tijdzone ziet, niet UTC).
     230              if (inp && inp.dataset.iso) {
     231                var d0 = new Date(inp.dataset.iso);
     232                if (!isNaN(d0)) inp.value = d0.getFullYear() + '-' + pad(d0.getMonth() + 1) + '-' + pad(d0.getDate()) + 'T' + pad(d0.getHours()) + ':' + pad(d0.getMinutes());
     233              }
     234              // "Ingepland voor" in leesbare lokale tijd i.p.v. ruwe UTC-ISO.
     235              var when = document.getElementById('pe-sched-when');
     236              if (when && when.dataset.iso) {
     237                var dw = new Date(when.dataset.iso);
     238                if (!isNaN(dw)) when.textContent = '⏳ ' + when.dataset.label + ' ' + dw.toLocaleString();
     239              }
    227240              function sync() { box.style.display = cb.checked ? '' : 'none'; if (inp) inp.disabled = !cb.checked; }
    228241              cb.addEventListener('change', sync); sync();
     242              // Bij opslaan: lokale invoer → UTC-ISO via een hidden veld, zodat de
     243              // server de juiste tijd opslaat (datetime-local heeft geen tijdzone).
     244              var form = cb.closest('form');
     245              if (form) {
     246                form.addEventListener('submit', function () {
     247                  if (inp) inp.removeAttribute('name');
     248                  var old = form.querySelector('input[data-pa-utc]');
     249                  if (old) old.remove();
     250                  if (cb.checked && inp && inp.value) {
     251                    var d2 = new Date(inp.value); // geïnterpreteerd in browser-tijdzone
     252                    if (!isNaN(d2)) {
     253                      var h = document.createElement('input');
     254                      h.type = 'hidden'; h.name = 'publish_at'; h.setAttribute('data-pa-utc', '');
     255                      h.value = d2.toISOString();
     256                      form.appendChild(h);
     257                    }
     258                  }
     259                });
     260              }
    229261            })();
    230262          </script>
Note: See TracChangeset for help on using the changeset viewer.