+
+
+
+
+ About Us - Bloom Valley Nursery
+
+
+
+
+
+
+
+
+
Bloom Valley Nursery
+
+
+
+
+
+
+
+
+
+
The Story of Bloom Valley
+
+ Legend has it that in 1822, Benjamin Bloom, his wife Violet, and
+ their young daughter Nora stumbled upon a breathtaking valley
+ brimming with vibrant, rare flowers during their journey westward.
+ Enchanted by its beauty, they decided to settle there, abandoning
+ their plans to reach California. This picturesque haven became known
+ as Bloom Valley.
+
+
+ Today, on the very land where the Bloom family found their paradise,
+ stands Bloom Valley Nursery. Still family-owned and operated,
+ siblings Bethany, Vincent, and Nathaniel Bloom carry forward a
+ legacy of preserving and sharing the natural beauty that captivated
+ the hearts of their ancestors over two centuries ago.
+
+
Though many things have changed through the years, our commitment to serving our community has remained the same. Let us help you cultivate joy, one bloom at a time!
+
+
+
+
+
+
We Want to Hear From You!
+
Your feedback provides us with valuable insight into where we stand in our commitment to our neighbors, friends, and the entire Bloom Valley community.
+
Feel free to contact us by filling out the form below if you have any questions, concerns, or simply want to tell us how we can better serve you in the future. You are also welcome to give us a call at the number above if you need to speak with someone directly. Our friendly staff can help answer your questions or guide you in placing custom orders as well!
';
+ cartTotalContainer.textContent = '';
+ return;
+ }
+
+ cart.forEach(item => {
+ const itemTotal = item.price * item.quantity;
+ total += itemTotal;
+
+ const listItem = document.createElement('li');
+ listItem.textContent = `${item.name} x ${item.quantity} - $${itemTotal.toFixed(2)}`;
+ cartItemsContainer.appendChild(listItem);
+ });
+
+ cartTotalContainer.textContent = `Subtotal: $${total.toFixed(2)}`;
+ }
+
+ // Show cart modal with current cart content
+ function showModal() {
+ renderCart(); // Always render the latest cart
+ modal.style.display = 'flex'; // Show the cart modal
+ }
+
+ // Show confirmation modal for actions (clear or process order)
+ function showConfirmationModal(message, action) {
+ confirmationMessage.textContent = message;
+ confirmationModal.style.display = 'flex'; // Show the confirmation modal
+
+ // Confirm action on the "Confirm" button
+ confirmationConfirmButton.onclick = () => {
+ action(); // Execute the passed action (clear cart, process order)
+ confirmationModal.style.display = 'none'; // Close the confirmation modal after confirming
+ };
+
+ // Close confirmation modal without performing any action
+ confirmationCloseButton.onclick = () => {
+ confirmationModal.style.display = 'none';
+ };
+ }
+
+ // Show final confirmation modal with success message
+ function showFinalConfirmationModal(message) {
+ finalConfirmationMessage.textContent = message;
+ finalConfirmationModal.style.display = 'flex'; // Show the final confirmation modal
+ finalConfirmationCloseButton.onclick = () => {
+ finalConfirmationModal.style.display = 'none'; // Close final confirmation modal
+ };
+ }
+
+ // Show custom modal when item is added to cart
+ function showItemAddedModal(message) {
+ itemAddedMessage.textContent = message; // Set message dynamically
+ itemAddedModal.style.display = 'flex'; // Show the modal
+ itemAddedClose.addEventListener('click', () => {
+ itemAddedModal.style.display = 'none'; // Close the modal
+ });
+ }
+
+ // Attach event listeners to both cart buttons
+ [shoppingCartButton, cartDetailsButton].forEach(button => {
+ if (button) {
+ button.addEventListener('click', showModal); // Open modal when clicked
+ }
+ });
+
+ // Close modal when clicking outside of it
+ window.addEventListener('click', event => {
+ if (event.target === modal) {
+ modal.style.display = 'none';
+ }
+ });
+
+ // Close the modal by clicking the close button (for cart modal)
+ if (closeModal) {
+ closeModal.addEventListener('click', () => {
+ modal.style.display = 'none';
+ });
+ }
+
+ // Add to cart functionality
+ const addToCartButtons = document.querySelectorAll('.add-to-cart-btn');
+ addToCartButtons.forEach(button => {
+ button.addEventListener('click', () => {
+ const productId = parseInt(button.dataset.productId, 10);
+ const product = products.find(item => item.id === productId);
+
+ if (product) {
+ const existingProduct = cart.find(item => item.id === productId);
+
+ if (existingProduct) {
+ existingProduct.quantity++;
+ } else {
+ cart.push({ ...product, quantity: 1 });
+ }
+
+ sessionStorage.setItem('cart', JSON.stringify(cart)); // Save cart to session storage
+ showItemAddedModal(`${product.name} has been added to the cart!`); // Show custom modal
+ }
+ });
+ });
+
+ // Event listener for Clear Cart button in the modal
+ if (clearCartModalButton) {
+ clearCartModalButton.addEventListener('click', () => {
+ showConfirmationModal('Are you sure you want to clear the cart?', () => {
+ sessionStorage.removeItem('cart');
+ cart = [];
+ renderCart(); // Re-render cart after clearing it
+ showFinalConfirmationModal('Cart has been cleared!'); // Show final confirmation for cart clearing
+ });
+ });
+ }
+
+ // Event listener for Process Order button in the modal
+ if (processOrderModalButton) {
+ processOrderModalButton.addEventListener('click', () => {
+ if (cart.length === 0) {
+ showItemAddedModal('Your cart is empty. Please add items to the cart before processing the order.');
+ return;
+ }
+
+ showConfirmationModal('Are you sure you want to process your order?', () => {
+ const receiptNumber = Math.floor(Math.random() * 1000000); // Generate receipt number
+ showFinalConfirmationModal(`Thank you for your order!\nYour receipt number is ${receiptNumber}.`);
+ sessionStorage.removeItem('cart');
+ cart = [];
+ renderCart(); // Re-render cart after processing the order
+ });
+ });
+ }
+});
+
+const allCloseButtons = document.querySelectorAll('.close-modal');
+allCloseButtons.forEach(button => {
+ button.addEventListener('click', () => {
+ // Close the parent modal of the button clicked
+ const modal = button.closest('.modal');
+ modal.style.display = 'none';
+ });
+});
diff --git a/BloomValleyNursery_FullProjectFiles/community.html b/BloomValleyNursery_FullProjectFiles/community.html
new file mode 100644
index 0000000..98e1d96
--- /dev/null
+++ b/BloomValleyNursery_FullProjectFiles/community.html
@@ -0,0 +1,256 @@
+
+
+
+
+
+
+
+ Community Events - Bloom Valley Nursery
+
+
+
+
+
+
+
+
+
Bloom Valley Nursery
+
+
+
+
+
+
+
Mark Your Calendars!
+
+
+
+
+
+
Upcoming Events
+
+
+
Events at Bloom Valley Nursery
+
+ All workshops at Bloom Valley Nursery are provided free of charge to
+ anyone interested in learning techniques and ideas for creating a
+ visually appealing living space that can be personalized to suite
+ individual needs. Registration links are provided in each Google
+ Calendar Event by clicking on the date of the event within the
+ Google Calendar on this page.
+
+
+
+ Gardening and Landscaping 101: When: 2nd Tuesday of
+ Every Month @ 6:30 pm. Join Bethany Bloom as she shares her tips for
+ creating a themed decor through-out the home that you will be
+ delighted to share with your holiday guests.
+
+
+ Deck the Halls When: Saturday @ 10:00 am. Join
+ Nathaniel and Vincent as they guide us through picking and tending
+ the perfect live Christmas tree for your Christmas decoration
+ focal-point.
+
+
+ Christmas Eve and Christmas Day Bloom Valley
+ Nursery will close on Christmas Eve at 8:00 pm for any last-minute
+ shopping. The nursery will remain closed until January 2nd. During
+ this time, we will be making improvements to the nursery grounds and
+ store with the aim of better serving our Bloom Valley neighbors,
+ friends and family. We are excited to share the new features and changes with
+ you in the New Year! Happy Holidays!!!
+
+
+
+
+
Community-Wide Events
+
+ This section includes local community events for which Bloom Valley
+ Nursery is in partner with or a sponsor of. These events are
+ typically free of charge, but can include sub-events by other local
+ organizations and businesses that may not be free of charge. Check
+ with specific organizations, businesses, and the Bloom Valley
+ Chamber of Commerce for specific details that may not be provided by
+ Bloom Valley Nursery.
+
+
+
+ Tree Lighting Ceremony When:Thursday @ 6:00 pm.
+ Help us kick off the Holiday festivities by joining the Bloom
+ family, along with the Bloom Valley Chamber of Commerce, the Bloom
+ Valley Garden Club, and many other local businesses and
+ organizations, as we gather in front of City Hall for the annual Tree
+ Lighting Ceremony! This event will include performances by the Bloom
+ Valley Junior and Senior High Marching Bands, a workshop for making
+ tree ornaments, the annual Chili Cook-off, and much more!
+
+
+
+
+
+
+
+
+ For more details, to add events to this page, or to leave feedback,
+ click here to send us a message.
+
+
+
+
+
+
+
+
+ ×
+
Newsletter Subscription
+
+
+
+
+
+
+
+ ×
+
+
+
+
+
+
+
+
+ ×
+
Your Shopping Cart
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
+
+
+
+
+ ×
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
+
+
+
+
+
+
+
diff --git a/BloomValleyNursery_FullProjectFiles/feedback.js b/BloomValleyNursery_FullProjectFiles/feedback.js
new file mode 100644
index 0000000..1ecc2bc
--- /dev/null
+++ b/BloomValleyNursery_FullProjectFiles/feedback.js
@@ -0,0 +1,93 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const feedbackForm = document.querySelector('#feedback-form form');
+ const nameInput = document.getElementById('name');
+ const emailInput = document.getElementById('email');
+ const phoneInput = document.getElementById('tel');
+ const messageInput = document.getElementById('message');
+
+ const alertBox = document.getElementById('custom-alert');
+ const alertMessage = document.getElementById('alert-message');
+ const alertOkButton = document.getElementById('alert-ok-button');
+ const alertCloseButton = document.getElementById('alert-close-btn');
+
+ const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; // Email validation regex
+ const phoneRegex = /^[0-9]{10,15}$/; // Phone validation regex (10-15 digits)
+ const nameRegex = /^[a-zA-Z\s]{2,}$/; // Name validation regex (at least 2 letters)
+ const sqlInjectionRegex = /[;'"\\]/; // Prevent SQL injection-like characters
+
+ // Form submission handler
+ feedbackForm.addEventListener('submit', (event) => {
+ event.preventDefault(); // Prevent form submission and page refresh
+
+ const name = nameInput.value.trim();
+ const email = emailInput.value.trim();
+ const phone = phoneInput.value.trim();
+ const message = messageInput.value.trim();
+
+ // Validate each field
+ if (!nameRegex.test(name)) {
+ showCustomAlert('Please enter a valid name (letters and spaces only).');
+ return;
+ }
+
+ if (!emailRegex.test(email)) {
+ showCustomAlert('Please enter a valid email address.');
+ return;
+ }
+
+ if (!phoneRegex.test(phone)) {
+ showCustomAlert('Please enter a valid phone number (10-15 digits).');
+ return;
+ }
+
+ if (sqlInjectionRegex.test(message)) {
+ showCustomAlert('Your message contains invalid characters.');
+ return;
+ }
+
+ // Save feedback to localStorage
+ const feedbackData = {
+ name,
+ email,
+ phone,
+ message,
+ timestamp: new Date().toISOString(),
+ };
+
+ // Retrieve existing feedback data or initialize an empty array
+ const feedbackList = JSON.parse(localStorage.getItem('feedbackList')) || [];
+ feedbackList.push(feedbackData); // Add new feedback to the list
+ localStorage.setItem('feedbackList', JSON.stringify(feedbackList)); // Save updated list to localStorage
+ console.log('Feedback saved to localStorage:', feedbackList);
+
+ // Show success message
+ showCustomAlert('Thank you for your feedback! We appreciate hearing from you.');
+ feedbackForm.reset(); // Clear the input fields after submission
+ });
+
+ // Function to show the custom alert modal
+ function showCustomAlert(message) {
+ alertMessage.textContent = message; // Set modal message
+ alertBox.classList.remove('hidden'); // Display the modal
+ alertBox.style.display = 'flex'; // Ensure the modal is visible
+ }
+
+ // Function to close the custom alert modal
+ function closeCustomAlert() {
+ alertBox.classList.add('hidden'); // Hide the modal
+ alertBox.style.display = 'none'; // Ensure it's hidden
+ }
+
+ // Close modal on "OK" button click
+ alertOkButton.addEventListener('click', closeCustomAlert);
+
+ // Close modal on "X" button click
+ alertCloseButton.addEventListener('click', closeCustomAlert);
+
+ // Close modal when clicking outside the modal content
+ window.addEventListener('click', (event) => {
+ if (event.target === alertBox) {
+ closeCustomAlert();
+ }
+ });
+});
diff --git a/BloomValleyNursery_FullProjectFiles/gallery-carousel.js b/BloomValleyNursery_FullProjectFiles/gallery-carousel.js
new file mode 100644
index 0000000..5dcc4a0
--- /dev/null
+++ b/BloomValleyNursery_FullProjectFiles/gallery-carousel.js
@@ -0,0 +1,127 @@
+// Gallery Carousel .js
+const products = {
+ trees: [
+ { id: 1, name: "Maple Tree", description: "Beautiful maple tree.", price: 55.00, image: "images/trees/MapleTree.png" },
+ { id: 2, name: "Birch Tree", description: "Sturdy birch tree.", price: 45.00, image: "images/trees/BirchTree.png" },
+ { id: 3, name: "Apple Tree", description: "Fruitful apple tree.", price: 35.00, image: "images/trees/AppleTree.png" }
+ ],
+ indoor: [
+ { id: 4, name: "Aloe Plant", description: "Thrives with 6-8 hours of direct sunlight a day.", price: 15.00, image: "images/indoor/AloePlant.png" },
+ { id: 5, name: "Spider Plant", description: "Low-maintenance and perfect for spaces with lots of natural light.", price: 12.50, image: "images/indoor/SpiderPlant.png" },
+ { id: 6, name: "String-of-Pearls Plant", description: "Best placed in east-facing windows or on shaded patios and balconies.", price: 20.00, image: "images/indoor/StringofPearls.png" }
+ ],
+ tools: [
+ { id: 7, name: "Watering Can", description: "Galvanized aluminum watering can.", price: 15.00, image: "images/accessories/WateringCan.png" },
+ { id: 8, name: "Potting Soil", description: "Premium-blend of nutrient-rich potting soil - 10 lb bag.", price: 8.00, image: "images/accessories/PottingSoil.png" },
+ { id: 9, name: "Bird House", description: "Handmade wooden bird house for hanging or mounting.", price: 11.00, image: "images/accessories/BirdHouse.png" }
+ ]
+};
+
+document.addEventListener('DOMContentLoaded', () => {
+ console.log("DOM fully loaded and parsed"); // Check if the DOM is ready
+
+ const productCarousel = document.getElementById('product-carousel');
+ const scrollLeftButton = document.getElementById('scroll-left');
+ const scrollRightButton = document.getElementById('scroll-right');
+ const categoryButtons = document.querySelectorAll('.cat-btn');
+
+ // Scroll button functionality
+ scrollLeftButton.addEventListener('click', () => {
+ productCarousel.scrollBy({ left: -300, behavior: 'smooth' });
+ });
+
+ scrollRightButton.addEventListener('click', () => {
+ productCarousel.scrollBy({ left: 300, behavior: 'smooth' });
+ });
+
+ // Map buttons to categories
+ categoryButtons.forEach(button => {
+ button.addEventListener('click', (event) => {
+ event.preventDefault(); // Prevent default navigation
+ const url = new URL(button.href); // Parse the URL
+ const category = url.searchParams.get('category'); // Get category from the query parameter
+ updateProductList(category); // Update the product list
+ });
+ });
+
+ // Load default category or the one from the current URL
+ const currentUrl = new URL(window.location.href);
+ const defaultCategory = currentUrl.searchParams.get('category') || 'trees';
+ updateProductList(defaultCategory);
+});
+
+function updateScrollButtons() {
+ const scrollLeftButton = document.getElementById('scroll-left');
+ const scrollRightButton = document.getElementById('scroll-right');
+ const productCarousel = document.getElementById('product-carousel');
+
+ scrollLeftButton.style.display = productCarousel.scrollLeft === 0 ? 'none' : 'block';
+ scrollRightButton.style.display =
+ productCarousel.scrollWidth - productCarousel.clientWidth === productCarousel.scrollLeft
+ ? 'none'
+ : 'block';
+}
+
+function updateProductList(category) {
+ const productList = document.getElementById("product-list");
+ if (!productList) {
+ console.error("Element with ID 'product-list' not found in the DOM.");
+ return;
+ }
+
+ productList.innerHTML = ""; // Clear existing products
+ console.log(`Updating product list for category: ${category}`); // Debugging line
+
+ const selectedProducts = products[category];
+
+ if (selectedProducts) {
+ selectedProducts.forEach(product => {
+ const productCard = document.createElement("div");
+ productCard.className = "product-card";
+
+ console.log(`Creating product card for: ${product.name}`); // Debugging line
+
+ productCard.innerHTML = `
+
+