Be / app. js
Aleater11's picture
Rename App. Js to app. js
c763b06 verified
document.addEventListener('DOMContentLoaded', () => {
// Initialize local storage for app data
const initializeStorage = () => {
if (!localStorage.getItem('beAppData')) {
const initialData = {
reflections: [],
decisions: [],
mindData: {
values: [],
thinkingPatterns: [],
growthAreas: []
},
streak: 0,
daysActive: 0,
reflectionsCount: 0,
insightsCount: 0,
decisionsCount: 0
};
localStorage.setItem('beAppData', JSON.stringify(initialData));
}
return JSON.parse(localStorage.getItem('beAppData'));
};
// Initialize app data
let appData = initializeStorage();
updateStatistics();
// Reset data functionality
const resetDataBtn = document.getElementById('reset-data-btn');
if (resetDataBtn) {
resetDataBtn.addEventListener('click', () => {
if (confirm('Are you sure you want to reset all data? This action cannot be undone.')) {
localStorage.removeItem('beAppData');
appData = initializeStorage();
updateStatistics();
updateUI();
showNotification('All data has been reset successfully!');
}
});
}
// Tab switching functionality
const bottomNavBtns = document.querySelectorAll('.bottom-nav-btn');
const tabContents = document.querySelectorAll('.tab-content');
bottomNavBtns.forEach(btn => {
btn.addEventListener('click', () => {
const targetTab = btn.getAttribute('data-tab');
// Update button active states
bottomNavBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
// Update tab content visibility
tabContents.forEach(content => {
if (content.id === targetTab) {
content.classList.add('active');
} else {
content.classList.remove('active');
}
});
// Scroll to top when changing tabs for better UX
window.scrollTo({ top: 0, behavior: 'smooth' });
});
});
// Save reflection functionality
const saveReflectionBtn = document.getElementById('save-reflection-btn');
const reflectionInput = document.getElementById('reflection-input');
if (saveReflectionBtn && reflectionInput) {
saveReflectionBtn.addEventListener('click', () => {
const reflection = reflectionInput.value.trim();
if (reflection) {
// Save to local storage
appData.reflections.unshift({
text: reflection,
date: new Date().toISOString(),
mood: 'Reflective'
});
// Update counts
appData.reflectionsCount++;
appData.daysActive = Math.min(appData.daysActive + 1, appData.reflections.length);
appData.streak++;
localStorage.setItem('beAppData', JSON.stringify(appData));
// Clear input
reflectionInput.value = '';
// Update UI
updateStatistics();
updateReflections();
// Show feedback
showNotification('Reflection saved successfully!');
} else {
alert('Please enter your reflection before saving.');
}
});
}
// Decision assistant functionality
const decisionSteps = document.querySelectorAll('.decision-step');
const decisionTypeSelector = document.getElementById('decision-type-selector');
let selectedDecisionType = null;
// Decision Type Selection
if (decisionTypeSelector) {
decisionTypeSelector.addEventListener('click', (e) => {
const button = e.target.closest('.decision-type-btn');
if (button) {
// Remove selected class from all buttons
decisionTypeSelector.querySelectorAll('.decision-type-btn').forEach(btn => {
btn.classList.remove('selected', 'border-indigo-500', 'bg-indigo-100');
});
// Add selected class to the clicked button
button.classList.add('selected', 'border-indigo-500', 'bg-indigo-100');
selectedDecisionType = button.getAttribute('data-type');
}
});
}
const navigateToStep = (targetStepId) => {
decisionSteps.forEach(step => {
if (step.id === targetStepId) {
step.classList.remove('hidden');
} else {
step.classList.add('hidden');
}
});
// Scroll to the top of the decision maker card
const deciderCard = document.querySelector('#decider .bg-white');
if (deciderCard) {
deciderCard.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
};
// Navigation Button Event Listeners
document.getElementById('to-step-2')?.addEventListener('click', () => {
const description = document.getElementById('decision-description').value.trim();
if (!description) {
alert('Please describe the decision you are facing.');
return;
}
if (!selectedDecisionType) {
alert('Please select a decision type.');
return;
}
navigateToStep('decision-step-2');
});
document.getElementById('to-step-3')?.addEventListener('click', () => {
// Validate options
const options = document.querySelectorAll('.option-item');
let valid = true;
options.forEach(option => {
const title = option.querySelector('.option-title').value.trim();
const description = option.querySelector('.option-description').value.trim();
if (!title || !description) {
valid = false;
}
});
if (!valid) {
alert('Please complete all option details before proceeding.');
return;
}
// Generate analysis
generateAnalysis();
navigateToStep('decision-step-3');
});
// Back buttons
document.querySelectorAll('.back-btn').forEach(button => {
button.addEventListener('click', () => {
const targetStepId = button.getAttribute('data-target');
navigateToStep(targetStepId);
});
});
// Add Option Button
const addOptionBtn = document.getElementById('add-option');
const optionContainer = document.getElementById('option-container');
let optionCounter = 2; // Start counting from 3 since 2 are already present
if (addOptionBtn && optionContainer) {
addOptionBtn.addEventListener('click', () => {
optionCounter++;
const newOption = document.createElement('div');
newOption.className = 'option-item p-4 border border-gray-300 rounded-lg bg-gray-50 relative slide-in';
newOption.innerHTML = `
<input type="text" class="option-title w-full p-2 border-b border-gray-300 mb-2 focus:outline-none focus:border-indigo-500 font-medium bg-transparent" placeholder="Option ${optionCounter} Title">
<textarea class="option-description w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 h-20 resize-none mt-1 transition duration-150 ease-in-out" placeholder="Describe this option..."></textarea>
<button class="remove-option absolute top-2 right-2 text-gray-400 hover:text-red-500 text-sm p-1" title="Remove option">&times;</button>
`;
optionContainer.appendChild(newOption);
// Add event listener to the new remove button
newOption.querySelector('.remove-option').addEventListener('click', handleRemoveOption);
});
}
// Remove Option Functionality
const handleRemoveOption = (event) => {
if (optionContainer.querySelectorAll('.option-item').length > 2) {
event.target.closest('.option-item').remove();
} else {
alert("At least two options are required.");
}
};
document.querySelectorAll('.remove-option').forEach(btn => {
btn.addEventListener('click', handleRemoveOption);
});
// Generate decision analysis
const generateAnalysis = () => {
const options = [];
document.querySelectorAll('.option-item').forEach(item => {
const title = item.querySelector('.option-title').value || 'Unnamed Option';
const description = item.querySelector('.option-description').value || 'No description provided.';
options.push({ title, description });
});
const decisionDesc = document.getElementById('decision-description')?.value || 'the decision';
const decisionType = selectedDecisionType || 'General';
// Generate analysis HTML
let prosConsHtml = `<p>Comparing options for <strong>${decisionDesc}</strong> (Type: ${decisionType}):</p>`;
let valueHtml = `<p>Considering your values related to a <strong>${decisionType}</strong> decision:</p>`;
let recommendationHtml = `<p>Recommendation for <strong>${decisionDesc}</strong>:</p>`;
options.forEach((opt, index) => {
// Extract pros and cons from description
const pros = [];
const cons = [];
// Simple analysis based on keywords in description
const words = opt.description.toLowerCase().split(/\s+/);
if (words.some(w => ['good', 'great', 'benefit', 'advantage', 'positive', 'pro'].includes(w))) {
pros.push('Positive aspects mentioned');
}
if (words.some(w => ['bad', 'drawback', 'downside', 'negative', 'con', 'concern'].includes(w))) {
cons.push('Concerns or drawbacks noted');
}
// Add a default if nothing detected
if (pros.length === 0) pros.push('Potential benefits could be explored further');
if (cons.length === 0) cons.push('Consider any potential downsides');
prosConsHtml += `
<div class="mt-2 p-2 border-l-2 border-indigo-200">
<strong>${opt.title}:</strong>
<div class="mt-1">
<span class="text-green-600 font-medium">Pros:</span> ${pros.join(', ')}
</div>
<div class="mt-1">
<span class="text-red-600 font-medium">Cons:</span> ${cons.join(', ')}
</div>
</div>
`;
// Value alignment based on decision type
const values = appData.mindData.values.length > 0 ?
appData.mindData.values :
['Growth', 'Balance', 'Security', 'Freedom', 'Connection'];
const alignedValue = values[index % values.length]; // Just for demonstration
valueHtml += `<p class="mt-1">- <strong>${opt.title}</strong> appears to align with your value of <strong>${alignedValue}</strong> based on the description.</p>`;
});
// Simple recommendation logic (alternate between options for demo)
const recommendedOption = options[0]; // Default to first option
recommendationHtml += `
<p class="mt-2">Based on the analysis, <strong>${recommendedOption.title}</strong> appears to be a strong option, particularly considering your values.</p>
<p class="mt-1"><strong>Considerations:</strong> Before finalizing your decision, reflect on how each option affects your long-term goals and whether there are any aspects you haven't fully explored.</p>
`;
// Update the UI
document.getElementById('pros-cons-analysis').innerHTML = prosConsHtml;
document.getElementById('value-alignment-analysis').innerHTML = valueHtml;
document.getElementById('ai-recommendation').innerHTML = recommendationHtml;
};
// Save Decision Button
document.getElementById('save-decision')?.addEventListener('click', () => {
const decisionDesc = document.getElementById('decision-description')?.value || 'Unnamed Decision';
const decisionType = selectedDecisionType || 'General';
// Get options
const options = [];
document.querySelectorAll('.option-item').forEach(item => {
const title = item.querySelector('.option-title').value || 'Unnamed Option';
const description = item.querySelector('.option-description').value || 'No description';
options.push({ title, description });
});
// Save to local storage
appData.decisions.unshift({
title: decisionDesc,
type: decisionType,
options: options,
date: new Date().toISOString(),
status: 'Pending'
});
appData.decisionsCount++;
localStorage.setItem('beAppData', JSON.stringify(appData));
// Update UI
updateStatistics();
updateDecisions();
// Show feedback and reset form
showNotification('Decision analysis saved successfully!');
navigateToStep('decision-step-1');
document.getElementById('decision-description').value = '';
decisionTypeSelector.querySelectorAll('.decision-type-btn').forEach(btn => {
btn.classList.remove('selected', 'border-indigo-500', 'bg-indigo-100');
});
selectedDecisionType = null;
});
// Chat functionality
const chatMessages = document.getElementById('chat-messages');
const chatInput = document.getElementById('chat-input');
const sendChatBtn = document.getElementById('send-chat-btn');
const addChatMessage = (message, isUser = true) => {
if (!message.trim()) return;
const messageElement = document.createElement('div');
messageElement.classList.add('chat-message', isUser ? 'user-message' : 'ai-message', 'slide-in');
const contentElement = document.createElement('p');
contentElement.classList.add('text-gray-800');
contentElement.textContent = message;
const timeElement = document.createElement('span');
timeElement.classList.add('text-xs', 'text-gray-500', 'mt-1', 'block', 'text-right');
timeElement.textContent = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
messageElement.appendChild(contentElement);
messageElement.appendChild(timeElement);
if (chatMessages) {
chatMessages.appendChild(messageElement);
// Scroll to the bottom
chatMessages.scrollTop = chatMessages.scrollHeight;
}
};
const handleSendChat = () => {
if (!chatInput) return;
const message = chatInput.value;
if (message.trim()) {
addChatMessage(message, true);
chatInput.value = '';
// Simulate AI response after a short delay
setTimeout(() => {
// Enhanced AI responses based on message content
let aiResponse = '';
const lowerMessage = message.toLowerCase();
if (lowerMessage.includes('career') || lowerMessage.includes('job') || lowerMessage.includes('work')) {
aiResponse = `It sounds like you're thinking about your career path. Professional transitions can be challenging but also exciting opportunities for growth. What specific aspects of your career are you looking to change?`;
} else if (lowerMessage.includes('relationship') || lowerMessage.includes('partner') || lowerMessage.includes('friend')) {
aiResponse = `Relationships are such an important part of our wellbeing. I notice you're thinking about connections in your life. Would you like to explore how your values might guide your approach to this relationship?`;
} else if (lowerMessage.includes('stress') || lowerMessage.includes('anxiety') || lowerMessage.includes('worry')) {
aiResponse = `I hear that you're experiencing some challenging emotions. Remember that it's normal to feel this way sometimes. Would it help to discuss some simple mindfulness techniques that could help manage these feelings in the moment?`;
} else {
aiResponse = `Thanks for sharing that. I'm curious to learn more about how this relates to your personal growth journey. Could you tell me what outcome you're hoping for?`;
}
addChatMessage(aiResponse, false);
}, 1000);
}
};
if (sendChatBtn && chatInput) {
sendChatBtn.addEventListener('click', handleSendChat);
chatInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
handleSendChat();
}
});
}
// UI Update Functions
function updateStatistics() {
document.getElementById('streak-count').textContent = appData.streak;
document.getElementById('reflections-count').textContent = appData.reflectionsCount;
document.getElementById('insights-count').textContent = appData.insightsCount;
document.getElementById('decisions-count').textContent = appData.decisionsCount;
document.getElementById('days-active-count').textContent = appData.daysActive;
// Update progress circle
const progressCircle = document.querySelector('.progress-circle-value');
const progressText = document.querySelector('.progress-circle-text');
let progress = 0;
if (appData.streak > 0) {
progress = Math.min(Math.round((appData.streak / 7) * 100), 100);
progressCircle.style.strokeDashoffset = 100 - progress;
progressText.textContent = progress + '%';
} else {
progressCircle.style.strokeDashoffset = 100;
progressText.textContent = '0%';
}
}
function updateReflections() {
const container = document.getElementById('past-reflections');
const noReflectionsMsg = document.getElementById('no-reflections-message');
if (container) {
// Clear existing content except the no-reflections message
Array.from(container.children).forEach(child => {
if (child.id !== 'no-reflections-message') {
child.remove();
}
});
if (appData.reflections.length > 0) {
// Hide the no-reflections message
if (noReflectionsMsg) noReflectionsMsg.classList.add('hidden');
// Add reflection cards
appData.reflections.slice(0, 6).forEach(reflection => {
const date = new Date(reflection.date);
const timeAgo = getTimeAgo(date);
const card = document.createElement('div');
card.className = 'bg-white border border-gray-200 rounded-lg p-4 shadow-sm hover:shadow-md transition-shadow';
card.innerHTML = `
<div class="flex justify-between items-start mb-3">
<span class="text-xs text-gray-500">${timeAgo}</span>
<span class="text-xs font-medium text-indigo-600">Mood: ${reflection.mood || 'Reflective'}</span>
</div>
<p class="text-gray-700 text-sm">${reflection.text}</p>
`;
container.appendChild(card);
});
} else {
// Show the no-reflections message
if (noReflectionsMsg) noReflectionsMsg.classList.remove('hidden');
}
}
}
function updateDecisions() {
const container = document.getElementById('recent-decisions');
const noDecisionsMsg = document.getElementById('no-decisions-message');
if (container) {
// Clear existing content except the no-decisions message
Array.from(container.children).forEach(child => {
if (child.id !== 'no-decisions-message') {
child.remove();
}
});
if (appData.decisions.length > 0) {
// Hide the no-decisions message
if (noDecisionsMsg) noDecisionsMsg.classList.add('hidden');
// Add decision cards
appData.decisions.slice(0, 4).forEach((decision, index) => {
const date = new Date(decision.date);
const timeAgo = getTimeAgo(date);
const card = document.createElement('div');
card.className = 'decision-card bg-white border border-gray-200 rounded-lg p-5 shadow hover:shadow-md';
card.innerHTML = `
<div class="flex justify-between items-start mb-3">
<h3 class="font-semibold text-lg text-gray-800">${decision.title}</h3>
<span class="text-xs text-gray-500">${timeAgo}</span>
</div>
<p class="text-gray-600 text-sm mb-3">Analysis of ${decision.type} decision with ${decision.options.length} options.</p>
<div class="flex justify-between items-center mt-4">
<span class="px-3 py-1 bg-${index % 2 === 0 ? 'green' : 'yellow'}-100 text-${index % 2 === 0 ? 'green' : 'yellow'}-800 rounded-full text-xs font-medium">${index % 2 === 0 ? 'Resolved' : 'Pending'}</span>
<button class="text-indigo-600 hover:text-indigo-800 text-sm font-medium focus:outline-none transition duration-150 ease-in-out">View Details</button>
</div>
`;
container.appendChild(card);
});
} else {
// Show the no-decisions message
if (noDecisionsMsg) noDecisionsMsg.classList.remove('hidden');
}
}
}
function updateMindData() {
const valuesList = document.getElementById('values-list');
const thinkingPatternsList = document.getElementById('thinking-patterns-list');
if (valuesList) {
valuesList.innerHTML = '';
const values = appData.mindData.values.length > 0 ?
appData.mindData.values :
['Start reflecting to discover your values'];
values.forEach(value => {
const li = document.createElement('li');
li.textContent = value;
valuesList.appendChild(li);
});
}
if (thinkingPatternsList) {
thinkingPatternsList.innerHTML = '';
const patterns = appData.mindData.thinkingPatterns.length > 0 ?
appData.mindData.thinkingPatterns :
['Make decisions to identify your thinking patterns'];
patterns.forEach(pattern => {
const li = document.createElement('li');
li.textContent = pattern;
thinkingPatternsList.appendChild(li);
});
}
}
function updateUI() {
updateStatistics();
updateReflections();
updateDecisions();
updateMindData();
}
// Helper Functions
function getTimeAgo(date) {
const now = new Date();
const diffInSeconds = Math.floor((now - date) / 1000);
if (diffInSeconds < 60) return 'Just now';
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)} minutes ago`;
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)} hours ago`;
if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)} days ago`;
return date.toLocaleDateString();
}
function showNotification(message) {
// Remove any existing notifications
const existingNotification = document.querySelector('.notification');
if (existingNotification) {
existingNotification.remove();
}
// Create and add the new notification
const notification = document.createElement('div');
notification.className = 'notification';
notification.textContent = message;
document.body.appendChild(notification);
// Remove the notification after 3 seconds
setTimeout(() => {
if (notification && notification.parentNode) {
notification.remove();
}
}, 3000);
}
// Initialize UI
updateUI();
});