Files
sst_site/.history/public/js/calculator_20251019182400.js
2025-10-19 18:27:00 +09:00

384 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Calculator Logic
class ProjectCalculator {
constructor() {
this.selectedServices = [];
this.selectedComplexity = null;
this.selectedTimeline = null;
this.currentStep = 1;
this.totalSteps = 3;
this.init();
}
init() {
this.setupEventListeners();
this.updateProgressBar();
}
setupEventListeners() {
// Service selection
document.querySelectorAll('.service-option').forEach(option => {
option.addEventListener('click', (e) => this.handleServiceSelection(e));
});
// Complexity selection
document.querySelectorAll('.complexity-option').forEach(option => {
option.addEventListener('click', (e) => this.handleComplexitySelection(e));
});
// Timeline selection
document.querySelectorAll('.timeline-option').forEach(option => {
option.addEventListener('click', (e) => this.handleTimelineSelection(e));
});
// Navigation buttons
document.querySelectorAll('.next-step').forEach(btn => {
btn.addEventListener('click', () => this.nextStep());
});
document.querySelectorAll('.prev-step').forEach(btn => {
btn.addEventListener('click', () => this.prevStep());
});
// Restart button
const restartBtn = document.querySelector('.restart-calculator');
if (restartBtn) {
restartBtn.addEventListener('click', () => this.restart());
}
}
handleServiceSelection(e) {
const option = e.currentTarget;
const service = option.dataset.service;
const price = parseInt(option.dataset.basePrice);
option.classList.toggle('selected');
if (option.classList.contains('selected')) {
this.selectedServices.push({ service, price });
this.animateSelection(option, true);
} else {
this.selectedServices = this.selectedServices.filter(s => s.service !== service);
this.animateSelection(option, false);
}
this.updateStepButton();
}
handleComplexitySelection(e) {
const option = e.currentTarget;
// Clear previous selections
document.querySelectorAll('.complexity-option').forEach(opt => {
opt.classList.remove('selected');
this.animateSelection(opt, false);
});
// Select current option
option.classList.add('selected');
this.animateSelection(option, true);
this.selectedComplexity = {
value: option.dataset.value,
multiplier: parseFloat(option.dataset.multiplier)
};
this.updateStepButton();
}
handleTimelineSelection(e) {
const option = e.currentTarget;
// Clear previous selections
document.querySelectorAll('.timeline-option').forEach(opt => {
opt.classList.remove('selected');
this.animateSelection(opt, false);
});
// Select current option
option.classList.add('selected');
this.animateSelection(option, true);
this.selectedTimeline = {
value: option.dataset.value,
multiplier: parseFloat(option.dataset.multiplier)
};
this.updateStepButton();
}
animateSelection(element, selected) {
if (selected) {
element.style.borderColor = '#3B82F6';
element.style.backgroundColor = '#EBF8FF';
element.style.transform = 'translateY(-2px)';
element.style.boxShadow = '0 8px 25px rgba(59, 130, 246, 0.15)';
} else {
element.style.borderColor = '';
element.style.backgroundColor = '';
element.style.transform = '';
element.style.boxShadow = '';
}
}
updateStepButton() {
const step1Button = document.querySelector('#step-1 .next-step');
const step2Button = document.querySelector('#step-2 .next-step');
if (step1Button) {
step1Button.disabled = this.selectedServices.length === 0;
step1Button.style.opacity = this.selectedServices.length > 0 ? '1' : '0.6';
}
if (step2Button) {
const isValid = this.selectedComplexity && this.selectedTimeline;
step2Button.disabled = !isValid;
step2Button.style.opacity = isValid ? '1' : '0.6';
}
}
updateProgressBar() {
const progressBar = document.querySelector('.calculator-progress-bar');
if (progressBar) {
const progress = (this.currentStep / this.totalSteps) * 100;
progressBar.style.width = `${progress}%`;
progressBar.className = `calculator-progress-bar step-${this.currentStep}`;
}
}
nextStep() {
if (this.currentStep >= this.totalSteps) return;
const currentStepElement = document.querySelector('.calculator-step.active');
const nextStepElement = currentStepElement.nextElementSibling;
if (nextStepElement && nextStepElement.classList.contains('calculator-step')) {
// Animate out current step
currentStepElement.style.opacity = '0';
currentStepElement.style.transform = 'translateX(-20px)';
setTimeout(() => {
currentStepElement.classList.remove('active');
currentStepElement.style.display = 'none';
// Animate in next step
nextStepElement.classList.add('active');
nextStepElement.style.display = 'block';
nextStepElement.style.opacity = '0';
nextStepElement.style.transform = 'translateX(20px)';
setTimeout(() => {
nextStepElement.style.opacity = '1';
nextStepElement.style.transform = 'translateX(0)';
}, 50);
this.currentStep++;
this.updateProgressBar();
if (this.currentStep === 3) {
setTimeout(() => this.calculateFinalPrice(), 300);
}
}, 200);
}
}
prevStep() {
if (this.currentStep <= 1) return;
const currentStepElement = document.querySelector('.calculator-step.active');
const prevStepElement = currentStepElement.previousElementSibling;
if (prevStepElement && prevStepElement.classList.contains('calculator-step')) {
// Animate out current step
currentStepElement.style.opacity = '0';
currentStepElement.style.transform = 'translateX(20px)';
setTimeout(() => {
currentStepElement.classList.remove('active');
currentStepElement.style.display = 'none';
// Animate in previous step
prevStepElement.classList.add('active');
prevStepElement.style.display = 'block';
prevStepElement.style.opacity = '0';
prevStepElement.style.transform = 'translateX(-20px)';
setTimeout(() => {
prevStepElement.style.opacity = '1';
prevStepElement.style.transform = 'translateX(0)';
}, 50);
this.currentStep--;
this.updateProgressBar();
}, 200);
}
}
calculateFinalPrice() {
let total = 0;
// Calculate base price from services
this.selectedServices.forEach(service => {
total += service.price;
});
// Apply complexity multiplier
if (this.selectedComplexity) {
total *= this.selectedComplexity.multiplier;
}
// Apply timeline multiplier
if (this.selectedTimeline) {
total *= this.selectedTimeline.multiplier;
}
// Animate price reveal
const priceElement = document.getElementById('final-price');
if (priceElement) {
priceElement.style.opacity = '0';
priceElement.style.transform = 'scale(0.8)';
setTimeout(() => {
priceElement.textContent = '₩' + total.toLocaleString();
priceElement.style.opacity = '1';
priceElement.style.transform = 'scale(1)';
}, 300);
}
// Generate summary
setTimeout(() => this.generateSummary(total), 600);
}
generateSummary(total) {
const summary = document.getElementById('project-summary');
if (!summary) return;
let summaryHTML = '';
// Services
const servicesLabel = window.calculatorTranslations?.labels?.selected_services || 'Selected Services';
const complexityLabel = window.calculatorTranslations?.labels?.complexity || 'Complexity';
const timelineLabel = window.calculatorTranslations?.labels?.timeline || 'Timeline';
summaryHTML += `<div class="mb-4"><strong>${servicesLabel}:</strong></div>`;
this.selectedServices.forEach(service => {
summaryHTML += `<div class="ml-4 mb-2 flex items-center">
<i class="fas fa-check-circle text-green-500 mr-2"></i>
${this.getServiceName(service.service)}
<span class="ml-auto font-semibold">₩${service.price.toLocaleString()}</span>
</div>`;
});
// Complexity
if (this.selectedComplexity) {
summaryHTML += `<div class="mt-4 mb-2 flex items-center">
<i class="fas fa-layer-group text-blue-500 mr-2"></i>
<strong>${complexityLabel}:</strong>
<span class="ml-2">${this.getComplexityName(this.selectedComplexity.value)}</span>
<span class="ml-auto text-sm text-gray-500">×${this.selectedComplexity.multiplier}</span>
</div>`;
}
// Timeline
if (this.selectedTimeline) {
summaryHTML += `<div class="mb-2 flex items-center">
<i class="fas fa-clock text-purple-500 mr-2"></i>
<strong>${timelineLabel}:</strong>
<span class="ml-2">${this.getTimelineName(this.selectedTimeline.value)}</span>
<span class="ml-auto text-sm text-gray-500">×${this.selectedTimeline.multiplier}</span>
</div>`;
}
// Animate summary appearance
summary.style.opacity = '0';
summary.innerHTML = summaryHTML;
setTimeout(() => {
summary.style.opacity = '1';
}, 200);
}
getServiceName(service) {
if (window.calculatorTranslations && window.calculatorTranslations.services) {
return window.calculatorTranslations.services[service] || service;
}
const names = {
web: 'Web Development',
mobile: 'Mobile App',
design: 'UI/UX Design',
marketing: 'Digital Marketing'
};
return names[service] || service;
}
getComplexityName(complexity) {
if (window.calculatorTranslations && window.calculatorTranslations.complexity) {
return window.calculatorTranslations.complexity[complexity] || complexity;
}
const names = {
simple: 'Simple',
medium: 'Medium',
complex: 'Complex'
};
return names[complexity] || complexity;
}
getTimelineName(timeline) {
if (window.calculatorTranslations && window.calculatorTranslations.timeline) {
return window.calculatorTranslations.timeline[timeline] || timeline;
}
const names = {
standard: 'Standard',
rush: 'Rush',
extended: 'Extended'
};
return names[timeline] || timeline;
}
restart() {
// Reset all selections
this.selectedServices = [];
this.selectedComplexity = null;
this.selectedTimeline = null;
this.currentStep = 1;
// Reset UI
document.querySelectorAll('.service-option, .complexity-option, .timeline-option').forEach(opt => {
opt.classList.remove('selected');
this.animateSelection(opt, false);
});
// Reset steps
document.querySelectorAll('.calculator-step').forEach(step => {
step.classList.remove('active');
step.style.display = 'none';
step.style.opacity = '1';
step.style.transform = 'translateX(0)';
});
// Show first step
const firstStep = document.getElementById('step-1');
if (firstStep) {
firstStep.classList.add('active');
firstStep.style.display = 'block';
}
this.updateProgressBar();
this.updateStepButton();
}
}
// Initialize calculator when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
// Theme initialization
const theme = localStorage.getItem('theme') || 'light';
document.documentElement.className = theme === 'dark' ? 'dark' : '';
// Initialize calculator
if (document.querySelector('.calculator-step')) {
new ProjectCalculator();
}
});