WELCOME TO CARRION SERVICES YOUR VISION OUR EXPERTISE

Transforming spaces with precision, quality, and craftsmanship. From installation to restoration, we bring your flooring dreams to life with unparalleled attention to detail.

WHO WE ARE

We Are Right Hardwood Flooring

Carrion Services was born from the vision and determination of Carlos Carrion, a Brazilian professional with over 6 years of experience in the renovation and finishing industry. Since arriving in the United States, Carlos has dedicated himself intensely to his profession, building a solid reputation based on hard work, technical excellence, and an unwavering commitment to quality.

OUR WORK

We are proud to provide top services

Hardwood Flooring

Hardwood flooring is a timeless, durable, and high-end choice for homeowners and businesses looking to elevate their interior spaces. In addition to its aesthetic appeal and long-lasting performance, hardwood also adds significant financial value to your property.

Luxury Vinyl Plank

Luxury Vinyl Plank (LVP) flooring is a top choice for homeowners and businesses seeking a balance of elegance, durability, and affordability

Luxury Vinyl Tile

Luxury Vinyl Tile (LVT) is an innovative flooring solution that offers the perfect blend of beauty, resilience, and ease of maintenance

Projects
0
People
0
Years
0
Offices
0

QUALITY & EXPERTISE

Entrust your floors to professionals. We’ll do the rest!

At Carrion Services LLC, we bring precision, craftsmanship, and dedication to every flooring project. Whether you’re looking to install, repair, or restore your floors, our team of experts ensures a flawless finish that enhances the beauty and durability of your space.

We understand that your floors are a vital part of your home or business, which is why we use high-quality materials, advanced techniques, and meticulous attention to detail to deliver results that exceed expectations. From hardwood to luxury vinyl and laminate, we tailor our services to your needs, ensuring a seamless and hassle-free experience from start to finish.

With Carrion Services LLC, you don’t have to worry about the details—we handle everything with expertise and professionalism, so you can enjoy stunning, long-lasting floors without the stress.

OUR WORK

Project Gallery

Testimonials

What Our Client’s Say

