Kopioi ostoslista -nappi + tykkäysten localStorage-muisti

- Ainesluettelon vieressä 'Kopioi ostoslista' -nappi: kopioi
  julkaisun nimen ja ainesosat ostoslistamuodossa leikepöydälle
- Tykkäykset tallennetaan localStorage:en — muistetaan vaikka
  PHP-sessio vanhenisi (selain muistaa oman tykkäyshistoriansa)
- Latauksessa yhdistetään server-sessio ja localStorage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 01:39:36 +02:00
parent 4c5b275225
commit 5fa93a49ad

View File

@@ -127,6 +127,8 @@ async function toggleLike(id) {
} else { } else {
APP.userLikes = APP.userLikes.filter(x => x !== id); APP.userLikes = APP.userLikes.filter(x => x !== id);
} }
// Persist to localStorage so likes survive session expiry
saveLocalLikes(APP.userLikes);
// Update all like buttons for this post (card + modal) // Update all like buttons for this post (card + modal)
document.querySelectorAll(`[data-like-id="${id}"]`).forEach(btn => { document.querySelectorAll(`[data-like-id="${id}"]`).forEach(btn => {
@@ -247,7 +249,10 @@ async function openPost(id) {
const stps = p.steps?.length const stps = p.steps?.length
? `<ol>${p.steps.map(s => `<li>${s}</li>`).join('')}</ol>` ? `<ol>${p.steps.map(s => `<li>${s}</li>`).join('')}</ol>`
: `<p class="empty-note">${t('no_steps')}</p>`; : `<p class="empty-note">${t('no_steps')}</p>`;
bodyHTML = `<h3>${t('modal_ingredients')}</h3>${ings}<h3>${t('modal_steps')}</h3>${stps}`; const copyBtn = p.ingredients?.length
? `<button class="copy-list-btn" onclick="copyIngredients('${p.id}')" style="margin-left:10px;padding:4px 12px;font-size:0.82rem;border:1px solid #ccc;background:#fff;border-radius:20px;cursor:pointer;">📋 Kopioi ostoslista</button>`
: '';
bodyHTML = `<div style="display:flex;align-items:center;flex-wrap:wrap;gap:6px;margin-bottom:2px"><h3 style="margin:0">${t('modal_ingredients')}</h3>${copyBtn}</div>${ings}<h3>${t('modal_steps')}</h3>${stps}`;
} else { } else {
bodyHTML = `<div class="post-body">${p.body || p.desc}</div>`; bodyHTML = `<div class="post-body">${p.body || p.desc}</div>`;
} }
@@ -557,6 +562,29 @@ function handleSubmit(e) {
// =========================== // ===========================
// INIT // INIT
// ===========================
// COPY INGREDIENTS
// ===========================
function copyIngredients(postId) {
const p = APP.posts.find(x => x.id === postId);
if (!p?.ingredients?.length) return;
const text = p.title + '\n\nOstoslista:\n' + p.ingredients.map(i => '• ' + i).join('\n');
navigator.clipboard.writeText(text).then(() => {
const btn = document.querySelector('.copy-list-btn');
if (btn) { btn.textContent = '✅ Kopioitu!'; setTimeout(() => { btn.textContent = '📋 Kopioi ostoslista'; }, 2000); }
}).catch(() => {});
}
// ===========================
// LOCAL LIKES PERSISTENCE
// ===========================
function getLocalLikes() {
try { return JSON.parse(localStorage.getItem('tykkaafi_likes') || '[]'); } catch { return []; }
}
function saveLocalLikes(arr) {
try { localStorage.setItem('tykkaafi_likes', JSON.stringify(arr)); } catch {}
}
// =========================== // ===========================
async function init() { async function init() {
try { try {
@@ -568,7 +596,10 @@ async function init() {
APP.posts = postsData.posts || []; APP.posts = postsData.posts || [];
APP.categories = catsData.categories || []; APP.categories = catsData.categories || [];
APP.likes = likesData.likes || {}; APP.likes = likesData.likes || {};
APP.userLikes = likesData.userLikes || []; // Merge server session likes with localStorage — remember likes across sessions
const serverLikes = likesData.userLikes || [];
const localLikes = getLocalLikes();
APP.userLikes = [...new Set([...serverLikes, ...localLikes])];
} catch (e) { } catch (e) {
console.error('API virhe:', e); console.error('API virhe:', e);
} }