Find Your Trusted Local Pro in South Africa

Get free, no-obligation quotes from top-rated, verified professionals. Message, call, or request online. Your journey to a job well done starts here.

🔒 POPI Compliant 500+ Vetted Pros 🛡️ Project Support 📞 24/7 Assistance
0
Jobs Completed
0
Active Professionals

Choose Your Preferred Way to Connect

📞

Call Us

Directly speak to our professionals

Call Now
💬

WhatsApp

Quick chat on WhatsApp

Message Us
📧

Email

Send your project details

Send Email
🏢

Visit Us

Meet our support team

Get Directions

Get Matched with Up to 5 Verified Local Pros

Tell us about your project in 60 seconds. It's completely free with no obligation.

🔒 We respect your privacy. No spam. No hidden fees. Our service is free for homeowners.

Why Thousands Trust ServiceLink SA

Free & No Obligation

Get quotes from multiple verified providers with zero commitment

🛡️

Verified Professionals

All providers are background-checked and quality-vetted

💰

Best Price Guarantee

Compare quotes and choose the best value for your budget

Why Homeowners Trust Us

Verified Professionals

All our pros are vetted and background checked for peace of mind.

Project Support

We guide you every step to ensure smooth project completion.

Satisfaction Guarantee

Your satisfaction is our top priority, every single time.

Meet Our Top Professionals

Mr Rammala

Expert Plumber with 10+ years experience.

J Smith

Certified Electrician delivering top quality work.

M Johnson

Air Conditioning Specialist ensuring perfect installations.

Frequently Asked Questions

How long does it take to get matched with pros?

You can expect matches within minutes after submitting your project details.

Is there any cost for requesting quotes?

Are the professionals verified?

Ready to Get Started?

Connect with top professionals today and get your project done right.

✅ Request Free Quotes
// ================== SERVICE FUNCTIONS ================== function populateServices() { const serviceSelect = document.getElementById('service'); if (!serviceSelect) return; // Clear existing options except first while (serviceSelect.options.length > 1) { serviceSelect.remove(1); } // Add services from data Object.keys(window.servicelinkServices).forEach(key => { const option = document.createElement('option'); option.value = key; option.textContent = window.servicelinkServices[key].title || key; serviceSelect.appendChild(option); }); // Ensure dropdown is visible and enabled serviceSelect.style.display = ''; serviceSelect.disabled = false; } function populateSubcategories(serviceKey) { const subcategoryGroup = document.getElementById('subcategory-group'); const subcategorySelect = document.getElementById('service_subcategory'); if (!subcategoryGroup || !subcategorySelect) return; // Reset subcategory subcategorySelect.innerHTML = ''; subcategorySelect.disabled = true; subcategoryGroup.style.display = 'none'; if (!serviceKey || !window.servicelinkServices || !window.servicelinkServices[serviceKey]) return; const service = window.servicelinkServices[serviceKey]; // Handle different data structures let categories = []; if (service.categories && Array.isArray(service.categories)) { categories = service.categories; } else if (service.categories && typeof service.categories === 'object') { categories = Object.values(service.categories); } else if (service.subcategories) { if (Array.isArray(service.subcategories)) { categories = service.subcategories; } else if (typeof service.subcategories === 'object') { categories = Object.values(service.subcategories); } } if (!categories || categories.length === 0) return; // Populate the dropdown categories.forEach(category => { const categoryName = typeof category === 'string' ? category : (category.name || category.title || ''); if (categoryName) { const option = document.createElement('option'); option.value = categoryName.toLowerCase().replace(/\s+/g, '_'); option.textContent = categoryName; subcategorySelect.appendChild(option); } }); subcategorySelect.disabled = false; subcategoryGroup.style.display = 'block'; } // ================== FORM SUBMISSION ================== function setupFormSubmission() { const form = document.getElementById('quote-form'); if (!form) return; form.addEventListener('submit', async function(e) { e.preventDefault(); const submitBtn = form.querySelector('button[type="submit"]'); const submitText = form.querySelector('.submit-text'); const loadingText = form.querySelector('.loading-text'); // Show loading state submitBtn.disabled = true; submitText.classList.add('hidden'); loadingText.classList.remove('hidden'); try { const formData = new FormData(form); const response = await fetch('https://www.servicelinksa.co.za/wp-admin/admin-ajax.php', { method: 'POST', body: formData }); const data = await response.json(); if (data.success) { showSuccessMessage('✅ Your quote request has been submitted successfully!'); form.reset(); // Reset to step 1 document.getElementById('step-1').classList.remove('hidden'); document.getElementById('step-2').classList.add('hidden'); } else { showErrorMessage(data.message || '❌ There was an error submitting the form.'); } } catch (error) { showErrorMessage('❌ Network error. Please try again.'); console.error('Submission error:', error); } finally { // Reset button state submitBtn.disabled = false; submitText.classList.remove('hidden'); loadingText.classList.add('hidden'); } }); } // Success/Error Messages function showSuccessMessage(message) { const messageDiv = document.createElement('div'); messageDiv.className = 'success-message'; messageDiv.innerHTML = `
${message}
`; document.getElementById('contact-form').prepend(messageDiv); setTimeout(() => messageDiv.remove(), 5000); } function showErrorMessage(message) { const messageDiv = document.createElement('div'); messageDiv.className = 'error-message'; messageDiv.innerHTML = `
${message}
`; document.getElementById('contact-form').prepend(messageDiv); setTimeout(() => messageDiv.remove(), 5000); } // ================== MAIN CODE ================== document.addEventListener("DOMContentLoaded", function() { // Get all elements const nextButtons = document.querySelectorAll('.next-step'); const prevButtons = document.querySelectorAll('.prev-step'); const step1 = document.getElementById('step-1'); const step2 = document.getElementById('step-2'); const serviceSelect = document.getElementById('service'); let currentStep = 0; // ================== EVENT LISTENERS ================== if (serviceSelect) { serviceSelect.addEventListener('change', function() { populateSubcategories(this.value); }); } // Next button nextButtons.forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); if (currentStep === 0) { // Move to step 2 step1.classList.add('hidden'); step1.classList.remove('active'); step2.classList.remove('hidden'); step2.classList.add('active'); // Populate services dropdown populateServices(); currentStep = 1; } }); }); // Previous button prevButtons.forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); if (currentStep === 1) { // Move back to step 1 step2.classList.add('hidden'); step2.classList.remove('active'); step1.classList.remove('hidden'); step1.classList.add('active'); currentStep = 0; } }); }); // Initialize form submission setupFormSubmission(); // Only initialize debug if admin });