My Leisure Profile & Preferences
My Interests
General Leisure Preferences
Discover Activity Ideas
Filter Activity Ideas (Uses preferences from Profile, or override below)
My Leisure Plan
My Wishlist / Activities to Plan
Drag these to the calendar, or click a calendar slot to add.Plan for Slot:
OR
Activity Log & Customization
Log Completed Leisure Activities
Go to "My Leisure Plan" tab, click on a planned item, and mark it as "Done" and rate it.
Recently Completed & Rated Activities:
Manage Custom Activity Library
Your Custom Activities:
No activities match your current filters/preferences. Try broadening your search or adding activities to your library!
'; return;} filtered.forEach(act => { const card = document.createElement('div'); card.className = 'lpa-activity-card'; card.style.borderColor = act.color || '#4ECDC4'; card.innerHTML = `${act.name}
${act.description || 'No description.'}
Category: ${act.interestCategory} | Budget: ${act.typicalBudget} | Energy: ${act.typicalEnergy}
Your wishlist is empty. Add activities from the "Discover" tab.
'; return;} lpa_wishlist.forEach(item => { const card = document.createElement('div'); card.className = 'lpa-activity-card'; card.draggable = true; card.dataset.activityId = item.id; // This should be the original activity ID from library card.dataset.activityName = item.name; card.dataset.activityColor = item.color || '#4ECDC4'; card.ondragstart = (ev) => { ev.dataTransfer.setData("text/plain", JSON.stringify({id: item.id, name: item.name, color: item.color})); }; card.innerHTML = `${item.name}
`; container.appendChild(card); }); } function lpa_removeFromWishlist(activityId, event){ if(event) event.stopPropagation(); lpa_wishlist = lpa_wishlist.filter(item => item.id !== activityId); lpa_saveData(); lpa_renderWishlistForPlanner(); } function lpa_populateModalActivitySelect() { const selectEl = document.getElementById('lpa-modalSelectActivity'); selectEl.innerHTML=''; lpa_wishlist.forEach(w => { // Prioritize wishlist const opt = document.createElement('option'); opt.value = `wishlist_${w.id}`; opt.textContent = `(Wishlist) ${w.name}`; opt.dataset.color = w.color; selectEl.appendChild(opt); }); lpa_getCombinedActivityLibrary().forEach(act => { if (!lpa_wishlist.find(w => w.id === act.id)) { // Add from library if not in wishlist const opt = document.createElement('option'); opt.value = act.id; opt.textContent = act.name; opt.dataset.color = act.color; selectEl.appendChild(opt); } }); } function lpa_renderPlannerGrid() { /* ... Renders the Mon-Sun grid for dropping/clicking ... */ const weekStartStr = document.getElementById('lpa-planWeekStart').value; if(!weekStartStr) return; document.getElementById('lpa-plannerWeekDisplay').textContent = `Week of ${new Date(weekStartStr+"T00:00:00").toLocaleDateString()}`; const thead = document.getElementById('lpa-plannerThead'); const tbody = document.getElementById('lpa-plannerTbody'); thead.innerHTML = ''; tbody.innerHTML = ''; const headerRow = thead.insertRow(); headerRow.insertCell().textContent = "Time"; const weekDates = []; const startDate = new Date(weekStartStr + "T00:00:00"); for(let i=0; i<7; i++) { const d = new Date(startDate); d.setDate(startDate.getDate() + i); weekDates.push(d.toISOString().split('T')[0]); const th = document.createElement('th'); th.textContent = `${whip_daysOfWeek[i]} (${d.getDate()})`; // Re-use whip_daysOfWeek headerRow.appendChild(th); } // Example slots: Morning, Afternoon, Evening (3 slots per day) const slotsOfDay = ["Morning (7-12)", "Afternoon (12-17)", "Evening (17-22)"]; // Conceptual slots const slotStartTimes = ["07:00", "12:00", "17:00"]; // For data-time slotsOfDay.forEach((slotName, slotIdx) => { const slotRow = tbody.insertRow(); slotRow.insertCell().textContent = slotName; weekDates.forEach(dateStr => { const cell = slotRow.insertCell(); cell.classList.add('lpa-planner-slot'); cell.dataset.date = dateStr; cell.dataset.time = slotStartTimes[slotIdx]; // Approximate start of slot cell.ondragover = (ev) => ev.preventDefault(); cell.ondrop = (ev) => { ev.preventDefault(); const activityData = JSON.parse(ev.dataTransfer.getData("text/plain")); lpa_addDroppedItemToSchedule(activityData, dateStr, slotStartTimes[slotIdx]); }; cell.onclick = () => lpa_openPlannerSlotModal(dateStr, slotStartTimes[slotIdx]); // Render items for this date and conceptual slot lpa_plannedItems.filter(item => item.date === dateStr && item.slotMarker === slotStartTimes[slotIdx]).forEach(item => { lpa_renderPlannerItemInCell(cell, item); }); }); }); lpa_clearAndRerenderPlannerItems(); // Ensure all existing items are drawn correctly } function lpa_renderPlannerItemInCell(cell, item) { const itemDiv = document.createElement('div'); itemDiv.className = 'lpa-planned-item'; itemDiv.style.backgroundColor = item.color || '#4ECDC4'; itemDiv.innerHTML = `${item.name}${item.startTime || ''} (${item.durationMinutes}m) `; itemDiv.title = `${item.name} - ${item.notes || ''}`; itemDiv.onclick = (e) => { e.stopPropagation(); lpa_editPlannerItem(item.id); }; cell.appendChild(itemDiv); } function lpa_clearAndRerenderPlannerItems(){ document.querySelectorAll('.lpa-planner-slot').forEach(slot => slot.innerHTML = ''); // Clear existing items visually lpa_plannedItems.forEach(item => { const cell = document.querySelector(`.lpa-planner-slot[data-date="${item.date}"][data-time="${item.slotMarker}"]`); if(cell) lpa_renderPlannerItemInCell(cell, item); }); } function lpa_addDroppedItemToSchedule(activityData, date, slotStartTime) { const plannedItem = { id: lpa_generateId(), activityId: activityData.id.startsWith('custom_') ? null : activityData.id, // original library ID or null for pure custom customActivityName: activityData.id.startsWith('custom_') ? activityData.name : null, name: activityData.name, // Display name date: date, startTime: slotStartTime, // Or prompt user for specific time within slot slotMarker: slotStartTime, // For matching cell durationMinutes: 60, // Default, user can edit notes: '', isDone: false, enjoymentRating: null, color: activityData.color || '#4ECDC4' }; lpa_plannedItems.push(plannedItem); // Remove from wishlist if it was a wishlist item if (activityData.id) { // Only if it had an ID (was from lib or wishlist) lpa_wishlist = lpa_wishlist.filter(w => w.id !== activityData.id); lpa_renderWishlistForPlanner(); } lpa_saveData(); lpa_clearAndRerenderPlannerItems(); // Use specific cell update } function lpa_openPlannerSlotModal(date, time, itemId = null) { const modal = document.getElementById('lpa-plannerSlotModal'); document.getElementById('lpa-slotModalDateTime').textContent = `${new Date(date+"T00:00:00").toLocaleDateString()} - Slot: ${time}`; document.getElementById('lpa-modalSlotFullDate').value = date; document.getElementById('lpa-modalSlotActualTime').value = time; // Set as default start document.getElementById('lpa-editingScheduledItemId').value = itemId || ''; document.getElementById('lpa-modalDeleteBtn').style.display = itemId ? 'inline-block' : 'none'; lpa_populateModalActivitySelect(); // Repopulate based on current wishlist/library if(itemId) { const item = lpa_plannedItems.find(i => i.id === itemId); if(item) { if(item.activityId && !item.customActivityName) document.getElementById('lpa-modalSelectActivity').value = item.activityId.startsWith('wishlist_') ? item.activityId : item.activityId; // if wishlist it has prefix else document.getElementById('lpa-modalSelectActivity').value = ''; document.getElementById('lpa-modalCustomActivityName').value = item.customActivityName || (item.type === 'hobbyAction' ? '' : item.name); document.getElementById('lpa-modalActivityNotes').value = item.notes || ''; document.getElementById('lpa-modalActivityStartTime').value = item.startTime || time; document.getElementById('lpa-modalActivityDuration').value = item.durationMinutes || 60; } } else { // New item document.getElementById('lpa-modalSelectActivity').value = ''; document.getElementById('lpa-modalCustomActivityName').value = ''; document.getElementById('lpa-modalActivityNotes').value = ''; document.getElementById('lpa-modalActivityStartTime').value = time; // Default to slot start time document.getElementById('lpa-modalActivityDuration').value = 60; } modal.style.display = 'block'; } function lpa_savePlannedActivity() { const id = document.getElementById('lpa-editingScheduledItemId').value; const date = document.getElementById('lpa-modalSlotFullDate').value; const startTime = document.getElementById('lpa-modalActivityStartTime').value; const duration = parseInt(document.getElementById('lpa-modalActivityDuration').value); const notes = document.getElementById('lpa-modalActivityNotes').value; const selectedActivityOpt = document.getElementById('lpa-modalSelectActivity'); const selectedActivityVal = selectedActivityOpt.value; const customName = document.getElementById('lpa-modalCustomActivityName').value.trim(); if ((!selectedActivityVal && !customName) || !startTime || isNaN(duration) || duration <= 0) { alert("Please select an activity or enter a custom name, and provide valid start time & duration."); return; } let activityId = null, name, color; if (selectedActivityVal) { if (selectedActivityVal.startsWith('wishlist_')) { // From wishlist const originalId = selectedActivityVal.replace('wishlist_',''); const wishlistItem = lpa_wishlist.find(w => w.id === originalId); if (wishlistItem) { activityId = originalId; name = wishlistItem.name; color = wishlistItem.color; } else { // Fallback: search full library const libItem = lpa_getCombinedActivityLibrary().find(a=>a.id === originalId); if(libItem) {activityId = originalId; name=libItem.name; color=libItem.color;} } } else { // Directly from library const libItem = lpa_getCombinedActivityLibrary().find(a=>a.id === selectedActivityVal); if(libItem) {activityId = libItem.id; name=libItem.name; color=libItem.color;} } if (!name && customName) name = customName; // If selected but want to override name else if (!name && !customName) {alert("Error identifying selected activity."); return;} } else { // Custom entry name = customName; color = '#80CBC4'; // Default color for custom entries in planner } const slotMarker = document.getElementById('lpa-modalSlotActualTime').value; // The original slot time for cell placement const plannedItem = { id: id || lpa_generateId(), activityId, customActivityName: (selectedActivityVal ? null : name), name, date, startTime, slotMarker, durationMinutes: duration, notes, isDone: false, enjoymentRating: null, color }; if(id) lpa_plannedItems = lpa_plannedItems.map(pi => pi.id === id ? plannedItem : pi); else lpa_plannedItems.push(plannedItem); // If activity was from wishlist and now planned, remove from wishlist. if(selectedActivityVal && selectedActivityVal.startsWith('wishlist_')){ const originalIdToRemove = selectedActivityVal.replace('wishlist_',''); lpa_wishlist = lpa_wishlist.filter(w => w.id !== originalIdToRemove); lpa_renderWishlistForPlanner(); } lpa_saveData(); lpa_clearAndRerenderPlannerItems(); document.getElementById('lpa-plannerSlotModal').style.display = 'none'; } function lpa_deleteFromPlanner(event) { if (event) event.stopPropagation(); // Prevent modal from opening const itemId = document.getElementById('lpa-editingScheduledItemId').value; if (itemId && confirm("Remove this item from the plan?")) { lpa_plannedItems = lpa_plannedItems.filter(i => i.id !== itemId); lpa_saveData(); lpa_clearAndRerenderPlannerItems(); document.getElementById('lpa-plannerSlotModal').style.display='none'; } else if (!itemId && event.target.closest('.lpa-planned-item')) { // Deleting directly from cell without opening modal (if X button added to cell item directly) const card = event.target.closest('.lpa-planned-item'); // This needs a way to get item ID from the card. For now, modal delete is primary. } } // --- Activity Log & Settings Tab --- function lpa_initLogSettingsTab(){ lpa_renderCompletedActivitiesLog(); lpa_renderCustomActivityLibraryList(); lpa_populateInterestCategoryForLibrary(); } function lpa_renderCompletedActivitiesLog(){ const listEl = document.getElementById('lpa-completedActivitiesLog'); listEl.innerHTML=''; const completed = lpa_plannedItems.filter(p => p.isDone).sort((a,b)=>new Date(b.date)-new Date(a.date)); if(completed.length === 0) {listEl.innerHTML = 'Rating: ${p.enjoymentRating ? '⭐'.repeat(p.enjoymentRating) : 'Not rated'} | Notes: ${p.notes || '-'}`; listEl.appendChild(li); }); } // In Log & Settings Tab, need functions to mark planned items as done & rate // This implies the planner view should also allow interaction for completion, or this tab lists all "pending" planned items // For simplicity, I'll assume users go to the "My Leisure Plan" to find an item, click to edit, then can mark done & rate from there. // The "Activity Log" tab is then just a view of these completed items. // Manage Custom Activity Library function lpa_populateInterestCategoryForLibrary() { const selectEl = document.getElementById('lpa-libActivityCategory'); selectEl.innerHTML = ''; const allInterests = [...new Set([...lpa_predefinedInterests, ...lpa_customInterests])].sort(); allInterests.forEach(interest => { const opt = document.createElement('option'); opt.value=interest; opt.textContent=interest; selectEl.appendChild(opt);}); } document.getElementById('lpa-customActivityForm').onsubmit = (e) => { e.preventDefault(); const id = document.getElementById('lpa-customActivityId').value; const name = document.getElementById('lpa-libActivityName').value.trim(); if(!name) { alert("Activity name is required."); return; } const activity = { id: id || lpa_generateId(), name, isCustom: true, description: document.getElementById('lpa-libActivityNotes').value, interestCategory: document.getElementById('lpa-libActivityCategory').value, // For custom, let user define these in notes or assume 'Any' for filters initially typicalBudget: 'Any', typicalEnergy: 'Any', typicalSocial: 'Any', typicalLocation: 'Any', color: `#${Math.floor(Math.random()*16777215).toString(16).padStart(6,'0')}` // Random color }; if (id) lpa_activityLibrary = lpa_activityLibrary.map(a => a.id === id ? activity : a); else lpa_activityLibrary.push(activity); lpa_saveData(); lpa_renderCustomActivityLibraryList(); document.getElementById('lpa-customActivityForm').reset(); document.getElementById('lpa-customActivityId').value = ''; if(document.getElementById('lpa-discoverTab').classList.contains('active')) lpa_filterAndDisplayActivities(); // Refresh discover if open }; function lpa_renderCustomActivityLibraryList() { const listEl = document.getElementById('lpa-customActivityLibraryList'); listEl.innerHTML = ''; const customActs = lpa_activityLibrary.filter(a => a.isCustom); if(customActs.length === 0){ listEl.innerHTML = '
${act.name}
Category: ${act.interestCategory} | ${act.description.substring(0,50)}...
Category: ${act.interestCategory} | ${act.description.substring(0,50)}...