// ========================================= // FASE 1: SISTEMA DE AGENDAMENTO - JAVASCRIPT // ========================================= // Configuration const CONFIG = { // Business hours (24-hour format) - Eastern Time (America/New_York) businessHours: { monday: { start: 6, end: 19 }, tuesday: { start: 6, end: 19 }, wednesday: { start: 6, end: 19 }, thursday: { start: 6, end: 19 }, friday: { start: 6, end: 19 }, saturday: { start: 6, end: 16 }, sunday: null // Closed }, appointmentDuration: 90, // minutes timeSlotInterval: 90, // minutes between appointments maxAdvanceBooking: 60, // days minAdvanceBooking: 1, // days timezone: 'America/New_York', // Eastern Time Zone googleMapsApiKey: 'AIzaSyC-NtscSlI9UrE000XSOkVUKn3aKCf2css' }; // Global variables let googleMapsLoaded = false; let autocompleteService = null; let placesService = null; // DOM Elements const form = document.getElementById('schedulingForm'); const submitBtn = document.getElementById('submitBtn'); const loadingSpinner = document.getElementById('loadingSpinner'); const successMessage = document.getElementById('successMessage'); const formContainer = document.querySelector('.form-container'); const dateInput = document.getElementById('preferredDate'); const timeSelect = document.getElementById('preferredTime'); // Initialize the application document.addEventListener('DOMContentLoaded', function() { // Only initialize scheduling form if it exists on the page if (form) { initializeDatePicker(); initializeTimeSlots(); initializeFormValidation(); initializePhoneFormatting(); initializeAddressAutocomplete(); // Add event listeners form.addEventListener('submit', handleFormSubmit); dateInput.addEventListener('change', handleDateChange); // Add smooth scrolling for form sections addSmoothScrolling(); } }); // Initialize Google Maps callback function initGoogleMaps() { googleMapsLoaded = true; if (typeof google !== 'undefined' && google.maps && google.maps.places) { autocompleteService = new google.maps.places.AutocompleteService(); placesService = new google.maps.places.PlacesService(document.createElement('div')); console.log('Google Maps API loaded successfully'); } } // Initialize date picker with business rules function initializeDatePicker() { const today = new Date(); // Get dates in Eastern Time const easternToday = new Date(today.toLocaleString("en-US", {timeZone: CONFIG.timezone})); const minDate = new Date(easternToday); minDate.setDate(easternToday.getDate() + CONFIG.minAdvanceBooking); const maxDate = new Date(easternToday); maxDate.setDate(easternToday.getDate() + CONFIG.maxAdvanceBooking); dateInput.min = formatDateForInput(minDate); dateInput.max = formatDateForInput(maxDate); // Set default to tomorrow in Eastern Time const tomorrow = new Date(easternToday); tomorrow.setDate(easternToday.getDate() + 1); dateInput.value = formatDateForInput(tomorrow); // Trigger time slot generation for default date handleDateChange(); } // Generate available time slots based on selected date function handleDateChange() { const selectedDate = new Date(dateInput.value + 'T00:00:00'); // Convert to Eastern Time for day calculation const easternDate = new Date(selectedDate.toLocaleString("en-US", {timeZone: CONFIG.timezone})); const dayName = easternDate.toLocaleDateString('en-US', { weekday: 'long', timeZone: CONFIG.timezone }).toLowerCase(); // Clear existing options timeSelect.innerHTML = ''; // Check if business is open on selected day const businessHour = CONFIG.businessHours[dayName]; if (!businessHour) { const option = document.createElement('option'); option.value = ''; option.textContent = 'Closed on Sundays'; option.disabled = true; timeSelect.appendChild(option); return; } // Generate time slots const timeSlots = generateTimeSlots(businessHour.start, businessHour.end); timeSlots.forEach(slot => { const option = document.createElement('option'); option.value = slot.value; option.textContent = slot.display; timeSelect.appendChild(option); }); } // Generate time slots for a given range function generateTimeSlots(startHour, endHour) { const slots = []; let currentTime = startHour * 60; // Convert to minutes const endTime = endHour * 60; while (currentTime < endTime) { const hours = Math.floor(currentTime / 60); const minutes = currentTime % 60; // Format time for display (12-hour format) const displayTime = formatTime12Hour(hours, minutes); // Format time for value (24-hour format) const valueTime = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`; slots.push({ value: valueTime, display: displayTime }); currentTime += CONFIG.timeSlotInterval; } return slots; } // Format time to 12-hour format function formatTime12Hour(hours, minutes) { const period = hours >= 12 ? 'PM' : 'AM'; const displayHours = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; const displayMinutes = minutes.toString().padStart(2, '0'); return `${displayHours}:${displayMinutes} ${period}`; } // Format date for input field function formatDateForInput(date) { return date.toISOString().split('T')[0]; } // Initialize form validation function initializeFormValidation() { const inputs = form.querySelectorAll('input[required], select[required]'); inputs.forEach(input => { input.addEventListener('blur', validateField); input.addEventListener('input', clearFieldError); }); } // Validate individual field function validateField(event) { const field = event.target; const value = field.value.trim(); const fieldName = field.name; clearFieldError(event); // Required field validation if (field.hasAttribute('required') && !value) { showFieldError(field, 'This field is required'); return false; } // Specific field validations switch (fieldName) { case 'email': if (value && !isValidEmail(value)) { showFieldError(field, 'Please enter a valid email address'); return false; } break; case 'phone': if (value && !isValidPhone(value)) { showFieldError(field, 'Please enter a valid phone number'); return false; } break; case 'firstName': case 'lastName': if (value && value.length < 2) { showFieldError(field, 'Name must be at least 2 characters'); return false; } break; } return true; } // Show field error function showFieldError(field, message) { const errorElement = field.parentNode.querySelector('.error-message'); if (errorElement) { errorElement.textContent = message; errorElement.style.display = 'block'; field.classList.add('error'); } } // Clear field error function clearFieldError(event) { const field = event.target; const errorElement = field.parentNode.querySelector('.error-message'); if (errorElement) { errorElement.style.display = 'none'; field.classList.remove('error'); } } // Email validation function isValidEmail(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } // Phone validation function isValidPhone(phone) { const phoneRegex = /^[\+]?[1-9][\d]{0,15}$/; const cleanPhone = phone.replace(/[\s\-\(\)\.]/g, ''); return phoneRegex.test(cleanPhone) && cleanPhone.length >= 10; } // Initialize address autocomplete function initializeAddressAutocomplete() { const addressInput = document.getElementById('address'); const suggestionsContainer = document.getElementById('addressSuggestions'); if (!addressInput || !suggestionsContainer) return; let selectedIndex = -1; let suggestions = []; // Add input event listener addressInput.addEventListener('input', function(e) { const query = e.target.value.trim(); if (query.length < 3) { hideSuggestions(); return; } // Debounce the API calls clearTimeout(addressInput.searchTimeout); addressInput.searchTimeout = setTimeout(() => { searchAddresses(query); }, 300); }); // Handle keyboard navigation addressInput.addEventListener('keydown', function(e) { const suggestionElements = suggestionsContainer.querySelectorAll('.address-suggestion'); switch(e.key) { case 'ArrowDown': e.preventDefault(); selectedIndex = Math.min(selectedIndex + 1, suggestionElements.length - 1); updateSelection(suggestionElements); break; case 'ArrowUp': e.preventDefault(); selectedIndex = Math.max(selectedIndex - 1, -1); updateSelection(suggestionElements); break; case 'Enter': e.preventDefault(); if (selectedIndex >= 0 && suggestionElements[selectedIndex]) { selectSuggestion(suggestions[selectedIndex]); } break; case 'Escape': hideSuggestions(); break; } }); // Hide suggestions when clicking outside document.addEventListener('click', function(e) { if (!addressInput.contains(e.target) && !suggestionsContainer.contains(e.target)) { hideSuggestions(); } }); function searchAddresses(query) { if (!googleMapsLoaded || !autocompleteService) { console.log('Google Maps not loaded yet'); return; } const request = { input: query, componentRestrictions: { country: 'us' }, types: ['address'], bounds: new google.maps.LatLngBounds( new google.maps.LatLng(35.0, -81.0), // Southwest Charlotte area new google.maps.LatLng(35.5, -80.5) // Northeast Charlotte area ) }; autocompleteService.getPlacePredictions(request, function(predictions, status) { if (status === google.maps.places.PlacesServiceStatus.OK && predictions) { suggestions = predictions; displaySuggestions(predictions); } else { hideSuggestions(); } }); } function displaySuggestions(predictions) { suggestionsContainer.innerHTML = ''; selectedIndex = -1; predictions.forEach((prediction, index) => { const suggestionElement = document.createElement('div'); suggestionElement.className = 'address-suggestion'; suggestionElement.textContent = prediction.description; suggestionElement.addEventListener('click', function() { selectSuggestion(prediction); }); suggestionsContainer.appendChild(suggestionElement); }); suggestionsContainer.style.display = 'block'; } function updateSelection(suggestionElements) { suggestionElements.forEach((element, index) => { element.classList.toggle('selected', index === selectedIndex); }); } function selectSuggestion(prediction) { addressInput.value = prediction.description; hideSuggestions(); // Validate the selected address validateAddress(prediction.place_id); } function hideSuggestions() { suggestionsContainer.style.display = 'none'; selectedIndex = -1; suggestions = []; } function validateAddress(placeId) { if (!placesService) return; const request = { placeId: placeId, fields: ['geometry', 'formatted_address', 'address_components'] }; placesService.getDetails(request, function(place, status) { if (status === google.maps.places.PlacesServiceStatus.OK) { // Check if address is in service area (Charlotte, NC area) const location = place.geometry.location; const lat = location.lat(); const lng = location.lng(); // Charlotte area bounds (approximate) const charlotteBounds = { north: 35.5, south: 35.0, east: -80.5, west: -81.0 }; if (lat >= charlotteBounds.south && lat <= charlotteBounds.north && lng >= charlotteBounds.west && lng <= charlotteBounds.east) { // Address is in service area addressInput.classList.remove('error'); clearFieldError({ target: addressInput }); // Add a subtle success indicator addressInput.style.borderColor = '#28a745'; setTimeout(() => { addressInput.style.borderColor = ''; }, 2000); } else { // Address is outside service area showFieldError(addressInput, 'Sorry, we currently only serve the Charlotte, NC area'); } } }); } } // Initialize phone number formatting function initializePhoneFormatting() { const phoneInput = document.getElementById('phone'); if (!phoneInput) return; phoneInput.addEventListener('input', function(e) { let value = e.target.value.replace(/\D/g, ''); if (value.length >= 6) { value = `(${value.slice(0, 3)}) ${value.slice(3, 6)}-${value.slice(6, 10)}`; } else if (value.length >= 3) { value = `(${value.slice(0, 3)}) ${value.slice(3)}`; } e.target.value = value; }); } // Handle form submission async function handleFormSubmit(event) { event.preventDefault(); // Validate all fields if (!validateForm()) { showFormError('Please correct the errors above and try again.'); return; } // Check if at least one service is selected const selectedServices = form.querySelectorAll('input[name="services"]:checked'); if (selectedServices.length === 0) { showFormError('Please select at least one service.'); return; } // Show loading state setLoadingState(true); try { // Collect form data const formData = collectFormData(); // For demo purposes, simulate a successful submission setTimeout(() => { showSuccessMessage(); setLoadingState(false); }, 1500); // In production, uncomment this to submit to backend /* const response = await submitAppointment(formData); if (response.success) { showSuccessMessage(response.data); } else { throw new Error(response.message || 'Failed to schedule appointment'); } */ } catch (error) { console.error('Submission error:', error); showFormError('Sorry, there was an error scheduling your appointment. Please try again or call us directly at (980) 890-5210.'); setLoadingState(false); } } // Validate entire form function validateForm() { const requiredFields = form.querySelectorAll('input[required], select[required]'); let isValid = true; requiredFields.forEach(field => { const event = { target: field }; if (!validateField(event)) { isValid = false; } }); return isValid; } // Show form error function showFormError(message) { // Create error message if it doesn't exist let errorContainer = form.querySelector('.form-error-message'); if (!errorContainer) { errorContainer = document.createElement('div'); errorContainer.className = 'form-error-message'; form.querySelector('.form-section:first-child').prepend(errorContainer); } errorContainer.textContent = message; errorContainer.style.display = 'block'; // Scroll to error errorContainer.scrollIntoView({ behavior: 'smooth', block: 'center' }); } // Set loading state function setLoadingState(isLoading) { submitBtn.disabled = isLoading; loadingSpinner.style.display = isLoading ? 'flex' : 'none'; submitBtn.style.display = isLoading ? 'none' : 'flex'; } // Collect form data function collectFormData() { const formData = new FormData(form); const data = {}; for (const [key, value] of formData.entries()) { if (data[key]) { if (!Array.isArray(data[key])) { data[key] = [data[key]]; } data[key].push(value); } else { data[key] = value; } } return data; } // Show success message function showSuccessMessage() { formContainer.style.display = 'none'; successMessage.style.display = 'block'; // Scroll to success message successMessage.scrollIntoView({ behavior: 'smooth', block: 'start' }); } // Reset form function resetForm() { form.reset(); formContainer.style.display = 'block'; successMessage.style.display = 'none'; // Reset date picker initializeDatePicker(); // Scroll to top form.scrollIntoView({ behavior: 'smooth', block: 'start' }); } // Add smooth scrolling function addSmoothScrolling() { const formSections = document.querySelectorAll('.form-section'); formSections.forEach(section => { const heading = section.querySelector('h3'); if (heading) { heading.style.cursor = 'pointer'; heading.addEventListener('click', () => { const content = Array.from(section.children).filter(el => el !== heading); content.forEach(el => { el.style.display = el.style.display === 'none' ? 'block' : 'none'; }); }); } }); } // ========================================= // FASE 2: GALERIA PREMIUM - JAVASCRIPT // ========================================= // Global variables for gallery let currentImageIndex = 0; let filteredImages = []; let allImages = []; // Initialize gallery when DOM is loaded document.addEventListener('DOMContentLoaded', function() { // Only initialize gallery if gallery elements exist on the page if (document.querySelector('.gallery-grid')) { initializeGallery(); initializeFilters(); initializeLightbox(); initializeLazyLoading(); } }); // Initialize gallery functionality function initializeGallery() { const galleryItems = document.querySelectorAll('.gallery-item'); if (!galleryItems.length) return; allImages = Array.from(galleryItems); filteredImages = [...allImages]; // Add click event to gallery items galleryItems.forEach((item, index) => { item.addEventListener('click', () => openLightbox(index)); item.classList.add('fade-in'); }); // Add loading animation setTimeout(() => { galleryItems.forEach(item => { item.style.opacity = '1'; }); }, 100); } // Initialize filter functionality function initializeFilters() { const filterButtons = document.querySelectorAll('.filter-btn'); if (!filterButtons.length) return; filterButtons.forEach(button => { button.addEventListener('click', () => { // Remove active class from all buttons filterButtons.forEach(btn => btn.classList.remove('active')); // Add active class to clicked button button.classList.add('active'); // Get filter value const filterValue = button.getAttribute('data-filter'); // Filter gallery items filterGallery(filterValue); }); }); } // Filter gallery items function filterGallery(filter) { const galleryGrid = document.getElementById('galleryGrid'); if (!galleryGrid) return; const galleryItems = document.querySelectorAll('.gallery-item'); // Add loading animation galleryGrid.classList.add('loading'); setTimeout(() => { galleryItems.forEach((item, index) => { const category = item.getAttribute('data-category'); if (filter === 'all' || category === filter) { item.style.display = 'block'; item.classList.add('filter-animation'); // Update filtered images array if (!filteredImages.includes(item)) { filteredImages.push(item); } } else { item.style.display = 'none'; // Remove from filtered images array const itemIndex = filteredImages.indexOf(item); if (itemIndex > -1) { filteredImages.splice(itemIndex, 1); } } }); // Update filtered images array filteredImages = Array.from(galleryItems).filter(item => item.style.display !== 'none' ); // Remove loading animation galleryGrid.classList.remove('loading'); // Remove animation class after animation completes setTimeout(() => { galleryItems.forEach(item => { item.classList.remove('filter-animation'); }); }, 400); }, 200); } // Initialize lightbox functionality function initializeLightbox() { const lightbox = document.getElementById('lightbox'); if (!lightbox) return; const lightboxClose = document.getElementById('lightboxClose'); const lightboxPrev = document.getElementById('lightboxPrev'); const lightboxNext = document.getElementById('lightboxNext'); // Close lightbox events lightboxClose.addEventListener('click', closeLightbox); lightbox.addEventListener('click', (e) => { if (e.target === lightbox) { closeLightbox(); } }); // Navigation events lightboxPrev.addEventListener('click', () => navigateLightbox(-1)); lightboxNext.addEventListener('click', () => navigateLightbox(1)); // Keyboard navigation document.addEventListener('keydown', (e) => { if (lightbox.style.display === 'block') { switch(e.key) { case 'Escape': closeLightbox(); break; case 'ArrowLeft': navigateLightbox(-1); break; case 'ArrowRight': navigateLightbox(1); break; } } }); } // Open lightbox with specific image function openLightbox(index) { const lightbox = document.getElementById('lightbox'); if (!lightbox) return; const lightboxImage = document.getElementById('lightboxImage'); const lightboxTitle = document.getElementById('lightboxTitle'); const lightboxDescription = document.getElementById('lightboxDescription'); const lightboxCategory = document.getElementById('lightboxCategory'); // Find the index in filtered images const galleryItems = document.querySelectorAll('.gallery-item[style*="block"], .gallery-item:not([style*="none"])'); currentImageIndex = index; if (galleryItems[index]) { const item = galleryItems[index]; const img = item.querySelector('img'); const title = item.getAttribute('data-title'); const description = item.getAttribute('data-description'); const category = item.getAttribute('data-category'); // Update lightbox content lightboxImage.src = img.src; lightboxImage.alt = img.alt; lightboxTitle.textContent = title; lightboxDescription.textContent = description; lightboxCategory.textContent = category.charAt(0).toUpperCase() + category.slice(1); // Show lightbox lightbox.style.display = 'block'; document.body.style.overflow = 'hidden'; // Add fade in animation setTimeout(() => { lightbox.style.opacity = '1'; }, 10); } } // Close lightbox function closeLightbox() { const lightbox = document.getElementById('lightbox'); if (!lightbox) return; lightbox.style.opacity = '0'; setTimeout(() => { lightbox.style.display = 'none'; document.body.style.overflow = 'auto'; }, 300); } // Navigate lightbox (previous/next) function navigateLightbox(direction) { const visibleItems = document.querySelectorAll('.gallery-item[style*="block"], .gallery-item:not([style*="none"])'); if (!visibleItems.length) return; currentImageIndex += direction; // Loop around if at beginning or end if (currentImageIndex < 0) { currentImageIndex = visibleItems.length - 1; } else if (currentImageIndex >= visibleItems.length) { currentImageIndex = 0; } // Update lightbox content const item = visibleItems[currentImageIndex]; if (item) { const img = item.querySelector('img'); const title = item.getAttribute('data-title'); const description = item.getAttribute('data-description'); const category = item.getAttribute('data-category'); const lightboxImage = document.getElementById('lightboxImage'); const lightboxTitle = document.getElementById('lightboxTitle'); const lightboxDescription = document.getElementById('lightboxDescription'); const lightboxCategory = document.getElementById('lightboxCategory'); // Add transition effect lightboxImage.style.opacity = '0'; setTimeout(() => { lightboxImage.src = img.src; lightboxImage.alt = img.alt; lightboxTitle.textContent = title; lightboxDescription.textContent = description; lightboxCategory.textContent = category.charAt(0).toUpperCase() + category.slice(1); lightboxImage.style.opacity = '1'; }, 150); } } // Initialize lazy loading for images function initializeLazyLoading() { const images = document.querySelectorAll('img[loading="lazy"]'); if (!images.length) return; if ('IntersectionObserver' in window) { const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.src; img.classList.remove('lazy'); imageObserver.unobserve(img); } }); }); images.forEach(img => { imageObserver.observe(img); }); } else { // Fallback for browsers without IntersectionObserver images.forEach(img => { img.src = img.src; }); } } // Touch/swipe support for mobile lightbox navigation let touchStartX = 0; let touchEndX = 0; function handleTouchStart(e) { touchStartX = e.changedTouches[0].screenX; } function handleTouchEnd(e) { touchEndX = e.changedTouches[0].screenX; handleSwipe(); } function handleSwipe() { const swipeThreshold = 50; const swipeDistance = touchEndX - touchStartX; if (Math.abs(swipeDistance) > swipeThreshold) { if (swipeDistance > 0) { // Swipe right - previous image navigateLightbox(-1); } else { // Swipe left - next image navigateLightbox(1); } } } // Add touch event listeners to lightbox document.addEventListener('DOMContentLoaded', function() { const lightboxContent = document.querySelector('.lightbox-content'); if (lightboxContent) { lightboxContent.addEventListener('touchstart', handleTouchStart, false); lightboxContent.addEventListener('touchend', handleTouchEnd, false); } });