Add custom activity support and clear booking data on submission
This commit is contained in:
@@ -96,6 +96,43 @@
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
.custom-activity-section {
|
||||
margin-top: 16px;
|
||||
background: var(--color-white);
|
||||
border: 2px solid var(--color-rose);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 16px;
|
||||
box-shadow: var(--shadow-soft);
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
.custom-activity-label {
|
||||
display: block;
|
||||
font-family: var(--font-heading);
|
||||
font-weight: 700;
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-rose-dark);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.custom-activity-input {
|
||||
width: 100%;
|
||||
padding: 12px 14px;
|
||||
font-family: var(--font-body);
|
||||
font-size: 1rem;
|
||||
color: var(--color-text);
|
||||
background: var(--color-bg);
|
||||
border: 2px solid var(--color-peach);
|
||||
border-radius: var(--radius-md);
|
||||
outline: none;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.custom-activity-input:focus {
|
||||
border-color: var(--color-rose);
|
||||
box-shadow: 0 0 0 3px rgba(224, 87, 126, 0.2);
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,18 @@
|
||||
</div>
|
||||
|
||||
<div class="activity-grid" id="activityGrid"></div>
|
||||
|
||||
<div id="customActivitySection" class="custom-activity-section hidden">
|
||||
<label for="customActivityInput" class="custom-activity-label">Was möchtest du unternehmen? ✏️</label>
|
||||
<input
|
||||
type="text"
|
||||
id="customActivityInput"
|
||||
class="custom-activity-input"
|
||||
placeholder="Beschreibung der Aktivität eingeben..."
|
||||
maxlength="150"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="continue-bar">
|
||||
|
||||
+148
-35
@@ -5,6 +5,8 @@
|
||||
const dateSummary = document.getElementById("dateSummary");
|
||||
const timeNotice = document.getElementById("timeNotice");
|
||||
const continueBtn = document.getElementById("continueBtn");
|
||||
const customActivitySection = document.getElementById("customActivitySection");
|
||||
const customActivityInput = document.getElementById("customActivityInput");
|
||||
|
||||
const selectedDate = localStorage.getItem("selectedDate");
|
||||
const selectedDateType = localStorage.getItem("selectedDateType") || "long";
|
||||
@@ -26,15 +28,59 @@
|
||||
let availableActivities = [];
|
||||
let selectedList = [];
|
||||
|
||||
function isCustomActivity(act) {
|
||||
return act && (act.name === "Etwas eigenes" || act.name === "Sonstiges" || act.type === "custom");
|
||||
}
|
||||
|
||||
fetch("appsettings.json")
|
||||
.then((response) => response.json())
|
||||
.then((settings) => {
|
||||
const allActivities = settings.activities || [];
|
||||
|
||||
const customAct = allActivities.find((a) => a.name === "Etwas eigenes" || a.name === "Sonstiges") || {
|
||||
name: "Etwas eigenes",
|
||||
icon: "✏️",
|
||||
type: "custom",
|
||||
};
|
||||
|
||||
let otherActivities = allActivities.filter((a) => a.name !== "Etwas eigenes" && a.name !== "Sonstiges");
|
||||
if (selectedDateType === "short") {
|
||||
availableActivities = allActivities.filter((a) => a.type === "short");
|
||||
} else {
|
||||
availableActivities = allActivities;
|
||||
otherActivities = otherActivities.filter((a) => a.type === "short");
|
||||
}
|
||||
|
||||
// "Etwas eigenes" erscheint IMMER an letzter Stelle
|
||||
availableActivities = [...otherActivities, customAct];
|
||||
|
||||
// Vorherige Auswahl wiederherstellen, falls vorhanden
|
||||
try {
|
||||
const stored = JSON.parse(localStorage.getItem("selectedActivities") || "[]");
|
||||
if (stored && stored.length > 0) {
|
||||
const isStoredCustom = stored.some(
|
||||
(a) => a.type === "custom" || (a.name && (a.name.startsWith("Etwas eigenes") || a.name.startsWith("Sonstiges")))
|
||||
);
|
||||
if (isStoredCustom) {
|
||||
const storedCustom = stored.find(
|
||||
(a) => a.type === "custom" || (a.name && (a.name.startsWith("Etwas eigenes") || a.name.startsWith("Sonstiges")))
|
||||
);
|
||||
selectedList = [customAct];
|
||||
if (storedCustom) {
|
||||
const desc =
|
||||
storedCustom.customDescription ||
|
||||
(storedCustom.name.includes(":")
|
||||
? storedCustom.name.split(":").slice(1).join(":").trim()
|
||||
: "");
|
||||
if (customActivityInput) {
|
||||
customActivityInput.value = desc;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selectedList = stored.filter((s) =>
|
||||
availableActivities.some((a) => a.name === s.name)
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
renderActivities();
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -43,20 +89,35 @@
|
||||
|
||||
function renderActivities() {
|
||||
activityGrid.innerHTML = "";
|
||||
const hasCustomSelected = selectedList.some(isCustomActivity);
|
||||
const hasShortSelected = selectedList.some((a) => a.type === "short");
|
||||
|
||||
if (hasCustomSelected) {
|
||||
if (customActivitySection) {
|
||||
customActivitySection.classList.remove("hidden");
|
||||
}
|
||||
} else {
|
||||
if (customActivitySection) {
|
||||
customActivitySection.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
availableActivities.forEach((activity) => {
|
||||
const card = document.createElement("button");
|
||||
card.type = "button";
|
||||
card.className = "activity-card";
|
||||
card.dataset.activity = activity.name;
|
||||
|
||||
const isSelected = selectedList.some((a) => a.name === activity.name);
|
||||
const isCustom = isCustomActivity(activity);
|
||||
const isSelected = isCustom
|
||||
? hasCustomSelected
|
||||
: selectedList.some((a) => a.name === activity.name);
|
||||
|
||||
if (isSelected) {
|
||||
card.classList.add("selected");
|
||||
}
|
||||
|
||||
const isLongDisabled = hasShortSelected && activity.type === "long";
|
||||
const isLongDisabled = !isCustom && hasShortSelected && activity.type === "long";
|
||||
if (isLongDisabled) {
|
||||
card.classList.add("is-disabled");
|
||||
card.disabled = true;
|
||||
@@ -84,31 +145,47 @@
|
||||
}
|
||||
|
||||
function handleCardClick(activity) {
|
||||
const isAlreadySelected = selectedList.some((a) => a.name === activity.name);
|
||||
const isCustom = isCustomActivity(activity);
|
||||
const hasCustomSelected = selectedList.some(isCustomActivity);
|
||||
|
||||
if (activity.type === "long") {
|
||||
if (isAlreadySelected) {
|
||||
if (isCustom) {
|
||||
if (hasCustomSelected) {
|
||||
selectedList = [];
|
||||
} else {
|
||||
// Custom-Aktivität darf mit keiner anderen Aktivität kombiniert werden!
|
||||
selectedList = [activity];
|
||||
setTimeout(() => {
|
||||
if (customActivityInput) {
|
||||
customActivityInput.focus();
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
} else {
|
||||
// Short activity
|
||||
if (isAlreadySelected) {
|
||||
selectedList = selectedList.filter((a) => a.name !== activity.name);
|
||||
} else if (selectedDateType === "short") {
|
||||
// An kurzen Tagen ist nur maximal eine kurze Aktivität erlaubt
|
||||
selectedList = [activity];
|
||||
} else {
|
||||
// An langen Tagen:
|
||||
// Falls vorher eine lange Aktivität gewählt war, ersetzen
|
||||
if (selectedList.some((a) => a.type === "long")) {
|
||||
selectedList = [activity];
|
||||
} else if (selectedList.length >= 2) {
|
||||
// Maximal 2 kurze Aktivitäten, die zweite ersetzen
|
||||
selectedList = [selectedList[0], activity];
|
||||
if (hasCustomSelected) {
|
||||
selectedList = [];
|
||||
}
|
||||
|
||||
const isAlreadySelected = selectedList.some((a) => a.name === activity.name);
|
||||
|
||||
if (activity.type === "long") {
|
||||
if (isAlreadySelected) {
|
||||
selectedList = [];
|
||||
} else {
|
||||
selectedList.push(activity);
|
||||
selectedList = [activity];
|
||||
}
|
||||
} else {
|
||||
if (isAlreadySelected) {
|
||||
selectedList = selectedList.filter((a) => a.name !== activity.name);
|
||||
} else if (selectedDateType === "short") {
|
||||
selectedList = [activity];
|
||||
} else {
|
||||
if (selectedList.some((a) => a.type === "long")) {
|
||||
selectedList = [activity];
|
||||
} else if (selectedList.length >= 2) {
|
||||
selectedList = [selectedList[0], activity];
|
||||
} else {
|
||||
selectedList.push(activity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,30 +193,66 @@
|
||||
renderActivities();
|
||||
}
|
||||
|
||||
if (customActivityInput) {
|
||||
customActivityInput.addEventListener("input", () => {
|
||||
updateNoticeAndContinue();
|
||||
});
|
||||
}
|
||||
|
||||
function updateNoticeAndContinue() {
|
||||
const hasCustomSelected = selectedList.some(isCustomActivity);
|
||||
const shortCount = selectedList.filter((a) => a.type === "short").length;
|
||||
const hasLong = selectedList.some((a) => a.type === "long");
|
||||
|
||||
if (selectedDateType === "long" && shortCount === 1 && !hasLong) {
|
||||
timeNotice.textContent =
|
||||
"💡 An diesem Tag haben wir reichlich Zeit! Wenn du möchtest, kannst du noch eine zweite kurze Aktivität auswählen.";
|
||||
timeNotice.classList.remove("hidden");
|
||||
} else if (selectedDateType === "long" && shortCount === 2) {
|
||||
timeNotice.textContent = "🎉 Perfekt! Du hast 2 kurze Aktivitäten für unseren Tag ausgewählt.";
|
||||
timeNotice.classList.remove("hidden");
|
||||
} else {
|
||||
if (hasCustomSelected) {
|
||||
timeNotice.classList.add("hidden");
|
||||
}
|
||||
const desc = customActivityInput ? customActivityInput.value.trim() : "";
|
||||
continueBtn.disabled = desc.length === 0;
|
||||
} else {
|
||||
if (selectedDateType === "long" && shortCount === 1 && !hasLong) {
|
||||
timeNotice.textContent =
|
||||
"💡 An diesem Tag haben wir reichlich Zeit! Wenn du möchtest, kannst du noch eine zweite kurze Aktivität auswählen.";
|
||||
timeNotice.classList.remove("hidden");
|
||||
} else if (selectedDateType === "long" && shortCount === 2) {
|
||||
timeNotice.textContent = "🎉 Perfekt! Du hast 2 kurze Aktivitäten für unseren Tag ausgewählt.";
|
||||
timeNotice.classList.remove("hidden");
|
||||
} else {
|
||||
timeNotice.classList.add("hidden");
|
||||
}
|
||||
|
||||
continueBtn.disabled = selectedList.length === 0;
|
||||
continueBtn.disabled = selectedList.length === 0;
|
||||
}
|
||||
}
|
||||
|
||||
continueBtn.addEventListener("click", () => {
|
||||
if (selectedList.length === 0) {
|
||||
return;
|
||||
}
|
||||
localStorage.setItem("selectedActivities", JSON.stringify(selectedList));
|
||||
localStorage.setItem("selectedActivity", selectedList.map((a) => a.name).join(" + "));
|
||||
|
||||
const hasCustomSelected = selectedList.some(isCustomActivity);
|
||||
|
||||
if (hasCustomSelected) {
|
||||
const customDesc = customActivityInput ? customActivityInput.value.trim() : "";
|
||||
if (!customDesc) {
|
||||
return;
|
||||
}
|
||||
|
||||
const customAct = selectedList.find(isCustomActivity);
|
||||
|
||||
const savedCustomAct = {
|
||||
name: customDesc,
|
||||
icon: customAct.icon || "✏️",
|
||||
type: "custom",
|
||||
customDescription: customDesc,
|
||||
};
|
||||
|
||||
localStorage.setItem("selectedActivities", JSON.stringify([savedCustomAct]));
|
||||
localStorage.setItem("selectedActivity", customDesc);
|
||||
} else {
|
||||
localStorage.setItem("selectedActivities", JSON.stringify(selectedList));
|
||||
localStorage.setItem("selectedActivity", selectedList.map((a) => a.name).join(" + "));
|
||||
}
|
||||
|
||||
window.location.href = "name.html";
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
{ "name": "Squash spielen", "icon": "🏸", "type": "short" },
|
||||
{ "name": "Essen im Namaste", "icon": "🍛", "type": "short" },
|
||||
{ "name": "Museum für Gegenwartskunst", "icon": "🖼️", "type": "short" },
|
||||
{ "name": "Playstation Co-Op", "icon": "🎮", "type": "short" }
|
||||
{ "name": "Playstation Co-Op", "icon": "🎮", "type": "short" },
|
||||
{ "name": "Etwas eigenes", "icon": "✏️", "type": "custom" }
|
||||
],
|
||||
"availableDates": [
|
||||
{ "date": "2026-08-11", "type": "short" },
|
||||
|
||||
+15
-10
@@ -10,7 +10,12 @@
|
||||
const activityIcon = document.getElementById("activityIcon");
|
||||
const checkoutBtn = document.getElementById("checkoutBtn");
|
||||
|
||||
const selectedActivity = localStorage.getItem("selectedActivity");
|
||||
function cleanPrefix(str) {
|
||||
if (!str) return "";
|
||||
return str.replace(/^(Etwas eigenes|Sonstiges):\s*/i, "");
|
||||
}
|
||||
|
||||
const selectedActivity = cleanPrefix(localStorage.getItem("selectedActivity"));
|
||||
const selectedDate = localStorage.getItem("selectedDate");
|
||||
const selectedName = localStorage.getItem("selectedName");
|
||||
|
||||
@@ -57,8 +62,12 @@
|
||||
checkoutBtn.textContent = "Wird übermittelt... 💌";
|
||||
|
||||
const payload = {
|
||||
activity: selectedActivity,
|
||||
activities: storedActivities,
|
||||
activity: cleanPrefix(selectedActivity),
|
||||
activities: storedActivities.map((a) => ({
|
||||
...a,
|
||||
name: cleanPrefix(a.name),
|
||||
customDescription: cleanPrefix(a.customDescription || a.name),
|
||||
})),
|
||||
date: selectedDate,
|
||||
dateType: localStorage.getItem("selectedDateType") || "long",
|
||||
name: selectedName,
|
||||
@@ -79,13 +88,9 @@
|
||||
})
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
try {
|
||||
const localBooked = JSON.parse(localStorage.getItem("bookedDates") || "[]");
|
||||
if (!localBooked.includes(selectedDate)) {
|
||||
localBooked.push(selectedDate);
|
||||
localStorage.setItem("bookedDates", JSON.stringify(localBooked));
|
||||
}
|
||||
} catch (e) {}
|
||||
// Alle lokal gespeicherten Daten (inkl. bookedDates und ausgewählter Werte) leeren,
|
||||
// damit bei der nächsten Buchung alles frisch geladen / neu ausgewählt wird.
|
||||
localStorage.clear();
|
||||
|
||||
summarySection.classList.add("hidden");
|
||||
if (backLink) {
|
||||
|
||||
Reference in New Issue
Block a user