Spaces:
Running
Running
🐳 19/03 - 14:49 - CONTEXTE IMPORTANT :Tu travailles sur un fichier HTML déjà existant contenant un simulateur VTC fonctionnel en multi-étapes.⚠️ RÈGLES STRICTES :- NE PAS recréer la page- NE PAS dupl
Browse files- simulateur-pertes.html +404 -65
simulateur-pertes.html
CHANGED
|
@@ -109,6 +109,16 @@
|
|
| 109 |
<input type="number" id="daysPerMonth" placeholder="Ex : 22"
|
| 110 |
class="w-full rounded-xl bg-black/40 border border-white/10 px-4 py-3 text-white text-sm outline-none focus:border-emerald-500/50 transition">
|
| 111 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
</div>
|
| 113 |
|
| 114 |
<div class="text-xs text-white/50 mb-4 bg-white/5 rounded-lg p-3">
|
|
@@ -198,7 +208,7 @@
|
|
| 198 |
<div class="bg-[#151821] border border-white/10 rounded-2xl p-5">
|
| 199 |
<h2 class="text-lg font-medium text-white mb-4">Votre véhicule</h2>
|
| 200 |
|
| 201 |
-
<div class="grid grid-cols-3 gap-2 mb-
|
| 202 |
<button type="button" data-value="thermique" class="vehicle-btn py-3 rounded-xl border border-white/10 text-white/60 bg-transparent transition text-sm font-medium">
|
| 203 |
Thermique
|
| 204 |
</button>
|
|
@@ -211,6 +221,13 @@
|
|
| 211 |
</div>
|
| 212 |
<input type="hidden" id="vehicleType" value="">
|
| 213 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 214 |
<div class="flex gap-3">
|
| 215 |
<button id="btnStep5Back" class="w-1/3 py-3 rounded-xl bg-white/5 text-white border border-white/10 text-sm font-medium hover:bg-white/10 transition">
|
| 216 |
Retour
|
|
@@ -292,12 +309,62 @@
|
|
| 292 |
Découvrir mon score TIE
|
| 293 |
</button>
|
| 294 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
<button id="btnReset" class="w-full py-2 mt-3 text-xs text-white/60 hover:text-white transition">
|
| 296 |
Refaire le calcul
|
| 297 |
</button>
|
| 298 |
</div>
|
| 299 |
</div>
|
| 300 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
<!-- Score Loading -->
|
| 302 |
<div id="scoreLoading" class="loading-container">
|
| 303 |
<div class="bg-[#151821] border border-white/10 rounded-2xl p-8 text-center">
|
|
@@ -371,10 +438,10 @@
|
|
| 371 |
|
| 372 |
<!-- CTAs -->
|
| 373 |
<div class="space-y-3 mb-6">
|
| 374 |
-
<button class="w-full py-3 rounded-xl bg-
|
| 375 |
-
|
| 376 |
</button>
|
| 377 |
-
<button class="w-full py-3 rounded-xl bg-
|
| 378 |
Développer mes clients privés
|
| 379 |
</button>
|
| 380 |
</div>
|
|
@@ -397,13 +464,18 @@
|
|
| 397 |
let formData = {
|
| 398 |
coursesPerDay: 0,
|
| 399 |
daysPerMonth: 0,
|
|
|
|
|
|
|
| 400 |
platformRevenue: 0,
|
| 401 |
privateRevenue: 0,
|
| 402 |
tipsRevenue: 0,
|
| 403 |
-
vehicleType: ''
|
|
|
|
| 404 |
};
|
| 405 |
|
| 406 |
let calculationResults = {};
|
|
|
|
|
|
|
| 407 |
|
| 408 |
// DOM Elements check helper
|
| 409 |
function getElement(id) {
|
|
@@ -504,6 +576,8 @@
|
|
| 504 |
// Step 1 Logic
|
| 505 |
const coursesPerDayInput = getElement('coursesPerDay');
|
| 506 |
const daysPerMonthInput = getElement('daysPerMonth');
|
|
|
|
|
|
|
| 507 |
const totalCoursesPreview = getElement('totalCoursesPreview');
|
| 508 |
const btnStep1Next = getElement('btnStep1Next');
|
| 509 |
|
|
@@ -525,10 +599,12 @@
|
|
| 525 |
|
| 526 |
if (btnStep1Next) {
|
| 527 |
btnStep1Next.addEventListener('click', () => {
|
| 528 |
-
if (!coursesPerDayInput || !daysPerMonthInput) return;
|
| 529 |
|
| 530 |
const courses = parseFloat(coursesPerDayInput.value);
|
| 531 |
const days = parseFloat(daysPerMonthInput.value);
|
|
|
|
|
|
|
| 532 |
|
| 533 |
if (!courses || courses <= 0) {
|
| 534 |
alert('Veuillez entrer un nombre de courses valide.');
|
|
@@ -538,9 +614,19 @@
|
|
| 538 |
alert('Veuillez entrer un nombre de jours valide (1-31).');
|
| 539 |
return;
|
| 540 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 541 |
|
| 542 |
formData.coursesPerDay = courses;
|
| 543 |
formData.daysPerMonth = days;
|
|
|
|
|
|
|
| 544 |
showStep(2);
|
| 545 |
});
|
| 546 |
}
|
|
@@ -610,6 +696,7 @@
|
|
| 610 |
// Step 5 Logic
|
| 611 |
const vehicleBtns = document.querySelectorAll('.vehicle-btn');
|
| 612 |
const vehicleTypeInput = getElement('vehicleType');
|
|
|
|
| 613 |
const btnStep5Back = getElement('btnStep5Back');
|
| 614 |
const btnStep5Calculate = getElement('btnStep5Calculate');
|
| 615 |
|
|
@@ -622,7 +709,7 @@
|
|
| 622 |
if (vehicleTypeInput) vehicleTypeInput.value = value;
|
| 623 |
formData.vehicleType = value;
|
| 624 |
|
| 625 |
-
if (btnStep5Calculate) btnStep5Calculate.disabled = false;
|
| 626 |
});
|
| 627 |
});
|
| 628 |
|
|
@@ -630,52 +717,155 @@
|
|
| 630 |
btnStep5Back.addEventListener('click', () => showStep(4));
|
| 631 |
}
|
| 632 |
|
| 633 |
-
// Calculation Logic
|
| 634 |
function calculateResults() {
|
| 635 |
-
|
| 636 |
const caTotal = formData.platformRevenue + formData.privateRevenue + formData.tipsRevenue;
|
| 637 |
-
const kmTotal = courses * 10;
|
| 638 |
-
|
| 639 |
-
// Cost per km
|
| 640 |
-
let costPerKm = 0.35; // thermique default
|
| 641 |
-
if (formData.vehicleType === 'hybride') costPerKm = 0.28;
|
| 642 |
-
if (formData.vehicleType === 'electrique') costPerKm = 0.20;
|
| 643 |
-
|
| 644 |
-
const costKm = kmTotal * costPerKm;
|
| 645 |
-
const charges = caTotal * 0.22;
|
| 646 |
|
| 647 |
-
//
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
const
|
| 653 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 654 |
// Percentages
|
| 655 |
const pctPlatform = caTotal > 0 ? (formData.platformRevenue / caTotal) * 100 : 0;
|
| 656 |
const pctPrivate = caTotal > 0 ? (formData.privateRevenue / caTotal) * 100 : 0;
|
| 657 |
const pctTips = caTotal > 0 ? (formData.tipsRevenue / caTotal) * 100 : 0;
|
| 658 |
|
| 659 |
-
// Private projection (+15%)
|
| 660 |
-
const privateGain = formData.privateRevenue * 0.15;
|
| 661 |
-
|
| 662 |
calculationResults = {
|
| 663 |
-
courses,
|
| 664 |
caTotal,
|
| 665 |
-
|
| 666 |
-
|
| 667 |
-
|
| 668 |
-
|
|
|
|
| 669 |
profit,
|
|
|
|
| 670 |
pctPlatform,
|
| 671 |
pctPrivate,
|
| 672 |
pctTips,
|
| 673 |
-
|
| 674 |
};
|
| 675 |
|
| 676 |
return calculationResults;
|
| 677 |
}
|
| 678 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 679 |
// TIE Score Calculation
|
| 680 |
function calculateTIEScore() {
|
| 681 |
const results = calculationResults;
|
|
@@ -768,6 +958,8 @@
|
|
| 768 |
|
| 769 |
function displayResults() {
|
| 770 |
const results = calculationResults;
|
|
|
|
|
|
|
| 771 |
|
| 772 |
// Update UI
|
| 773 |
const resultIcon = getElement('resultIcon');
|
|
@@ -783,40 +975,65 @@
|
|
| 783 |
const privateProjection = getElement('privateProjection');
|
| 784 |
const gainProjection = getElement('gainProjection');
|
| 785 |
|
|
|
|
| 786 |
if (profitAmount) profitAmount.textContent = formatMoney(results.profit);
|
| 787 |
if (caTotal) caTotal.textContent = formatMoney(results.caTotal);
|
| 788 |
-
if (chargesAmount) chargesAmount.textContent = '-' + formatMoney(results.
|
| 789 |
-
if (kmCost) kmCost.textContent = '-' + formatMoney(results.
|
| 790 |
if (pctPlatform) pctPlatform.textContent = Math.round(results.pctPlatform) + '%';
|
| 791 |
if (pctPrivate) pctPrivate.textContent = Math.round(results.pctPrivate) + '%';
|
| 792 |
if (pctTips) pctTips.textContent = Math.round(results.pctTips) + '%';
|
| 793 |
|
| 794 |
-
// Result logic
|
| 795 |
-
if (results.profit <
|
| 796 |
if (resultIcon) resultIcon.textContent = '💸';
|
| 797 |
-
if (resultTitle) resultTitle.textContent = `
|
| 798 |
-
if (resultSubtitle) resultSubtitle.textContent =
|
| 799 |
-
} else if (results.profit <
|
| 800 |
if (resultIcon) resultIcon.textContent = '⚖️';
|
| 801 |
-
if (resultTitle) resultTitle.textContent = "
|
| 802 |
-
if (resultSubtitle) resultSubtitle.textContent =
|
| 803 |
} else {
|
| 804 |
if (resultIcon) resultIcon.textContent = '🚀';
|
| 805 |
-
if (resultTitle) resultTitle.textContent = "
|
| 806 |
-
if (resultSubtitle) resultSubtitle.textContent =
|
| 807 |
}
|
| 808 |
|
| 809 |
-
//
|
| 810 |
-
if (
|
| 811 |
-
if (privateProjection)
|
| 812 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 813 |
} else {
|
| 814 |
-
if (privateProjection)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 815 |
}
|
|
|
|
|
|
|
|
|
|
| 816 |
}
|
| 817 |
|
| 818 |
function displayScore() {
|
| 819 |
-
const score = calculateTIEScore();
|
| 820 |
|
| 821 |
const tieScore = getElement('tieScore');
|
| 822 |
const scoreLabel = getElement('scoreLabel');
|
|
@@ -838,20 +1055,54 @@
|
|
| 838 |
if (scoreLabel) scoreLabel.textContent = score.label;
|
| 839 |
if (scoreInterpretation) scoreInterpretation.textContent = score.interpretation;
|
| 840 |
|
| 841 |
-
|
| 842 |
-
|
| 843 |
-
|
| 844 |
-
if (
|
| 845 |
-
|
| 846 |
-
if (
|
| 847 |
-
if (
|
| 848 |
-
|
| 849 |
-
|
| 850 |
-
|
| 851 |
-
if (
|
| 852 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 853 |
} else if (scoreProjectionText) {
|
| 854 |
-
scoreProjectionText.textContent = "Votre
|
| 855 |
}
|
| 856 |
}
|
| 857 |
|
|
@@ -862,6 +1113,11 @@
|
|
| 862 |
alert('Veuillez sélectionner un type de véhicule.');
|
| 863 |
return;
|
| 864 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 865 |
|
| 866 |
showLoading();
|
| 867 |
|
|
@@ -876,10 +1132,58 @@
|
|
| 876 |
});
|
| 877 |
}
|
| 878 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 879 |
// Discover score button
|
| 880 |
const btnDiscoverScore = getElement('btnDiscoverScore');
|
| 881 |
if (btnDiscoverScore) {
|
| 882 |
btnDiscoverScore.addEventListener('click', () => {
|
|
|
|
|
|
|
|
|
|
| 883 |
showScoreLoading();
|
| 884 |
|
| 885 |
setTimeout(() => {
|
|
@@ -889,6 +1193,16 @@
|
|
| 889 |
});
|
| 890 |
}
|
| 891 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 892 |
// Reset button
|
| 893 |
const btnReset = getElement('btnReset');
|
| 894 |
if (btnReset) {
|
|
@@ -897,18 +1211,24 @@
|
|
| 897 |
formData = {
|
| 898 |
coursesPerDay: 0,
|
| 899 |
daysPerMonth: 0,
|
|
|
|
|
|
|
| 900 |
platformRevenue: 0,
|
| 901 |
privateRevenue: 0,
|
| 902 |
tipsRevenue: 0,
|
| 903 |
-
vehicleType: ''
|
|
|
|
| 904 |
};
|
| 905 |
|
| 906 |
// Clear inputs
|
| 907 |
if (coursesPerDayInput) coursesPerDayInput.value = '';
|
| 908 |
if (daysPerMonthInput) daysPerMonthInput.value = '';
|
|
|
|
|
|
|
| 909 |
if (platformRevenueInput) platformRevenueInput.value = '';
|
| 910 |
if (privateRevenueInput) privateRevenueInput.value = '';
|
| 911 |
if (tipsRevenueInput) tipsRevenueInput.value = '';
|
|
|
|
| 912 |
|
| 913 |
vehicleBtns.forEach(b => b.classList.remove('selected'));
|
| 914 |
if (vehicleTypeInput) vehicleTypeInput.value = '';
|
|
@@ -916,6 +1236,9 @@
|
|
| 916 |
|
| 917 |
if (totalCoursesPreview) totalCoursesPreview.textContent = '0';
|
| 918 |
|
|
|
|
|
|
|
|
|
|
| 919 |
// Go back to step 1
|
| 920 |
showStep(1);
|
| 921 |
});
|
|
@@ -932,6 +1255,22 @@
|
|
| 932 |
|
| 933 |
if (daysPerMonthInput) {
|
| 934 |
daysPerMonthInput.addEventListener('keypress', (e) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 935 |
if (e.key === 'Enter' && btnStep1Next) btnStep1Next.click();
|
| 936 |
});
|
| 937 |
}
|
|
|
|
| 109 |
<input type="number" id="daysPerMonth" placeholder="Ex : 22"
|
| 110 |
class="w-full rounded-xl bg-black/40 border border-white/10 px-4 py-3 text-white text-sm outline-none focus:border-emerald-500/50 transition">
|
| 111 |
</div>
|
| 112 |
+
<div>
|
| 113 |
+
<label class="block text-sm text-white/80 mb-2">Heures travaillées dans le mois</label>
|
| 114 |
+
<input type="number" id="hoursPerMonth" placeholder="Ex : 180"
|
| 115 |
+
class="w-full rounded-xl bg-black/40 border border-white/10 px-4 py-3 text-white text-sm outline-none focus:border-emerald-500/50 transition">
|
| 116 |
+
</div>
|
| 117 |
+
<div>
|
| 118 |
+
<label class="block text-sm text-white/80 mb-2">Distance mensuelle estimée (km)</label>
|
| 119 |
+
<input type="number" id="distancePerMonth" placeholder="Ex : 2500"
|
| 120 |
+
class="w-full rounded-xl bg-black/40 border border-white/10 px-4 py-3 text-white text-sm outline-none focus:border-emerald-500/50 transition">
|
| 121 |
+
</div>
|
| 122 |
</div>
|
| 123 |
|
| 124 |
<div class="text-xs text-white/50 mb-4 bg-white/5 rounded-lg p-3">
|
|
|
|
| 208 |
<div class="bg-[#151821] border border-white/10 rounded-2xl p-5">
|
| 209 |
<h2 class="text-lg font-medium text-white mb-4">Votre véhicule</h2>
|
| 210 |
|
| 211 |
+
<div class="grid grid-cols-3 gap-2 mb-4" id="vehicleButtons">
|
| 212 |
<button type="button" data-value="thermique" class="vehicle-btn py-3 rounded-xl border border-white/10 text-white/60 bg-transparent transition text-sm font-medium">
|
| 213 |
Thermique
|
| 214 |
</button>
|
|
|
|
| 221 |
</div>
|
| 222 |
<input type="hidden" id="vehicleType" value="">
|
| 223 |
|
| 224 |
+
<div class="mb-4">
|
| 225 |
+
<label class="block text-sm text-white/80 mb-2">Mensualité crédit / leasing (€)</label>
|
| 226 |
+
<input type="number" id="vehiclePayment" placeholder="Ex : 350"
|
| 227 |
+
class="w-full rounded-xl bg-black/40 border border-white/10 px-4 py-3 text-white text-sm outline-none focus:border-emerald-500/50 transition">
|
| 228 |
+
<p class="text-xs text-white/40 mt-2">Mettre 0 si véhicule déjà payé</p>
|
| 229 |
+
</div>
|
| 230 |
+
|
| 231 |
<div class="flex gap-3">
|
| 232 |
<button id="btnStep5Back" class="w-1/3 py-3 rounded-xl bg-white/5 text-white border border-white/10 text-sm font-medium hover:bg-white/10 transition">
|
| 233 |
Retour
|
|
|
|
| 309 |
Découvrir mon score TIE
|
| 310 |
</button>
|
| 311 |
|
| 312 |
+
<button id="btnShowDetails" class="w-full py-3 rounded-xl bg-white/5 border border-white/10 text-white font-medium text-sm hover:bg-white/10 transition mb-2">
|
| 313 |
+
Voir le détail des coûts
|
| 314 |
+
</button>
|
| 315 |
+
|
| 316 |
<button id="btnReset" class="w-full py-2 mt-3 text-xs text-white/60 hover:text-white transition">
|
| 317 |
Refaire le calcul
|
| 318 |
</button>
|
| 319 |
</div>
|
| 320 |
</div>
|
| 321 |
|
| 322 |
+
<!-- Details Section (Collapsible) -->
|
| 323 |
+
<div id="detailsSection" class="step-container">
|
| 324 |
+
<div class="bg-[#151821] border border-white/10 rounded-2xl p-5 mb-4">
|
| 325 |
+
<h3 class="text-base font-medium text-white mb-4">Détail de votre activité</h3>
|
| 326 |
+
|
| 327 |
+
<div class="space-y-3 mb-4 text-sm">
|
| 328 |
+
<div class="flex justify-between text-white/60">
|
| 329 |
+
<span>Chiffre d'affaires total</span>
|
| 330 |
+
<span id="detailCA" class="text-white font-medium">0 €</span>
|
| 331 |
+
</div>
|
| 332 |
+
<div class="flex justify-between text-white/60">
|
| 333 |
+
<span>Charges sociales (22%)</span>
|
| 334 |
+
<span id="detailSocial" class="text-red-400">-0 €</span>
|
| 335 |
+
</div>
|
| 336 |
+
<div class="flex justify-between text-white/60">
|
| 337 |
+
<span>Coût variable (${calculationResults.costPerKm}€/km)</span>
|
| 338 |
+
<span id="detailVariable" class="text-red-400">-0 €</span>
|
| 339 |
+
</div>
|
| 340 |
+
<div class="flex justify-between text-white/60">
|
| 341 |
+
<span>Assurance (fixe)</span>
|
| 342 |
+
<span id="detailInsurance" class="text-red-400">-200 €</span>
|
| 343 |
+
</div>
|
| 344 |
+
<div class="flex justify-between text-white/60">
|
| 345 |
+
<span>Mensualité véhicule</span>
|
| 346 |
+
<span id="detailPayment" class="text-red-400">-0 €</span>
|
| 347 |
+
</div>
|
| 348 |
+
<div class="border-t border-white/10 pt-3 flex justify-between text-white font-medium">
|
| 349 |
+
<span>BÉNÉFICE NET</span>
|
| 350 |
+
<span id="detailProfit" class="text-emerald-400">0 €</span>
|
| 351 |
+
</div>
|
| 352 |
+
</div>
|
| 353 |
+
|
| 354 |
+
<div class="bg-black/40 rounded-lg p-3 mb-4">
|
| 355 |
+
<div class="flex justify-between text-sm mb-1">
|
| 356 |
+
<span class="text-white/60">Taux horaire réel</span>
|
| 357 |
+
<span id="detailHourly" class="text-white font-medium">0 €/h</span>
|
| 358 |
+
</div>
|
| 359 |
+
<div class="text-xs text-white/40">Basé sur ${formData.hoursPerMonth}h travaillées</div>
|
| 360 |
+
</div>
|
| 361 |
+
|
| 362 |
+
<button id="btnBackFromDetails" class="w-full py-3 rounded-xl bg-white/5 border border-white/10 text-white font-medium text-sm hover:bg-white/10 transition">
|
| 363 |
+
Retour aux résultats
|
| 364 |
+
</button>
|
| 365 |
+
</div>
|
| 366 |
+
</div>
|
| 367 |
+
|
| 368 |
<!-- Score Loading -->
|
| 369 |
<div id="scoreLoading" class="loading-container">
|
| 370 |
<div class="bg-[#151821] border border-white/10 rounded-2xl p-8 text-center">
|
|
|
|
| 438 |
|
| 439 |
<!-- CTAs -->
|
| 440 |
<div class="space-y-3 mb-6">
|
| 441 |
+
<button id="btnBackFromScore" class="w-full py-3 rounded-xl bg-white/5 border border-white/10 text-white font-medium text-sm hover:bg-white/10 transition">
|
| 442 |
+
Retour à mes résultats
|
| 443 |
</button>
|
| 444 |
+
<button class="w-full py-3 rounded-xl bg-emerald-500 text-black font-medium text-sm hover:opacity-90 transition">
|
| 445 |
Développer mes clients privés
|
| 446 |
</button>
|
| 447 |
</div>
|
|
|
|
| 464 |
let formData = {
|
| 465 |
coursesPerDay: 0,
|
| 466 |
daysPerMonth: 0,
|
| 467 |
+
hoursPerMonth: 0,
|
| 468 |
+
distancePerMonth: 0,
|
| 469 |
platformRevenue: 0,
|
| 470 |
privateRevenue: 0,
|
| 471 |
tipsRevenue: 0,
|
| 472 |
+
vehicleType: '',
|
| 473 |
+
vehiclePayment: 0
|
| 474 |
};
|
| 475 |
|
| 476 |
let calculationResults = {};
|
| 477 |
+
let tieProjection = {};
|
| 478 |
+
let tieScoreData = {};
|
| 479 |
|
| 480 |
// DOM Elements check helper
|
| 481 |
function getElement(id) {
|
|
|
|
| 576 |
// Step 1 Logic
|
| 577 |
const coursesPerDayInput = getElement('coursesPerDay');
|
| 578 |
const daysPerMonthInput = getElement('daysPerMonth');
|
| 579 |
+
const hoursPerMonthInput = getElement('hoursPerMonth');
|
| 580 |
+
const distancePerMonthInput = getElement('distancePerMonth');
|
| 581 |
const totalCoursesPreview = getElement('totalCoursesPreview');
|
| 582 |
const btnStep1Next = getElement('btnStep1Next');
|
| 583 |
|
|
|
|
| 599 |
|
| 600 |
if (btnStep1Next) {
|
| 601 |
btnStep1Next.addEventListener('click', () => {
|
| 602 |
+
if (!coursesPerDayInput || !daysPerMonthInput || !hoursPerMonthInput || !distancePerMonthInput) return;
|
| 603 |
|
| 604 |
const courses = parseFloat(coursesPerDayInput.value);
|
| 605 |
const days = parseFloat(daysPerMonthInput.value);
|
| 606 |
+
const hours = parseFloat(hoursPerMonthInput.value);
|
| 607 |
+
const distance = parseFloat(distancePerMonthInput.value);
|
| 608 |
|
| 609 |
if (!courses || courses <= 0) {
|
| 610 |
alert('Veuillez entrer un nombre de courses valide.');
|
|
|
|
| 614 |
alert('Veuillez entrer un nombre de jours valide (1-31).');
|
| 615 |
return;
|
| 616 |
}
|
| 617 |
+
if (!hours || hours <= 0) {
|
| 618 |
+
alert('Veuillez entrer un nombre d\'heures valide.');
|
| 619 |
+
return;
|
| 620 |
+
}
|
| 621 |
+
if (!distance || distance <= 0) {
|
| 622 |
+
alert('Veuillez entrer une distance valide.');
|
| 623 |
+
return;
|
| 624 |
+
}
|
| 625 |
|
| 626 |
formData.coursesPerDay = courses;
|
| 627 |
formData.daysPerMonth = days;
|
| 628 |
+
formData.hoursPerMonth = hours;
|
| 629 |
+
formData.distancePerMonth = distance;
|
| 630 |
showStep(2);
|
| 631 |
});
|
| 632 |
}
|
|
|
|
| 696 |
// Step 5 Logic
|
| 697 |
const vehicleBtns = document.querySelectorAll('.vehicle-btn');
|
| 698 |
const vehicleTypeInput = getElement('vehicleType');
|
| 699 |
+
const vehiclePaymentInput = getElement('vehiclePayment');
|
| 700 |
const btnStep5Back = getElement('btnStep5Back');
|
| 701 |
const btnStep5Calculate = getElement('btnStep5Calculate');
|
| 702 |
|
|
|
|
| 709 |
if (vehicleTypeInput) vehicleTypeInput.value = value;
|
| 710 |
formData.vehicleType = value;
|
| 711 |
|
| 712 |
+
if (btnStep5Calculate && formData.vehicleType) btnStep5Calculate.disabled = false;
|
| 713 |
});
|
| 714 |
});
|
| 715 |
|
|
|
|
| 717 |
btnStep5Back.addEventListener('click', () => showStep(4));
|
| 718 |
}
|
| 719 |
|
| 720 |
+
// Calculation Logic - New Model
|
| 721 |
function calculateResults() {
|
| 722 |
+
// A. CA Total
|
| 723 |
const caTotal = formData.platformRevenue + formData.privateRevenue + formData.tipsRevenue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 724 |
|
| 725 |
+
// B. Variable costs based on vehicle type
|
| 726 |
+
let costPerKm = 0.35; // thermique
|
| 727 |
+
if (formData.vehicleType === 'hybride') costPerKm = 0.25;
|
| 728 |
+
if (formData.vehicleType === 'electrique') costPerKm = 0.15;
|
| 729 |
+
|
| 730 |
+
const variableCost = formData.distancePerMonth * costPerKm;
|
| 731 |
+
|
| 732 |
+
// C. Fixed charges
|
| 733 |
+
const insuranceFixed = 200;
|
| 734 |
+
const vehiclePayment = formData.vehiclePayment || 0;
|
| 735 |
+
const fixedCharges = insuranceFixed + vehiclePayment;
|
| 736 |
+
|
| 737 |
+
// D. Social charges (22% of CA)
|
| 738 |
+
const socialCharges = caTotal * 0.22;
|
| 739 |
+
|
| 740 |
+
// E. Profit
|
| 741 |
+
const profit = caTotal - socialCharges - variableCost - fixedCharges;
|
| 742 |
+
|
| 743 |
+
// F. Hourly rate
|
| 744 |
+
const hourlyRate = formData.hoursPerMonth > 0 ? profit / formData.hoursPerMonth : 0;
|
| 745 |
+
|
| 746 |
// Percentages
|
| 747 |
const pctPlatform = caTotal > 0 ? (formData.platformRevenue / caTotal) * 100 : 0;
|
| 748 |
const pctPrivate = caTotal > 0 ? (formData.privateRevenue / caTotal) * 100 : 0;
|
| 749 |
const pctTips = caTotal > 0 ? (formData.tipsRevenue / caTotal) * 100 : 0;
|
| 750 |
|
|
|
|
|
|
|
|
|
|
| 751 |
calculationResults = {
|
|
|
|
| 752 |
caTotal,
|
| 753 |
+
variableCost,
|
| 754 |
+
fixedCharges,
|
| 755 |
+
socialCharges,
|
| 756 |
+
insuranceFixed,
|
| 757 |
+
vehiclePayment,
|
| 758 |
profit,
|
| 759 |
+
hourlyRate,
|
| 760 |
pctPlatform,
|
| 761 |
pctPrivate,
|
| 762 |
pctTips,
|
| 763 |
+
costPerKm
|
| 764 |
};
|
| 765 |
|
| 766 |
return calculationResults;
|
| 767 |
}
|
| 768 |
|
| 769 |
+
// TIE Projection Logic
|
| 770 |
+
function calculateTIEProjection() {
|
| 771 |
+
const currentPrivateRatio = calculationResults.pctPrivate;
|
| 772 |
+
const caTotal = calculationResults.caTotal;
|
| 773 |
+
|
| 774 |
+
// If private is less than 30%, calculate potential
|
| 775 |
+
if (currentPrivateRatio < 30) {
|
| 776 |
+
// Target: 30% of CA as private
|
| 777 |
+
const targetPrivateRevenue = caTotal * 0.30;
|
| 778 |
+
const currentPrivateRevenue = formData.privateRevenue;
|
| 779 |
+
const additionalPrivateRevenue = targetPrivateRevenue - currentPrivateRevenue;
|
| 780 |
+
|
| 781 |
+
// Private base rate: 2€/km
|
| 782 |
+
// But we need to calculate the gain based on better margins
|
| 783 |
+
// Private has no commission (vs platform which has ~20-25%)
|
| 784 |
+
// So the gain is roughly the commission difference on the additional amount
|
| 785 |
+
|
| 786 |
+
const avgCommissionRate = 0.22; // Average platform commission
|
| 787 |
+
const gainFromConversion = additionalPrivateRevenue * avgCommissionRate;
|
| 788 |
+
|
| 789 |
+
// Recalculate total profit with new private ratio
|
| 790 |
+
const newCaTotal = caTotal; // Same total, just redistributed
|
| 791 |
+
const newSocialCharges = newCaTotal * 0.22;
|
| 792 |
+
const newProfit = newCaTotal - newSocialCharges - calculationResults.variableCost - calculationResults.fixedCharges;
|
| 793 |
+
const monthlyGain = newProfit - calculationResults.profit;
|
| 794 |
+
|
| 795 |
+
tieProjection = {
|
| 796 |
+
hasPotential: true,
|
| 797 |
+
currentPrivateRatio: currentPrivateRatio,
|
| 798 |
+
targetPrivateRatio: 30,
|
| 799 |
+
monthlyGain: monthlyGain > 0 ? monthlyGain : 0,
|
| 800 |
+
message: `En passant à 30% de revenus privés, vous pourriez gagner ${monthlyGain > 0 ? Math.round(monthlyGain) : 0}€ de plus par mois`
|
| 801 |
+
};
|
| 802 |
+
} else {
|
| 803 |
+
tieProjection = {
|
| 804 |
+
hasPotential: false,
|
| 805 |
+
currentPrivateRatio: currentPrivateRatio,
|
| 806 |
+
message: "Votre mix privé/plateforme est déjà optimal (30% ou plus)"
|
| 807 |
+
};
|
| 808 |
+
}
|
| 809 |
+
|
| 810 |
+
return tieProjection;
|
| 811 |
+
}
|
| 812 |
+
|
| 813 |
+
// TIE Score Calculation (0-100)
|
| 814 |
+
function calculateTIEScore() {
|
| 815 |
+
let score = 0;
|
| 816 |
+
const results = calculationResults;
|
| 817 |
+
|
| 818 |
+
// 1. Profitability (40 points max)
|
| 819 |
+
if (results.profit > 3000) score += 40;
|
| 820 |
+
else if (results.profit > 2000) score += 30;
|
| 821 |
+
else if (results.profit > 1500) score += 20;
|
| 822 |
+
else if (results.profit > 800) score += 10;
|
| 823 |
+
else score += 5;
|
| 824 |
+
|
| 825 |
+
// 2. Private revenue mix (20 points max)
|
| 826 |
+
if (results.pctPrivate >= 50) score += 20;
|
| 827 |
+
else if (results.pctPrivate >= 30) score += 15;
|
| 828 |
+
else if (results.pctPrivate >= 15) score += 10;
|
| 829 |
+
else if (results.pctPrivate >= 5) score += 5;
|
| 830 |
+
else score += 0;
|
| 831 |
+
|
| 832 |
+
// 3. Hourly rate efficiency (25 points max)
|
| 833 |
+
if (results.hourlyRate > 25) score += 25;
|
| 834 |
+
else if (results.hourlyRate > 18) score += 20;
|
| 835 |
+
else if (results.hourlyRate > 12) score += 15;
|
| 836 |
+
else if (results.hourlyRate > 8) score += 10;
|
| 837 |
+
else score += 5;
|
| 838 |
+
|
| 839 |
+
// 4. Vehicle efficiency (15 points max)
|
| 840 |
+
if (formData.vehicleType === 'electrique') score += 15;
|
| 841 |
+
else if (formData.vehicleType === 'hybride') score += 10;
|
| 842 |
+
else score += 5; // thermique
|
| 843 |
+
|
| 844 |
+
tieScoreData = {
|
| 845 |
+
total: score,
|
| 846 |
+
label: getScoreLabel(score),
|
| 847 |
+
interpretation: getScoreInterpretation(score)
|
| 848 |
+
};
|
| 849 |
+
|
| 850 |
+
return tieScoreData;
|
| 851 |
+
}
|
| 852 |
+
|
| 853 |
+
function getScoreLabel(score) {
|
| 854 |
+
if (score >= 80) return "Chauffeur Expert";
|
| 855 |
+
if (score >= 65) return "Bon niveau";
|
| 856 |
+
if (score >= 45) return "Activité stable";
|
| 857 |
+
if (score >= 25) return "À optimiser";
|
| 858 |
+
return "Activité à risque";
|
| 859 |
+
}
|
| 860 |
+
|
| 861 |
+
function getScoreInterpretation(score) {
|
| 862 |
+
if (score >= 80) return "🏆 Excellent ! Votre activité est bien optimisée et rentable.";
|
| 863 |
+
if (score >= 65) return "🚀 Très bien. Votre activité est rentable mais peut encore s'améliorer.";
|
| 864 |
+
if (score >= 45) return "⚖️ Correct. Votre activité est viable mais pourrait être plus optimisée.";
|
| 865 |
+
if (score >= 25) return "⚠️ Fragile. Vous devriez développer vos revenus privés et réduire les coûts.";
|
| 866 |
+
return "🚨 Alert. Votre rentabilité est faible. Développez vos clients privés rapidement.";
|
| 867 |
+
}
|
| 868 |
+
|
| 869 |
// TIE Score Calculation
|
| 870 |
function calculateTIEScore() {
|
| 871 |
const results = calculationResults;
|
|
|
|
| 958 |
|
| 959 |
function displayResults() {
|
| 960 |
const results = calculationResults;
|
| 961 |
+
const projection = calculateTIEProjection();
|
| 962 |
+
const score = calculateTIEScore();
|
| 963 |
|
| 964 |
// Update UI
|
| 965 |
const resultIcon = getElement('resultIcon');
|
|
|
|
| 975 |
const privateProjection = getElement('privateProjection');
|
| 976 |
const gainProjection = getElement('gainProjection');
|
| 977 |
|
| 978 |
+
// Update new detailed breakdown
|
| 979 |
if (profitAmount) profitAmount.textContent = formatMoney(results.profit);
|
| 980 |
if (caTotal) caTotal.textContent = formatMoney(results.caTotal);
|
| 981 |
+
if (chargesAmount) chargesAmount.textContent = '-' + formatMoney(results.socialCharges);
|
| 982 |
+
if (kmCost) kmCost.textContent = '-' + formatMoney(results.variableCost);
|
| 983 |
if (pctPlatform) pctPlatform.textContent = Math.round(results.pctPlatform) + '%';
|
| 984 |
if (pctPrivate) pctPrivate.textContent = Math.round(results.pctPrivate) + '%';
|
| 985 |
if (pctTips) pctTips.textContent = Math.round(results.pctTips) + '%';
|
| 986 |
|
| 987 |
+
// Result logic based on new calculation
|
| 988 |
+
if (results.profit < 800) {
|
| 989 |
if (resultIcon) resultIcon.textContent = '💸';
|
| 990 |
+
if (resultTitle) resultTitle.textContent = `Activité non rentable`;
|
| 991 |
+
if (resultSubtitle) resultSubtitle.textContent = `Bénéfice mensuel : ${formatMoney(results.profit)} · Taux horaire : ${formatMoney(results.hourlyRate)}/h`;
|
| 992 |
+
} else if (results.profit < 2000) {
|
| 993 |
if (resultIcon) resultIcon.textContent = '⚖️';
|
| 994 |
+
if (resultTitle) resultTitle.textContent = "Activité viable mais fragile";
|
| 995 |
+
if (resultSubtitle) resultSubtitle.textContent = `Bénéfice : ${formatMoney(results.profit)}/mois · ${formatMoney(results.hourlyRate)}/h`;
|
| 996 |
} else {
|
| 997 |
if (resultIcon) resultIcon.textContent = '🚀';
|
| 998 |
+
if (resultTitle) resultTitle.textContent = "Activité rentable et solide";
|
| 999 |
+
if (resultSubtitle) resultSubtitle.textContent = `Bénéfice : ${formatMoney(results.profit)}/mois · ${formatMoney(results.hourlyRate)}/h`;
|
| 1000 |
}
|
| 1001 |
|
| 1002 |
+
// TIE Projection
|
| 1003 |
+
if (projection.hasPotential && projection.monthlyGain > 0) {
|
| 1004 |
+
if (privateProjection) {
|
| 1005 |
+
privateProjection.classList.remove('hidden');
|
| 1006 |
+
privateProjection.innerHTML = `
|
| 1007 |
+
<div class="flex items-center gap-2 text-emerald-400 font-medium text-sm mb-1">
|
| 1008 |
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/><polyline points="17 6 23 6 23 12"/></svg>
|
| 1009 |
+
Potentiel TIE
|
| 1010 |
+
</div>
|
| 1011 |
+
<div class="text-sm text-white/80">
|
| 1012 |
+
Passer à 30% de privés = <span class="text-emerald-400 font-medium">+${Math.round(projection.monthlyGain)}€/mois</span>
|
| 1013 |
+
</div>
|
| 1014 |
+
`;
|
| 1015 |
+
}
|
| 1016 |
} else {
|
| 1017 |
+
if (privateProjection) {
|
| 1018 |
+
privateProjection.classList.remove('hidden');
|
| 1019 |
+
privateProjection.innerHTML = `
|
| 1020 |
+
<div class="flex items-center gap-2 text-emerald-400 font-medium text-sm mb-1">
|
| 1021 |
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
|
| 1022 |
+
Mix optimal atteint
|
| 1023 |
+
</div>
|
| 1024 |
+
<div class="text-sm text-white/80">
|
| 1025 |
+
${projection.message}
|
| 1026 |
+
</div>
|
| 1027 |
+
`;
|
| 1028 |
+
}
|
| 1029 |
}
|
| 1030 |
+
|
| 1031 |
+
// Store score for display
|
| 1032 |
+
window.currentTIEScore = score;
|
| 1033 |
}
|
| 1034 |
|
| 1035 |
function displayScore() {
|
| 1036 |
+
const score = window.currentTIEScore || calculateTIEScore();
|
| 1037 |
|
| 1038 |
const tieScore = getElement('tieScore');
|
| 1039 |
const scoreLabel = getElement('scoreLabel');
|
|
|
|
| 1055 |
if (scoreLabel) scoreLabel.textContent = score.label;
|
| 1056 |
if (scoreInterpretation) scoreInterpretation.textContent = score.interpretation;
|
| 1057 |
|
| 1058 |
+
// Calculate breakdown points
|
| 1059 |
+
const results = calculationResults;
|
| 1060 |
+
let profitPoints = 0;
|
| 1061 |
+
if (results.profit > 3000) profitPoints = 40;
|
| 1062 |
+
else if (results.profit > 2000) profitPoints = 30;
|
| 1063 |
+
else if (results.profit > 1500) profitPoints = 20;
|
| 1064 |
+
else if (results.profit > 800) profitPoints = 10;
|
| 1065 |
+
else profitPoints = 5;
|
| 1066 |
+
|
| 1067 |
+
let mixPoints = 0;
|
| 1068 |
+
if (results.pctPrivate >= 50) mixPoints = 20;
|
| 1069 |
+
else if (results.pctPrivate >= 30) mixPoints = 15;
|
| 1070 |
+
else if (results.pctPrivate >= 15) mixPoints = 10;
|
| 1071 |
+
else if (results.pctPrivate >= 5) mixPoints = 5;
|
| 1072 |
+
|
| 1073 |
+
let hourlyPoints = 0;
|
| 1074 |
+
if (results.hourlyRate > 25) hourlyPoints = 25;
|
| 1075 |
+
else if (results.hourlyRate > 18) hourlyPoints = 20;
|
| 1076 |
+
else if (results.hourlyRate > 12) hourlyPoints = 15;
|
| 1077 |
+
else if (results.hourlyRate > 8) hourlyPoints = 10;
|
| 1078 |
+
else hourlyPoints = 5;
|
| 1079 |
+
|
| 1080 |
+
let vehiclePoints = 0;
|
| 1081 |
+
if (formData.vehicleType === 'electrique') vehiclePoints = 15;
|
| 1082 |
+
else if (formData.vehicleType === 'hybride') vehiclePoints = 10;
|
| 1083 |
+
else vehiclePoints = 5;
|
| 1084 |
+
|
| 1085 |
+
if (scoreProfit) scoreProfit.textContent = `${profitPoints}/40`;
|
| 1086 |
+
if (scoreMix) scoreMix.textContent = `${mixPoints}/20`;
|
| 1087 |
+
if (scoreQuality) scoreQuality.textContent = `${hourlyPoints}/25`;
|
| 1088 |
+
if (scoreEfficiency) scoreEfficiency.textContent = `${vehiclePoints}/15`;
|
| 1089 |
+
|
| 1090 |
+
if (barProfit) barProfit.style.width = (profitPoints / 40 * 100) + '%';
|
| 1091 |
+
if (barMix) barMix.style.width = (mixPoints / 20 * 100) + '%';
|
| 1092 |
+
if (barQuality) barQuality.style.width = (hourlyPoints / 25 * 100) + '%';
|
| 1093 |
+
if (barEfficiency) barEfficiency.style.width = (vehiclePoints / 15 * 100) + '%';
|
| 1094 |
+
|
| 1095 |
+
// Points to gain
|
| 1096 |
+
const currentPrivateRatio = results.pctPrivate;
|
| 1097 |
+
let pointsToGain = 0;
|
| 1098 |
+
if (currentPrivateRatio < 30) {
|
| 1099 |
+
pointsToGain = Math.round((30 - currentPrivateRatio) / 2);
|
| 1100 |
+
}
|
| 1101 |
+
|
| 1102 |
+
if (scoreProjectionText && pointsToGain > 0) {
|
| 1103 |
+
scoreProjectionText.textContent = `+${pointsToGain} points possibles en développant vos courses privées`;
|
| 1104 |
} else if (scoreProjectionText) {
|
| 1105 |
+
scoreProjectionText.textContent = "Votre profil est bien optimisé";
|
| 1106 |
}
|
| 1107 |
}
|
| 1108 |
|
|
|
|
| 1113 |
alert('Veuillez sélectionner un type de véhicule.');
|
| 1114 |
return;
|
| 1115 |
}
|
| 1116 |
+
|
| 1117 |
+
// Get vehicle payment
|
| 1118 |
+
if (vehiclePaymentInput) {
|
| 1119 |
+
formData.vehiclePayment = parseFloat(vehiclePaymentInput.value) || 0;
|
| 1120 |
+
}
|
| 1121 |
|
| 1122 |
showLoading();
|
| 1123 |
|
|
|
|
| 1132 |
});
|
| 1133 |
}
|
| 1134 |
|
| 1135 |
+
// Show Details button
|
| 1136 |
+
const btnShowDetails = getElement('btnShowDetails');
|
| 1137 |
+
const btnBackFromDetails = getElement('btnBackFromDetails');
|
| 1138 |
+
const detailsSection = getElement('detailsSection');
|
| 1139 |
+
|
| 1140 |
+
function showDetails() {
|
| 1141 |
+
const results = calculationResults;
|
| 1142 |
+
|
| 1143 |
+
// Update detail values
|
| 1144 |
+
const detailCA = getElement('detailCA');
|
| 1145 |
+
const detailSocial = getElement('detailSocial');
|
| 1146 |
+
const detailVariable = getElement('detailVariable');
|
| 1147 |
+
const detailInsurance = getElement('detailInsurance');
|
| 1148 |
+
const detailPayment = getElement('detailPayment');
|
| 1149 |
+
const detailProfit = getElement('detailProfit');
|
| 1150 |
+
const detailHourly = getElement('detailHourly');
|
| 1151 |
+
|
| 1152 |
+
if (detailCA) detailCA.textContent = formatMoney(results.caTotal);
|
| 1153 |
+
if (detailSocial) detailSocial.textContent = '-' + formatMoney(results.socialCharges);
|
| 1154 |
+
if (detailVariable) detailVariable.textContent = '-' + formatMoney(results.variableCost);
|
| 1155 |
+
if (detailInsurance) detailInsurance.textContent = '-' + formatMoney(results.insuranceFixed);
|
| 1156 |
+
if (detailPayment) detailPayment.textContent = '-' + formatMoney(results.vehiclePayment);
|
| 1157 |
+
if (detailProfit) detailProfit.textContent = formatMoney(results.profit);
|
| 1158 |
+
if (detailHourly) detailHourly.textContent = formatMoney(results.hourlyRate) + '/h';
|
| 1159 |
+
|
| 1160 |
+
// Hide result, show details
|
| 1161 |
+
const resultScreen = getElement('resultScreen');
|
| 1162 |
+
if (resultScreen) resultScreen.classList.remove('active');
|
| 1163 |
+
if (detailsSection) detailsSection.classList.add('active');
|
| 1164 |
+
}
|
| 1165 |
+
|
| 1166 |
+
function hideDetails() {
|
| 1167 |
+
if (detailsSection) detailsSection.classList.remove('active');
|
| 1168 |
+
const resultScreen = getElement('resultScreen');
|
| 1169 |
+
if (resultScreen) resultScreen.classList.add('active');
|
| 1170 |
+
}
|
| 1171 |
+
|
| 1172 |
+
if (btnShowDetails) {
|
| 1173 |
+
btnShowDetails.addEventListener('click', showDetails);
|
| 1174 |
+
}
|
| 1175 |
+
|
| 1176 |
+
if (btnBackFromDetails) {
|
| 1177 |
+
btnBackFromDetails.addEventListener('click', hideDetails);
|
| 1178 |
+
}
|
| 1179 |
+
|
| 1180 |
// Discover score button
|
| 1181 |
const btnDiscoverScore = getElement('btnDiscoverScore');
|
| 1182 |
if (btnDiscoverScore) {
|
| 1183 |
btnDiscoverScore.addEventListener('click', () => {
|
| 1184 |
+
// Hide details if open
|
| 1185 |
+
if (detailsSection) detailsSection.classList.remove('active');
|
| 1186 |
+
|
| 1187 |
showScoreLoading();
|
| 1188 |
|
| 1189 |
setTimeout(() => {
|
|
|
|
| 1193 |
});
|
| 1194 |
}
|
| 1195 |
|
| 1196 |
+
// Back button from score to results
|
| 1197 |
+
const btnBackFromScore = getElement('btnBackFromScore');
|
| 1198 |
+
if (btnBackFromScore) {
|
| 1199 |
+
btnBackFromScore.addEventListener('click', () => {
|
| 1200 |
+
const scoreScreen = getElement('scoreScreen');
|
| 1201 |
+
if (scoreScreen) scoreScreen.classList.remove('active');
|
| 1202 |
+
showResults();
|
| 1203 |
+
});
|
| 1204 |
+
}
|
| 1205 |
+
|
| 1206 |
// Reset button
|
| 1207 |
const btnReset = getElement('btnReset');
|
| 1208 |
if (btnReset) {
|
|
|
|
| 1211 |
formData = {
|
| 1212 |
coursesPerDay: 0,
|
| 1213 |
daysPerMonth: 0,
|
| 1214 |
+
hoursPerMonth: 0,
|
| 1215 |
+
distancePerMonth: 0,
|
| 1216 |
platformRevenue: 0,
|
| 1217 |
privateRevenue: 0,
|
| 1218 |
tipsRevenue: 0,
|
| 1219 |
+
vehicleType: '',
|
| 1220 |
+
vehiclePayment: 0
|
| 1221 |
};
|
| 1222 |
|
| 1223 |
// Clear inputs
|
| 1224 |
if (coursesPerDayInput) coursesPerDayInput.value = '';
|
| 1225 |
if (daysPerMonthInput) daysPerMonthInput.value = '';
|
| 1226 |
+
if (hoursPerMonthInput) hoursPerMonthInput.value = '';
|
| 1227 |
+
if (distancePerMonthInput) distancePerMonthInput.value = '';
|
| 1228 |
if (platformRevenueInput) platformRevenueInput.value = '';
|
| 1229 |
if (privateRevenueInput) privateRevenueInput.value = '';
|
| 1230 |
if (tipsRevenueInput) tipsRevenueInput.value = '';
|
| 1231 |
+
if (vehiclePaymentInput) vehiclePaymentInput.value = '';
|
| 1232 |
|
| 1233 |
vehicleBtns.forEach(b => b.classList.remove('selected'));
|
| 1234 |
if (vehicleTypeInput) vehicleTypeInput.value = '';
|
|
|
|
| 1236 |
|
| 1237 |
if (totalCoursesPreview) totalCoursesPreview.textContent = '0';
|
| 1238 |
|
| 1239 |
+
// Hide details if open
|
| 1240 |
+
if (detailsSection) detailsSection.classList.remove('active');
|
| 1241 |
+
|
| 1242 |
// Go back to step 1
|
| 1243 |
showStep(1);
|
| 1244 |
});
|
|
|
|
| 1255 |
|
| 1256 |
if (daysPerMonthInput) {
|
| 1257 |
daysPerMonthInput.addEventListener('keypress', (e) => {
|
| 1258 |
+
if (e.key === 'Enter') {
|
| 1259 |
+
if (hoursPerMonthInput) hoursPerMonthInput.focus();
|
| 1260 |
+
}
|
| 1261 |
+
});
|
| 1262 |
+
}
|
| 1263 |
+
|
| 1264 |
+
if (hoursPerMonthInput) {
|
| 1265 |
+
hoursPerMonthInput.addEventListener('keypress', (e) => {
|
| 1266 |
+
if (e.key === 'Enter') {
|
| 1267 |
+
if (distancePerMonthInput) distancePerMonthInput.focus();
|
| 1268 |
+
}
|
| 1269 |
+
});
|
| 1270 |
+
}
|
| 1271 |
+
|
| 1272 |
+
if (distancePerMonthInput) {
|
| 1273 |
+
distancePerMonthInput.addEventListener('keypress', (e) => {
|
| 1274 |
if (e.key === 'Enter' && btnStep1Next) btnStep1Next.click();
|
| 1275 |
});
|
| 1276 |
}
|