Refactor database handling to require PostgreSQL connection, removing fallback to JSON. Implement error handling for database unavailability in key files. Update .env.example to reflect mandatory DATABASE_URL for local development. Remove Firebase configuration and related code from the project.

This commit is contained in:
2026-05-23 10:23:28 +02:00
parent 547778bba5
commit 6577db475a
20 changed files with 823 additions and 789 deletions
+16 -92
View File
@@ -61,37 +61,23 @@
})();
// ── Newsletter subscription logic ──────────────────────────
// ── Newsletter (mailto) ────────────────────────────────────
function handleSubscribe(e) {
e.preventDefault();
var emailInput = document.getElementById('newsletterEmail');
var feedback = document.getElementById('newsletterFeedback');
var form = document.getElementById('newsletterForm');
var btn = form.querySelector('button');
var email = emailInput.value.trim();
if (!email) return;
btn.disabled = true;
feedback.className = 'newsletter-feedback';
feedback.textContent = '';
var subject = encodeURIComponent('FlixCooks Newsletter');
var body = encodeURIComponent('Please add me to the newsletter: ' + email);
window.location.href = 'mailto:<?php echo e($contactEmail); ?>?subject=' + subject + '&body=' + body;
window.db.collection('subscribers').doc(email.toLowerCase()).set({
email: email.toLowerCase(),
subscribedAt: firebase.firestore.FieldValue.serverTimestamp(),
status: 'active'
})
.then(function() {
form.classList.add('success');
emailInput.disabled = true;
feedback.className = 'newsletter-feedback success';
feedback.textContent = '<?php echo $langCode === "de" ? "Erfolgreich abonniert!" : "Successfully subscribed!"; ?>';
})
.catch(function(error) {
btn.disabled = false;
feedback.className = 'newsletter-feedback error';
feedback.textContent = '<?php echo $langCode === "de" ? "Fehler: " : "Error: "; ?>' + error.message;
});
form.classList.add('success');
feedback.className = 'newsletter-feedback success';
feedback.textContent = '<?php echo $langCode === "de" ? "E-Mail-Programm geöffnet bitte absenden." : "Email client opened — please send."; ?>';
}
// ── Guest Modal Logic ──────────────────────────────────────
@@ -121,33 +107,12 @@ document.addEventListener('click', function(e) {
}
});
// ── Favorites Toggle & Management ───────────────────────────
var currentUser = null;
var userFavSlugs = new Set();
function syncFavorites(uid) {
window.db.collection('user_favorites').where('userId', '==', uid).get()
.then(function(snapshot) {
userFavSlugs.clear();
snapshot.forEach(function(doc) {
userFavSlugs.add(doc.data().recipeSlug);
});
updateHeartStates();
})
.catch(function(err) {
console.error("Error syncing favorites: ", err);
});
}
function clearFavorites() {
userFavSlugs.clear();
updateHeartStates();
}
// ── Favorites (localStorage) ───────────────────────────────
function updateHeartStates() {
if (!window.fcLocal) return;
document.querySelectorAll('.btn-favorite').forEach(function(btn) {
var slug = btn.getAttribute('data-slug');
if (userFavSlugs.has(slug)) {
if (slug && window.fcLocal.hasFavorite(slug)) {
btn.classList.add('active');
} else {
btn.classList.remove('active');
@@ -156,43 +121,12 @@ function updateHeartStates() {
}
function toggleFavorite(slug, btn) {
if (!currentUser) {
if (!window.fcLocal) {
openGuestModal();
return;
}
var docId = currentUser.uid + '_' + slug;
var docRef = window.db.collection('user_favorites').doc(docId);
if (userFavSlugs.has(slug)) {
// Optimistic UI update
userFavSlugs.delete(slug);
btn.classList.remove('active');
docRef.delete()
.catch(function(err) {
console.error("Error removing favorite: ", err);
// Rollback
userFavSlugs.add(slug);
btn.classList.add('active');
});
} else {
// Optimistic UI update
userFavSlugs.add(slug);
btn.classList.add('active');
docRef.set({
userId: currentUser.uid,
recipeSlug: slug,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
})
.catch(function(err) {
console.error("Error adding favorite: ", err);
// Rollback
userFavSlugs.delete(slug);
btn.classList.remove('active');
});
}
window.fcLocal.toggleFavorite(slug);
updateHeartStates();
}
// Hook up event listeners to all favorite buttons dynamically
@@ -206,18 +140,8 @@ document.addEventListener('click', function(e) {
}
});
// Setup Auth state observer for favorites
window.addEventListener('DOMContentLoaded', function() {
if (window.auth) {
window.auth.onAuthStateChanged(function(user) {
currentUser = user;
if (user) {
syncFavorites(user.uid);
} else {
clearFavorites();
}
});
}
updateHeartStates();
});
})();
</script>
@@ -228,10 +152,10 @@ window.addEventListener('DOMContentLoaded', function() {
<button class="guest-modal-close" onclick="closeGuestModal()" aria-label="Close modal">×</button>
<div class="guest-modal-icon">❤️</div>
<h3><?php echo $langCode === 'de' ? 'Lieblingsrezept speichern' : 'Save your favorite recipe'; ?></h3>
<p><?php echo $langCode === 'de' ? 'Erstelle ein kostenloses Konto oder melde dich an, um Rezepte in deinen Favoriten zu speichern und deine Ernährungsziele zu verwalten.' : 'Create a free account or login to save recipes to your favorites and manage your dietary goals.'; ?></p>
<p><?php echo $langCode === 'de' ? 'Speichere Rezepte lokal in deinem Browser und verwalte dein Ernährungsziel im Profil.' : 'Save recipes locally in your browser and manage your dietary goal in your profile.'; ?></p>
<div class="guest-modal-actions">
<a class="btn-reveal" href="/login.php<?php echo $langSuffix; ?>">
<span class="btn-reveal-text"><?php echo $langCode === 'de' ? 'Jetzt Anmelden' : 'Login / Register'; ?></span>
<span class="btn-reveal-text"><?php echo $langCode === 'de' ? 'Zum Profil' : 'Go to profile'; ?></span>
<span class="btn-reveal-arrow">→</span>
</a>
<button class="underline-link" onclick="closeGuestModal()"><?php echo $langCode === 'de' ? 'Später' : 'Maybe later'; ?></button>