iWaffle21 commited on
Commit
30d34bb
·
verified ·
1 Parent(s): 220640e

Create an interactive Pressure Washing Estimate Calculator and publish it inside the "Quotes" channel.

Browse files

UI: a Service Type dropdown with: Fleet Car Washing, Driveway Cleaning, Fence Cleaning, Roof Cleaning, Gutter Cleaning, Deck/Patio Cleaning, House Washing.
For every service except Fleet Car Washing, show two tabs named "Condition" and "Size [Sqr Feet]".

Condition: dropdown → Light, Average, Heavy.

Size [Sqr Feet]: numeric input for custom sq ft.

For Fleet Car Washing, show two tabs named "Number Of Vehicles" and "Plans".

Number Of Vehicles: numeric input (how many vehicles).

Plans: dropdown → Standard, Premium.

Pricing rules:

Driveway Cleaning: if size ≤ 500 → flat $75.99. If size > 500 → $75.99 + ((size − 500) × $0.17). Apply condition multiplier: Light ×1.0, Average ×1.2, Heavy ×1.4.

Fence & Deck/Patio: Light = size × $0.25; Average = size × $0.35; Heavy = size × $0.45.

Roof Cleaning: Light = size × $0.35; Average = size × $0.45; Heavy = size × $0.55.

House Washing (industry standard): Light = size × $0.30; Average = size × $0.40; Heavy = size × $0.50.

Gutter Cleaning: input is length (ft) in the Size tab; price = length × $1.25. (Condition tab may be hidden or disabled for gutters.)

Fleet Car Washing: Base per-car price: Standard = $25, Premium = $35. Bulk discounts applied per car when quantity ≥ 3: 3–5 cars → subtract $2 per car; 6–10 → subtract $3 per car; 11+ → subtract $5 per car. (Example: 5 premium cars = 5 × (35 − 2) = $165.)

Behavior: auto-calculate and display “Estimated Total: $___” live whenever inputs change. Reset irrelevant inputs when switching services. Validate numeric inputs (no negatives). Format output as currency.

Style: clean card layout, rounded corners, bold labels, subtle blue accent, smooth transitions between tabs.

components/estimate-calculator.js CHANGED
@@ -1 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class EstimateCalculator extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ .calculator-card {
7
+ background: white;
8
+ border-radius: 12px;
9
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
10
+ padding: 2rem;
11
+ max-width: 600px;
12
+ margin: 0 auto;
13
+ }
14
+ .form-group {
15
+ margin-bottom: 1.5rem;
16
+ }
17
+ .form-label {
18
+ display: block;
19
+ font-weight: 600;
20
+ color: #1e293b;
21
+ margin-bottom: 0.5rem;
22
+ }
23
+ .form-input, .form-select {
24
+ width: 100%;
25
+ padding: 0.75rem;
26
+ border: 1px solid #e2e8f0;
27
+ border-radius: 0.5rem;
28
+ transition: all 0.3s ease;
29
+ font-size: 1rem;
30
+ }
31
+ .form-input:focus, .form-select:focus {
32
+ outline: none;
33
+ border-color: #3b82f6;
34
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
35
+ }
36
+ .tabs-container {
37
+ display: flex;
38
+ margin-bottom: 1.5rem;
39
+ border-bottom: 1px solid #e2e8f0;
40
+ }
41
+ .tab {
42
+ padding: 0.75rem 1.5rem;
43
+ background: white;
44
+ border: 1px solid #e2e8f0;
45
+ border-bottom: none;
46
+ border-radius: 0.5rem 0.5rem 0 0;
47
+ cursor: pointer;
48
+ transition: all 0.3s ease;
49
+ font-weight: 500;
50
+ color: #64748b;
51
+ }
52
+ .tab.active {
53
+ background: #3b82f6;
54
+ color: white;
55
+ }
56
+ .result {
57
+ margin-top: 2rem;
58
+ padding: 1.5rem;
59
+ background: #f8fafc;
60
+ border-radius: 0.5rem;
61
+ text-align: center;
62
+ font-weight: 600;
63
+ color: #1e293b;
64
+ border: 1px solid #e2e8f0;
65
+ font-size: 1.25rem;
66
+ transition: all 0.3s ease;
67
+ }
68
+ .hidden {
69
+ display: none;
70
+ }
71
+ .error {
72
+ color: #dc2626;
73
+ font-size: 0.875rem;
74
+ margin-top: 0.5rem;
75
+ }
76
+ input[type="number"]::-webkit-outer-spin-button,
77
+ input[type="number"]::-webkit-inner-spin-button {
78
+ -webkit-appearance: none;
79
+ margin: 0;
80
+ }
81
+ input[type="number"] {
82
+ -moz-appearance: textfield;
83
+ }
84
+ </style>
85
+ <div class="calculator-card">
86
+ <div class="form-group">
87
+ <label class="form-label">Service Type</label>
88
+ <select id="service" class="form-select">
89
+ <option value="">Select a service</option>
90
+ <option value="fleet">Fleet Car Washing</option>
91
+ <option value="driveway">Driveway Cleaning</option>
92
+ <option value="fence">Fence Cleaning</option>
93
+ <option value="roof">Roof Cleaning</option>
94
+ <option value="gutter">Gutter Cleaning</option>
95
+ <option value="deck">Deck/Patio Cleaning</option>
96
+ <option value="house">House Washing</option>
97
+ </select>
98
+ </div>
99
 
