Yoonc's picture
Upload 2 files
f7c6da6 verified
raw
history blame
34.6 kB
<!DOCTYPE html>
<html>
<head>
<title>{{ title if logged_in else 'Spiritual Path Finder - Login' }}</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #F5F5F5;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
background: white;
border-radius: 16px;
padding: 40px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
max-width: 700px;
width: 100%;
animation: slideIn 0.4s ease;
max-height: 90vh;
overflow-y: auto;
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
h1 {
color: #3D3D3D;
font-size: 32px;
margin-bottom: 8px;
text-align: center;
font-weight: 800;
}
p {
color: #6B7280;
text-align: center;
margin-bottom: 30px;
font-size: 15px;
}
.subtitle {
color: #9CA3AF;
font-size: 14px;
text-align: center;
margin-bottom: 25px;
line-height: 1.6;
}
input[type="text"], input[type="password"] {
width: 100%;
padding: 12px 16px;
font-size: 15px;
border: none;
background: #F5F5F5;
border-radius: 10px;
transition: all 0.2s;
outline: none;
}
input:focus {
background: #EBEBEB;
box-shadow: 0 0 0 2px #E5E5E5;
}
button, .btn {
padding: 12px 24px;
font-size: 15px;
background: #3D3D3D;
color: white;
border: none;
border-radius: 10px;
cursor: pointer;
transition: all 0.2s;
font-weight: 600;
text-decoration: none;
display: inline-block;
}
button:hover, .btn:hover {
background: #1A1A1A;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
button:active, .btn:active { transform: translateY(0); }
button:disabled { background: #E5E5E5; color: #999; cursor: not-allowed; transform: none; }
.logout-btn, .reset-btn {
background: #6B7280;
padding: 8px 16px;
font-size: 13px;
margin-top: 15px;
}
.logout-btn:hover, .reset-btn:hover {
background: #4B5563;
box-shadow: 0 4px 12px rgba(107, 114, 128, 0.3);
}
.auth-form input {
width: 100%;
margin-bottom: 15px;
}
.auth-form button {
width: 100%;
}
.switch-link {
color: #3D3D3D;
text-decoration: none;
cursor: pointer;
font-weight: 600;
margin-top: 15px;
display: inline-block;
transition: color 0.2s;
}
.switch-link:hover {
color: #1A1A1A;
text-decoration: underline;
}
.question-block {
background: #FAFAFA;
padding: 30px;
border-radius: 12px;
margin-bottom: 20px;
border: none;
display: none;
min-height: 400px;
}
.question-block.active {
display: block;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateX(20px); }
to { opacity: 1; transform: translateX(0); }
}
.question-block h4 {
color: #3D3D3D;
margin-bottom: 25px;
font-weight: 700;
font-size: 18px;
line-height: 1.6;
}
.question-number {
display: inline-block;
background: #3D3D3D;
color: #fff;
width: 32px;
height: 32px;
border-radius: 50%;
text-align: center;
line-height: 32px;
margin-right: 12px;
font-size: 16px;
}
.option {
display: block;
padding: 16px 20px;
margin-bottom: 12px;
background: white;
border: none;
border-radius: 10px;
cursor: pointer;
transition: all 0.2s;
font-size: 15px;
color: #3D3D3D;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.option:hover {
background: #F5F5F5;
transform: translateX(5px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.option input[type="radio"] {
margin-right: 12px;
cursor: pointer;
width: 18px;
height: 18px;
}
.option input[type="radio"]:disabled {
cursor: not-allowed;
opacity: 0.5;
}
.option:has(input[type="radio"]:disabled) {
opacity: 0.4;
cursor: not-allowed;
}
.option:has(input[type="radio"]:disabled):hover {
background: white;
transform: none;
}
.question-counter {
text-align: center;
color: #999;
font-size: 14px;
margin-bottom: 15px;
font-weight: 600;
}
.submit-btn {
width: 100%;
padding: 16px;
font-size: 16px;
margin-top: 10px;
background: #3D3D3D;
color: #fff;
border: none;
border-radius: 10px;
font-weight: 600;
transition: background 0.2s;
}
.submit-btn:hover {
background: #1A1A1A;
color: #fff;
}
.result-card {
padding: 25px;
border-radius: 12px;
margin-bottom: 20px;
border: none;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}
.result-card.rank-1 {
background: #FFFACD;
}
.result-card.rank-2 {
background: #B4C7E7;
}
.result-card.rank-3 {
background: #90EE90;
}
.result-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 15px;
}
.result-rank {
color: #fff;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
font-weight: 800;
background: #3D3D3D;
}
.result-title { flex: 1; margin-left: 15px; }
.result-title h3 {
font-size: 22px; margin-bottom: 5px; color: #3D3D3D;
}
.result-percentage {
font-size: 24px; font-weight: 800; color: #3D3D3D;
}
.result-description { color: #666; line-height: 1.6; margin-bottom: 12px; font-size: 14px; }
.result-details { background: rgba(255, 255, 255, 0.6); border: none; padding: 15px; border-radius: 8px; margin-top: 15px; }
.result-details h5 { color: #3D3D3D; font-size: 13px; margin-bottom: 8px; font-weight: 700; }
.result-details p { color: #666; font-size: 13px; margin-bottom: 10px; text-align: left; }
.icon { font-size: 24px; margin-right: 8px; }
.success-msg { color: #3D3D3D; font-weight: 600; }
.error-msg { color: #666; font-weight: 600; text-align: center; padding: 10px; }
.progress-bar { background: #F5F5F5; height: 8px; border-radius: 4px; overflow: hidden; margin-bottom: 20px; }
.progress-fill { background: #3D3D3D; height: 100%; transition: width 0.3s; }
.buttons-row { display: flex; gap: 10px; justify-content: center; margin-top: 20px; }
.nav-buttons { display: flex; gap: 12px; justify-content: space-between; margin-top: 20px; }
.nav-btn, .nav-btn.next {
padding: 12px 24px;
font-size: 15px;
background: #3D3D3D;
color: #fff;
border: none;
border-radius: 10px;
cursor: pointer;
transition: background 0.2s;
font-weight: 600;
}
.nav-btn:hover, .nav-btn.next:hover { background: #1A1A1A; color: #fff; transform: translateY(-1px); }
.nav-btn:disabled { opacity: 0.3; cursor: not-allowed; transform: none; }
h3 { text-align: center; color: #3D3D3D; }
.chat-toggle-btn {
background: rgba(255, 255, 255, 0.8);
color: #3D3D3D;
border: none;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 600;
margin-top: 15px;
width: 100%;
transition: background 0.2s, color 0.2s;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.chat-toggle-btn:hover { background: #3D3D3D; color: #fff; }
.chat-window {
display: none;
background: rgba(255, 255, 255, 0.9);
border: none;
border-radius: 10px;
margin-top: 15px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.chat-window.open { display: block; animation: slideDown 0.3s ease; }
@keyframes slideDown { from { opacity: 0; max-height: 0; } to { opacity: 1; max-height: 500px; } }
.chat-messages { height: 250px; overflow-y: auto; padding: 15px; background: transparent; }
.chat-message { margin-bottom: 12px; padding: 10px 14px; border-radius: 8px; max-width: 85%; line-height: 1.5; font-size: 14px; }
.chat-message.user {
background: #3D3D3D;
color: #fff;
margin-left: auto;
text-align: right;
}
.chat-message.bot {
background: white;
color: #3D3D3D;
border: none;
text-align: left;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
}
.chat-message.bot ul { margin: 8px 0 0 0; padding-left: 20px; }
.chat-message.bot li { margin-bottom: 6px; line-height: 1.6; }
.chat-input-area { display: flex; gap: 8px; padding: 12px; background: transparent; border-top: none; }
.chat-input {
flex: 1;
padding: 10px 14px;
border: none;
background: white;
border-radius: 8px;
font-size: 14px;
outline: none;
color: #3D3D3D;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
}
.chat-input:focus { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); }
.chat-send-btn {
padding: 10px 20px;
background: #3D3D3D;
color: #fff;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
font-size: 14px;
transition: background 0.2s;
}
.chat-send-btn:hover { background: #1A1A1A; color: #fff; }
.chat-send-btn:disabled { background: #F5F5F5; color: #999; cursor: not-allowed; }
.chat-typing { color: #999; font-style: italic; font-size: 13px; padding: 10px 14px; }
</style>
</head>
<body>
<div class="container">
{% if not logged_in %}
<!-- Login/Signup Form -->
<h1><span class="icon">🌟</span>Spiritual Path Finder</h1>
<p>{{ 'Begin your journey of self-discovery' if is_signup else 'Welcome back, seeker!' }}</p>
<div class="auth-form">
<input type="text" id="authUsername" placeholder="Username">
<input type="password" id="authPassword" placeholder="Password">
<button onclick="authenticate()">{{ 'Sign Up' if is_signup else 'Sign In' }}</button>
<div id="result"></div>
<p class="switch-link" onclick="switchAuth()">
{{ 'Already have an account? Sign In' if is_signup else 'New here? Sign Up' }}
</p>
</div>
<script>
function authenticate() {
const username = document.getElementById('authUsername').value.trim();
const password = document.getElementById('authPassword').value;
if (!username || !password) {
document.getElementById('result').innerHTML =
'<p class="error-msg">⚠️ Please fill in all fields</p>';
return;
}
const endpoint = window.location.pathname === '/signup' ? '/signup' : '/login';
fetch(endpoint, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({username, password})
})
.then(response => response.json())
.then(data => {
if (data.success) {
window.location.href = '/';
} else {
document.getElementById('result').innerHTML =
`<p class="error-msg">${data.message}</p>`;
}
});
}
function switchAuth() {
const newPath = window.location.pathname === '/signup' ? '/login' : '/signup';
window.location.href = newPath;
}
document.getElementById('authPassword').addEventListener('keypress', function(e) {
if (e.key === 'Enter') authenticate();
});
</script>
{% else %}
<!-- Assessment Interface -->
<h1>{{ title }}</h1>
<p>{{ message }}</p>
{% if not has_results %}
<p class="subtitle">
Discover which spiritual or religious path aligns with your beliefs, values, and lifestyle.
Answer 8 thoughtful questions about your worldview.
</p>
<div class="question-counter" id="questionCounter">Question 1 of {{ questions|length }}</div>
<div class="progress-bar">
<div class="progress-fill" id="progressBar" style="width: 0%"></div>
</div>
<div style="display:none;" id="assessmentData"
data-total="{{ questions|length }}"
data-ids="{{ questions|map(attribute='id')|list|tojson|safe }}">
</div>
<form id="assessmentForm">
{% for question in questions %}
{% set q_index = loop.index %}
<div class="question-block" data-question-index="{{ q_index }}" {% if loop.first %}data-active="true"{% endif %}>
<h4>
<span class="question-number">{{ q_index }}</span>
{{ question.question }}
</h4>
{% for option in question.options.keys() %}
<label class="option">
<input type="radio"
name="q{{ question.id }}"
value="{{ option }}"
data-question-index="{{ q_index }}"
onchange="handleAnswer(this)">
{{ option }}
</label>
{% endfor %}
<div class="nav-buttons" style="justify-content: flex-end;">
<button type="button" class="nav-btn next" id="nextBtn{{ q_index }}" onclick="goToNext()" disabled>
Next β†’
</button>
</div>
</div>
{% endfor %}
<button type="button" class="submit-btn" onclick="submitAssessment()" id="submitBtn" style="display: none;">
✨ Discover Your Path
</button>
</form>
<div id="errorMsg"></div>
{% else %}
<!-- Results Display -->
<p class="subtitle">
Based on your responses, here are the spiritual paths that align most closely with your values and beliefs:
</p>
<div id="resultsContainer">
{% for result in results %}
<div class="result-card rank-{{ loop.index }}">
<div class="result-header">
<div class="result-rank">{{ loop.index }}</div>
<div class="result-title">
<h3>{{ result.name }}</h3>
</div>
<div class="result-percentage">{{ result.percentage }}%</div>
</div>
<p class="result-description">{{ result.description }}</p>
<div class="result-details">
<h5>πŸ“Ώ Common Practices:</h5>
<p>{{ result.practices }}</p>
<h5>πŸ’­ Core Beliefs:</h5>
<p>{{ result.core_beliefs }}</p>
</div>
<button class="chat-toggle-btn" onclick="toggleChat('{{ result.name }}')">
πŸ’¬ Ask Questions About {{ result.name }}
</button>
<div class="chat-window" id="chat-{{ result.name|replace(' ', '-') }}">
<div class="chat-messages" id="messages-{{ result.name|replace(' ', '-') }}">
<div class="chat-message bot">
Hi! Ask me anything about {{ result.name }}.<br>
<span style="color:#7C3AED; font-size:13px;">
Example: "What are the daily practices?"<br>
Example: "How do I get started with this path?"
</span>
</div>
</div>
<div class="chat-input-area">
<input type="text"
class="chat-input"
id="input-{{ result.name|replace(' ', '-') }}"
placeholder="Ask about {{ result.name }}..."
onkeypress="if(event.key==='Enter') sendMessage('{{ result.name }}')">
<button class="chat-send-btn"
id="send-{{ result.name|replace(' ', '-') }}"
onclick="sendMessage('{{ result.name }}')">
Send
</button>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="buttons-row">
<button class="btn reset-btn" onclick="resetAssessment()">πŸ”„ Retake Assessment</button>
</div>
{% endif %}
<div style="text-align: center;">
<a href="/logout" class="btn logout-btn">Logout</a>
</div>
<script>
var currentQuestion = 1;
var maxQuestionReached = 1; // Track the furthest question reached
var assessmentDataEl = document.getElementById('assessmentData');
var totalQuestions = assessmentDataEl ? parseInt(assessmentDataEl.getAttribute('data-total')) : 0;
var questionIds = assessmentDataEl ? JSON.parse(assessmentDataEl.getAttribute('data-ids')) : [];
// Show first question on load
window.addEventListener('DOMContentLoaded', function() {
showQuestion(1);
});
function showQuestion(questionIndex) {
if (questionIndex > maxQuestionReached + 1) return;
if (questionIndex > maxQuestionReached) maxQuestionReached = questionIndex;
document.querySelectorAll('.question-block').forEach(function(block) {
block.classList.remove('active');
var blockIndex = parseInt(block.getAttribute('data-question-index'));
if (blockIndex === questionIndex) block.classList.add('active');
if (blockIndex < questionIndex) {
block.querySelectorAll('input[type="radio"]').forEach(function(radio) { radio.disabled = true; });
}
});
currentQuestion = questionIndex;
document.getElementById('questionCounter').textContent = 'Question ' + questionIndex + ' of ' + totalQuestions;
document.getElementById('progressBar').style.width = ((questionIndex - 1) / totalQuestions) * 100 + '%';
updateNavigationButtons();
}
function updateNavigationButtons() {
var nextBtn = document.getElementById('nextBtn' + currentQuestion);
if (nextBtn) {
var currentQuestionId = questionIds[currentQuestion - 1];
var radioName = 'q' + currentQuestionId;
var isAnswered = document.querySelector('input[name="' + radioName + '"]:checked') !== null;
if (currentQuestion === totalQuestions && isAnswered) {
nextBtn.style.display = 'none';
document.getElementById('submitBtn').style.display = 'block';
} else {
nextBtn.disabled = !isAnswered;
nextBtn.style.display = 'inline-block';
}
}
}
function handleAnswer(radioElement) {
var questionIndex = parseInt(radioElement.getAttribute('data-question-index'));
// Only process if this is the current question
if (questionIndex !== currentQuestion) {
return;
}
updateNavigationButtons();
// Auto-advance to next question after selection
setTimeout(function() {
if (questionIndex < totalQuestions) {
showQuestion(questionIndex + 1);
} else {
// Last question - show submit button
var nextBtn = document.getElementById('nextBtn' + questionIndex);
if (nextBtn) {
nextBtn.style.display = 'none';
}
document.getElementById('submitBtn').style.display = 'block';
}
}, 400);
}
function goToNext() {
if (currentQuestion < totalQuestions) {
showQuestion(currentQuestion + 1);
}
}
function submitAssessment() {
var form = document.getElementById('assessmentForm');
var answers = [];
questionIds.forEach(function(qId) {
var radioName = 'q' + qId;
var selectedRadio = form.querySelector('input[name="' + radioName + '"]:checked');
if (selectedRadio) {
answers.push({
question_id: qId,
answer: selectedRadio.value
});
}
});
if (answers.length !== totalQuestions) {
document.getElementById('errorMsg').innerHTML =
'<p class="error-msg">⚠️ Please answer all questions</p>';
return;
}
document.getElementById('submitBtn').disabled = true;
document.getElementById('submitBtn').textContent = '✨ Calculating...';
fetch('/submit_assessment', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({answers: answers})
})
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.success) {
window.location.reload();
} else {
document.getElementById('errorMsg').innerHTML =
'<p class="error-msg">' + data.message + '</p>';
document.getElementById('submitBtn').disabled = false;
document.getElementById('submitBtn').textContent = '✨ Discover Your Path';
}
});
}
function resetAssessment() {
if (!confirm('Are you sure you want to retake the assessment? Your current results will be cleared.')) {
return;
}
fetch('/reset_assessment', {
method: 'POST',
headers: {'Content-Type': 'application/json'}
})
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.success) {
window.location.reload();
}
});
}
// Chat functionality
var chatHistories = {};
function formatBotResponse(text) {
var div = document.createElement('div');
div.textContent = text;
var escaped = div.innerHTML;
if (escaped.match(/\*\s+/g) || escaped.match(/β€’\s+/g) || escaped.match(/^\s*-\s+/gm)) {
var lines = escaped.split(/(?:\*|β€’|\n-)\s+/);
if (lines.length > 1) {
var formatted = lines[0].trim() ? lines[0].trim() + '<br><br>' : '';
formatted += '<ul style="margin: 0; padding-left: 20px; line-height: 1.8;">';
for (var i = 1; i < lines.length; i++) {
if (lines[i].trim()) formatted += '<li style="margin-bottom: 6px;">' + lines[i].trim() + '</li>';
}
return formatted + '</ul>';
}
}
return escaped.replace(/\n/g, '<br>');
}
function toggleChat(religionName) {
var chatId = 'chat-' + religionName.replace(/\s+/g, '-');
var chatWindow = document.getElementById(chatId);
if (chatWindow.classList.contains('open')) {
chatWindow.classList.remove('open');
} else {
chatWindow.classList.add('open');
var inputId = 'input-' + religionName.replace(/\s+/g, '-');
setTimeout(function() {
document.getElementById(inputId).focus();
}, 300);
}
}
function sendMessage(religionName) {
var inputId = 'input-' + religionName.replace(/\s+/g, '-');
var messagesId = 'messages-' + religionName.replace(/\s+/g, '-');
var sendBtnId = 'send-' + religionName.replace(/\s+/g, '-');
var inputEl = document.getElementById(inputId);
var messagesEl = document.getElementById(messagesId);
var sendBtn = document.getElementById(sendBtnId);
var message = inputEl.value.trim();
if (!message) return;
// Initialize chat history if not exists
if (!chatHistories[religionName]) {
chatHistories[religionName] = [];
}
// Add user message to UI
var userMsgDiv = document.createElement('div');
userMsgDiv.className = 'chat-message user';
userMsgDiv.textContent = message;
messagesEl.appendChild(userMsgDiv);
// Clear input and disable send button
inputEl.value = '';
sendBtn.disabled = true;
// Show typing indicator
var typingDiv = document.createElement('div');
typingDiv.className = 'chat-typing';
typingDiv.textContent = 'πŸ’­ Thinking...';
messagesEl.appendChild(typingDiv);
// Scroll to bottom
messagesEl.scrollTop = messagesEl.scrollHeight;
// Add to chat history
chatHistories[religionName].push({
role: 'user',
content: message
});
// Send to backend
fetch('/chat', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
message: message,
religion: religionName,
history: chatHistories[religionName]
})
})
.then(function(response) { return response.json(); })
.then(function(data) {
messagesEl.removeChild(typingDiv);
if (data.success) {
var botMsgDiv = document.createElement('div');
botMsgDiv.className = 'chat-message bot';
// Format the response with proper bullet points
var formattedResponse = formatBotResponse(data.response);
botMsgDiv.innerHTML = formattedResponse;
messagesEl.appendChild(botMsgDiv);
chatHistories[religionName].push({
role: 'assistant',
content: data.response
});
} else {
var errorMsgDiv = document.createElement('div');
errorMsgDiv.className = 'chat-message bot';
errorMsgDiv.style.color = '#EF4444';
errorMsgDiv.textContent = '❌ ' + data.message;
messagesEl.appendChild(errorMsgDiv);
}
sendBtn.disabled = false;
messagesEl.scrollTop = messagesEl.scrollHeight;
})
.catch(function(error) {
messagesEl.removeChild(typingDiv);
var errorMsgDiv = document.createElement('div');
errorMsgDiv.className = 'chat-message bot';
errorMsgDiv.style.color = '#EF4444';
errorMsgDiv.textContent = '❌ Connection error';
messagesEl.appendChild(errorMsgDiv);
sendBtn.disabled = false;
messagesEl.scrollTop = messagesEl.scrollHeight;
});
}
</script>
{% endif %}
</div>
</body>
</html>