100
+ <!-- Standard Tabs for most services -->
101
+ <div id="standardTabs" class="hidden">
102
+ <div class="tabs-container">
103
+ <div class="tab active" data-tab="condition">Condition</div>
104
+ <div class="tab" data-tab="size">Size [Sqr Feet]</div>
105
+ </div>
106
+
107
+ <!-- Fleet Car Washing Tabs -->
108
+ <div id="fleetTabs" class="hidden">
109
+ <div class="tabs-container">
110
+ <div class="tab active" data-tab="vehicles">Number Of Vehicles</div>
111
+ <div class="tab" data-tab="plans">Plans</div>
112
+ </div>
113
+
114
+ <!-- Condition Tab Content -->
115
+ <div id="conditionTab" class="tab-content active">
116
+ <div class="form-group">
117
+ <label class="form-label">Condition</label>
118
+ <select id="condition" class="form-select">
119
+ <option value="light">Light</option>
120
+ <option value="average">Average</option>
121
+ <option value="heavy">Heavy</option>
122
+ </div>
123
+ </div>
124
+
125
+ <!-- Size Tab Content -->
126
+ <div id="sizeTab" class="tab-content">
127
+ <div class="form-group">
128
+ <label class="form-label">Size [Sqr Feet]</label>
129
+ <input type="number" id="size" class="form-input" min="0" placeholder="Enter square footage">
130
+ </div>
131
+ </div>
132
+
133
+ <!-- Vehicles Tab Content -->
134
+ <div id="vehiclesTab" class="tab-content hidden">
135
+ <div class="form-group">
136
+ <label class="form-label">Number Of Vehicles</label>
137
+ <input type="number" id="vehicles" class="form-input" min="0" placeholder="Enter number of vehicles">
138
+ </div>
139
+ </div>
140
+
141
+ <!-- Plans Tab Content -->
142
+ <div id="plansTab" class="tab-content hidden">
143
+ <div class="form-group">
144
+ <label class="form-label">Plans</label>
145
+ <select id="plan" class="form-select">
146
+ <option value="standard">Standard</option>
147
+ <option value="premium">Premium</option>
148
+ </div>
149
+ </div>
150
+
151
+ <div id="result" class="result">
152
+ Estimated Total: $0.00
153
+ </div>
154
+ </div>
155
+ `;
156
+
157
+ this.initializeCalculator();
158
+ }
159
+
160
+ initializeCalculator() {
161
+ const serviceSelect = this.shadowRoot.getElementById('service');
162
+ const conditionSelect = this.shadowRoot.getElementById('condition');
163
+ const sizeInput = this.shadowRoot.getElementById('size');
164
+ const vehiclesInput = this.shadowRoot.getElementById('vehicles');
165
+ const planSelect = this.shadowRoot.getElementById('plan');
166
+ const resultDiv = this.shadowRoot.getElementById('result');
167
+
168
+ // Tab switching functionality
169
+ const tabs = this.shadowRoot.querySelectorAll('.tab');
170
+ tabs.forEach(tab => {
171
+ tab.addEventListener('click', () => {
172
+ const tabType = tab.getAttribute('data-tab');
173
+
174
+ // Deactivate all tabs
175
+ tabs.forEach(t => t.classList.remove('active'));
176
+ tab.classList.add('active');
177
+
178
+ // Show corresponding tab content
179
+ const tabContents = this.shadowRoot.querySelectorAll('.tab-content');
180
+ tabContents.forEach(content => content.classList.add('hidden'));
181
+
182
+ const targetTab = this.shadowRoot.getElementById(`${tabType}Tab`);
183
+ if (targetTab) {
184
+ targetTab.classList.remove('hidden');
185
+ }
186
+ });
187
+ });
188
+
189
+ // Calculate function
190
+ const calculateEstimate = () => {
191
+ const service = serviceSelect.value;
192
+ const condition = conditionSelect.value;
193
+ const size = parseFloat(sizeInput.value) || 0;
194
+ const vehicles = parseInt(vehiclesInput.value) || 0;
195
+ const plan = planSelect.value;
196
+
197
+ let price = 0;
198
+
199
+ // Validation
200
+ if (size < 0 || vehicles < 0) {
201
+ resultDiv.textContent = 'Please enter valid positive numbers';
202
+ return;
203
+ }
204
+
205
+ switch (service) {
206
+ case 'driveway':
207
+ if (size <= 500) {
208
+ price = 75.99;
209
+ } else {
210
+ price = 75.99 + ((size - 500) * 0.17);
211
+ }
212
+ // Apply condition multiplier
213
+ if (condition === 'average') price *= 1.2;
214
+ if (condition === 'heavy') price *= 1.4;
215
+ break;
216
+
217
+ case 'fence':
218
+ case 'deck':
219
+ if (condition === 'light') price = size * 0.25;
220
+ if (condition === 'average') price = size * 0.35;
221
+ if (condition === 'heavy') price = size * 0.45;
222
+ break;
223
+
224
+ case 'roof':
225
+ if (condition === 'light') price = size * 0.35;
226
+ if (condition === 'average') price = size * 0.45;
227
+ if (condition === 'heavy') price = size * 0.55;
228
+ break;
229
+
230
+ case 'house':
231
+ if (condition === 'light') price = size * 0.30;
232
+ if (condition === 'average') price = size * 0.40;
233
+ if (condition === 'heavy') price = size * 0.50;
234
+ break;
235
+
236
+ case 'gutter':
237
+ price = size * 1.25;
238
+ break;
239
+
240
+ case 'fleet':
241
+ let basePrice = plan === 'standard' ? 25 : 35;
242
+
243
+ // Apply bulk discounts
244
+ if (vehicles >= 3 && vehicles <= 5) {
245
+ basePrice -= 2;
246
+ } else if (vehicles >= 6 && vehicles <= 10) {
247
+ basePrice -= 3;
248
+ } else if (vehicles >= 11) {
249
+ basePrice -= 5;
250
+ }
251
+ price = basePrice * vehicles;
252
+ break;
253
+ }
254
+
255
+ // Format as currency
256
+ const formattedPrice = new Intl.NumberFormat('en-US', {
257
+ style: 'currency',
258
+ currency: 'USD'
259
+ }).format(price);
260
+
261
+ resultDiv.textContent = `Estimated Total: ${formattedPrice}`;
262
+ }
263
+
264
+ // Service change handler
265
+ serviceSelect.addEventListener('change', () => {
266
+ const service = serviceSelect.value;
267
+
268
+ // Reset inputs
269
+ conditionSelect.value = 'light';
270
+ sizeInput.value = '';
271
+ vehiclesInput.value = '';
272
+ planSelect.value = 'standard';
273
+
274
+ // Show/hide appropriate tabs
275
+ const standardTabs = this.shadowRoot.getElementById('standardTabs');
276
+ const fleetTabs = this.shadowRoot.getElementById('fleetTabs');
277
+
278
+ if (service === 'fleet') {
279
+ standardTabs.classList.add('hidden');
280
+ fleetTabs.classList.remove('hidden');
281
+
282
+ // Show vehicles tab by default
283
+ this.shadowRoot.querySelectorAll('.tab-content').forEach(content => content.classList.add('hidden'));
284
+ this.shadowRoot.getElementById('vehiclesTab').classList.remove('hidden');
285
+ } else {
286
+ standardTabs.classList.remove('hidden');
287
+ fleetTabs.classList.add('hidden');
288
+
289
+ // Show condition tab by default
290
+ this.shadowRoot.getElementById('conditionTab').classList.remove('hidden');
291
+ }
292
+
293
+ calculateEstimate();
294
+ });
295
+
296
+ // Input change listeners
297
+ conditionSelect.addEventListener('change', calculateEstimate);
298
+ sizeInput.addEventListener('input', calculateEstimate);
299
+ vehiclesInput.addEventListener('input', calculateEstimate);
300
+ planSelect.addEventListener('change', calculateEstimate);
301
+
302
+ // Initial calculation
303
+ calculateEstimate();
304
+ }
305
+ }
306
+
307
+ customElements.define('estimate-calculator', EstimateCalculator);
components/navbar.js CHANGED
@@ -124,8 +124,8 @@ class CustomNavbar extends HTMLElement {
124
  <li class="nav-link"><a href="/">Home</a></li>
125
  <li class="nav-link"><a href="/services.html">Services</a></li>
126
  <li class="nav-link"><a href="/gallery.html">Gallery</a></li>
127
- <li class="nav-link"><a href="/contact.html">Contact</a></li>
128
- <li class="nav-link"><a href="/contact.html" class="cta-button">Free Quote</a></li>
129
  </ul>
130
  <button class="mobile-menu-button">
131
  <i data-feather="menu"></i>
 
124
  <li class="nav-link"><a href="/">Home</a></li>
125
  <li class="nav-link"><a href="/services.html">Services</a></li>
126
  <li class="nav-link"><a href="/gallery.html">Gallery</a></li>
127
+ <li class="nav-link"><a href="/contact.html">Contact</a></li>
128
+ <li class="nav-link"><a href="/estimate-calculator.html">Free Quote Calculator</a></li>
129
  </ul>
130
  <button class="mobile-menu-button">
131
  <i data-feather="menu"></i>
estimate-calculator.html ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Free Quote Calculator | Phoenix Pressure Washing | Oklahoma City</title>
7
+ <meta name="description" content="Get an instant pressure washing estimate for your Oklahoma City property. Calculate pricing for driveway, roof, fence, house washing and more.">
8
+ <link rel="icon" type="image/x-icon" href="/assets/img/favicon.ico">
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
11
+ <link rel="stylesheet" href="/assets/css/styles.css">
12
+ </head>
13
+ <body class="bg-gray-50">
14
+ <custom-navbar></custom-navbar>
15
+
16
+ <!-- Calculator Hero -->
17
+ <section class="hero-banner">
18
+ <div class="container mx-auto px-4">
19
+ <div class="max-w-3xl">
20
+ <h1>Free Quote Calculator</h1>
21
+ <p>Get an instant estimate for our professional pressure washing services in Oklahoma City</p>
22
+ <a href="/contact.html" class="inline-block bg-primary text-white font-bold py-3 px-8 rounded-lg hover:bg-red-600 transition duration-300 shadow-lg hover:shadow-xl">Contact Us Directly</a>
23
+ </div>
24
+ </div>
25
+ </section>
26
+
27
+ <!-- Calculator Section -->
28
+ <section class="py-16 bg-white">
29
+ <div class="container mx-auto px-4">
30
+ <div class="text-center mb-12">
31
+ <h2 class="text-3xl font-bold text-gray-800 mb-4">Instant Pressure Washing Estimate</h2>
32
+ <p class="text-gray-600 max-w-2xl mx-auto">Select your service type and provide details for an accurate quote</p>
33
+ </div>
34
+
35
+ <estimate-calculator></estimate-calculator>
36
+
37
+ <div class="text-center mt-12">
38
+ <p class="text-gray-600 mb-4">Need a more detailed quote or have special requirements?</p>
39
+ <a href="/contact.html" class="inline-block bg-primary text-white font-bold py-3 px-8 rounded-lg hover:bg-red-600 transition duration-300">Contact Us for a Custom Quote</a>
40
+ </div>
41
+ </div>
42
+ </section>
43
+
44
+ <!-- FAQ -->
45
+ <section class="py-16 bg-gray-50">
46
+ <div class="container mx-auto px-4">
47
+ <div class="text-center mb-12">
48
+ <h2 class="text-3xl font-bold text-gray-800 mb-4">Calculator FAQ</h2>
49
+ <p class="text-gray-600 max-w-2xl mx-auto">Common questions about our pressure washing pricing and services</p>
50
+ </div>
51
+
52
+ <div class="max-w-3xl mx-auto">
53
+ <div class="faq-item">
54
+ <div class="faq-question">
55
+ <h3 class="text-xl font-semibold text-gray-800">How accurate is this calculator?</h3>
56
+ <i data-feather="chevron-down" class="text-primary transition-transform duration-300"></i>
57
+ </div>
58
+ <div class="faq-answer">
59
+ <p class="text-gray-600">Our calculator provides estimates based on our standard pricing structure. Final quotes may vary based on site-specific conditions, accessibility, and additional requirements.</p>
60
+ </div>
61
+ </div>
62
+
63
+ <div class="faq-item">
64
+ <div class="faq-question">
65
+ <h3 class="text-xl font-semibold text-gray-800">Do you offer discounts for multiple services?</h3>
66
+ <i data-feather="chevron-down" class="text-primary transition-transform duration-300"></i>
67
+ </div>
68
+ <div class="faq-answer">
69
+ <p class="text-gray-600">Yes! When you book multiple services together, we offer package discounts. Contact us directly for the best pricing on bundled services.</p>
70
+ </div>
71
+ </div>
72
+
73
+ <div class="faq-item">
74
+ <div class="faq-question">
75
+ <h3 class="text-xl font-semibold text-gray-800">What's included in the quoted price?</h3>
76
+ <i data-feather="chevron-down" class="text-primary transition-transform duration-300"></i>
77
+ </div>
78
+ <div class="faq-answer">
79
+ <p class="text-gray-600">All quoted prices include labor, equipment, and eco-friendly cleaning solutions. Additional charges may apply for extremely difficult access, extensive prep work, or heavily soiled conditions requiring multiple passes.</p>
80
+ </div>
81
+ </div>
82
+ </div>
83
+ </div>
84
+ </section>
85
+
86
+ <custom-footer></custom-footer>
87
+
88
+ <script src="/components/navbar.js"></script>
89
+ <script src="/components/footer.js"></script>
90
+ <script src="/components/estimate-calculator.js"></script>
91
+ <script>
92
+ feather.replace();
93
+ </script>
94
+ </body>
95
+ </html>