diff --git a/client/src/components/quickmed/HomePage/FeaturesSection.jsx b/client/src/components/quickmed/HomePage/FeaturesSection.jsx new file mode 100644 index 0000000..3b5fab3 --- /dev/null +++ b/client/src/components/quickmed/HomePage/FeaturesSection.jsx @@ -0,0 +1,53 @@ +// client/src/components/quickmed/HomePage/FeaturesSection.jsx +import React from 'react'; +import Icons from './Icons'; + +const FeaturesSection = () => { + const features = [ + { + icon: , + title: 'Instant Search', + description: 'Get real-time medicine suggestions as you type with our powerful autocomplete.', + }, + { + icon: , + title: 'FDA Verified Data', + description: 'Access reliable drug information directly from the OpenFDA database.', + }, + { + icon: , + title: 'Comprehensive Details', + description: 'View usage, side effects, ingredients, warnings, and storage information.', + }, + ]; + + return ( +
+
+
+

Why Choose QuickMed?

+

+ Get accurate, comprehensive, and up-to-date medicine information at your fingertips. +

+
+ +
+ {features.map((feature, index) => ( +
+
+ {feature.icon} +
+

{feature.title}

+

{feature.description}

+
+ ))} +
+
+
+ ); +}; + +export default FeaturesSection; diff --git a/client/src/components/quickmed/HomePage/Footer.jsx b/client/src/components/quickmed/HomePage/Footer.jsx new file mode 100644 index 0000000..c7db50b --- /dev/null +++ b/client/src/components/quickmed/HomePage/Footer.jsx @@ -0,0 +1,61 @@ +// client/src/components/quickmed/HomePage/Footer.jsx +import React from 'react'; +import Icons from './Icons'; + +const Footer = ({ navigateToQuickclinic }) => { + return ( +
+
+
+ {/* Brand Column */} +
+
+
+ +
+ QuickMed +
+

Part of the QuickClinic ecosystem

+
+ + {/* Disclaimer Column */} +
+
+ Disclaimer +
+

+ Data sourced from OpenFDA. For educational purposes only and should not replace + professional medical advice. +

+
+ + {/* CTA Column */} +
+
+ Need Medical Advice? +
+

+ Book an appointment with top doctors near you. +

+ +
+
+
+
+ ); +}; + +export default Footer; diff --git a/client/src/components/quickmed/HomePage/HeroSection.jsx b/client/src/components/quickmed/HomePage/HeroSection.jsx new file mode 100644 index 0000000..7907e54 --- /dev/null +++ b/client/src/components/quickmed/HomePage/HeroSection.jsx @@ -0,0 +1,14 @@ +// client/src/components/quickmed/HomePage/HeroSection.jsx +import React from 'react'; + +const HeroSection = () => { + return ( +
+ {/* Decorative Elements */} +
+
+
+ ); +}; + +export default HeroSection; diff --git a/client/src/components/quickmed/HomePage/Icons.jsx b/client/src/components/quickmed/HomePage/Icons.jsx new file mode 100644 index 0000000..fd2fa6c --- /dev/null +++ b/client/src/components/quickmed/HomePage/Icons.jsx @@ -0,0 +1,92 @@ +// client/src/components/quickmed/HomePage/Icons.jsx +import React from 'react'; + +const Icons = { + Search: () => ( + + + + ), + Sun: () => ( + + + + ), + Moon: () => ( + + + + ), + Pill: () => ( + + + + ), + Shield: () => ( + + + + ), + Lightning: () => ( + + + + ), + Database: () => ( + + + + ), + Close: () => ( + + + + ), + Spinner: () => ( + + + + + ), +}; + +export default Icons; diff --git a/client/src/components/quickmed/HomePage/InfoBanner.jsx b/client/src/components/quickmed/HomePage/InfoBanner.jsx new file mode 100644 index 0000000..f24f5d2 --- /dev/null +++ b/client/src/components/quickmed/HomePage/InfoBanner.jsx @@ -0,0 +1,33 @@ +// client/src/components/quickmed/HomePage/InfoBanner.jsx +import React from 'react'; + +const InfoBanner = ({ navigateToQuickclinic }) => { + return ( +
+
+
+
+
+
+

+ Part of QuickClinic Ecosystem +

+

+ QuickMed integrates seamlessly with QuickClinic's suite of healthcare tools for a + complete medical information experience. +

+
+ +
+
+
+
+ ); +}; + +export default InfoBanner; diff --git a/client/src/components/quickmed/HomePage/SearchBar.jsx b/client/src/components/quickmed/HomePage/SearchBar.jsx new file mode 100644 index 0000000..7277eca --- /dev/null +++ b/client/src/components/quickmed/HomePage/SearchBar.jsx @@ -0,0 +1,110 @@ +// client/src/components/quickmed/HomePage/SearchBar.jsx +import React from 'react'; +import Icons from './Icons'; + +const SearchBar = ({ + searchRef, + searchQuery, + setSearchQuery, + isLoading, + showSuggestions, + setShowSuggestions, + suggestions, + selectedIndex, + setSelectedIndex, + handleSelectMedicine, + handleKeyDown, +}) => { + const popularTags = ['Aspirin', 'Ibuprofen', 'Acetaminophen', 'Amoxicillin']; + + const handleTagClick = (tag) => { + setSearchQuery(tag); + setShowSuggestions(true); + }; + + return ( +
+ {/* Search Box */} +
+
+
+
+ {isLoading ? : } +
+ { + setSearchQuery(e.target.value); + setShowSuggestions(true); + setSelectedIndex(-1); + }} + onFocus={() => setShowSuggestions(true)} + onKeyDown={handleKeyDown} + placeholder="Search for medicines (e.g., Aspirin, Ibuprofen...)" + className="w-full px-4 py-4 sm:py-5 bg-transparent text-med-text placeholder-med-text-muted focus:outline-none text-base sm:text-lg" + /> + {searchQuery && ( + + )} +
+
+ + {/* Suggestions Dropdown */} + {showSuggestions && suggestions.length > 0 && ( +
+
    + {suggestions.map((suggestion, index) => { + const name = suggestion.name || suggestion; + return ( +
  • + +
  • + ); + })} +
+
+ )} + + {/* No Results */} + {showSuggestions && searchQuery.length >= 2 && !isLoading && suggestions.length === 0 && ( +
+ No medicines found for "{searchQuery}" +
+ )} + + {/* Quick Tags */} +
+ Popular searches: + {popularTags.map((tag) => ( + + ))} +
+
+ ); +}; + +export default SearchBar; diff --git a/client/src/pages/quickmed/HomePage.jsx b/client/src/pages/quickmed/HomePage.jsx new file mode 100644 index 0000000..a64b009 --- /dev/null +++ b/client/src/pages/quickmed/HomePage.jsx @@ -0,0 +1,183 @@ +// client/src/pages/quickmed/HomePage.jsx +import React, { useState, useEffect, useRef, useCallback } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { getMedicineSuggestions } from '../../service/medicineApiService'; +import Icons from '../../components/quickmed/HomePage/Icons'; +import SearchBar from '../../components/quickmed/HomePage/SearchBar'; +import HeroSection from '../../components/quickmed/HomePage/HeroSection'; +import FeaturesSection from '../../components/quickmed/HomePage/FeaturesSection'; +import InfoBanner from '../../components/quickmed/HomePage/InfoBanner'; +import Footer from '../../components/quickmed/HomePage/Footer'; + +const QuickMedPage = () => { + const [darkMode, setDarkMode] = useState(() => { + if (typeof window !== 'undefined') { + return ( + localStorage.getItem('quickmed-theme') === 'dark' || + (!localStorage.getItem('quickmed-theme') && + window.matchMedia('(prefers-color-scheme: dark)').matches) + ); + } + return false; + }); + const [searchQuery, setSearchQuery] = useState(''); + const [suggestions, setSuggestions] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [showSuggestions, setShowSuggestions] = useState(false); + const [selectedIndex, setSelectedIndex] = useState(-1); + + const searchRef = useRef(null); + const navigate = useNavigate(); + + // Toggle dark mode + useEffect(() => { + if (darkMode) { + document.documentElement.classList.add('dark'); + localStorage.setItem('quickmed-theme', 'dark'); + } else { + document.documentElement.classList.remove('dark'); + localStorage.setItem('quickmed-theme', 'light'); + } + }, [darkMode]); + + // Debounced search for suggestions + const fetchSuggestions = useCallback(async (query) => { + if (query.length < 2) { + setSuggestions([]); + return; + } + + setIsLoading(true); + try { + const response = await getMedicineSuggestions(query); + setSuggestions(response.suggestions || []); + } catch (error) { + console.error('Error fetching suggestions:', error); + setSuggestions([]); + } finally { + setIsLoading(false); + } + }, []); + + // Debounce effect + useEffect(() => { + const timer = setTimeout(() => { + if (searchQuery) { + fetchSuggestions(searchQuery); + } else { + setSuggestions([]); + } + }, 300); + + return () => clearTimeout(timer); + }, [searchQuery, fetchSuggestions]); + + // Click outside handler + useEffect(() => { + const handleClickOutside = (event) => { + if (searchRef.current && !searchRef.current.contains(event.target)) { + setShowSuggestions(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + // Handle medicine selection + const handleSelectMedicine = (medicineName) => { + const encodedName = encodeURIComponent(medicineName.toLowerCase().replace(/\s+/g, '-')); + navigate(`/quick-med/medicine/${encodedName}`); + }; + + const navigateToQuickclinic = () => { + navigate('/'); + }; + + // Keyboard navigation + const handleKeyDown = (e) => { + if (!showSuggestions || suggestions.length === 0) return; + + switch (e.key) { + case 'ArrowDown': + e.preventDefault(); + setSelectedIndex((prev) => (prev < suggestions.length - 1 ? prev + 1 : prev)); + break; + case 'ArrowUp': + e.preventDefault(); + setSelectedIndex((prev) => (prev > 0 ? prev - 1 : -1)); + break; + case 'Enter': + e.preventDefault(); + if (selectedIndex >= 0 && suggestions[selectedIndex]) { + handleSelectMedicine(suggestions[selectedIndex].name || suggestions[selectedIndex]); + } + break; + case 'Escape': + setShowSuggestions(false); + setSelectedIndex(-1); + break; + default: + break; + } + }; + + return ( +
+
+ + + {/* Search Bar Section */} +
+
+ +
+
+ {/* Badge */} +
+ + Powered by OpenFDA +
+ + {/* Heading */} +

+ Find Medicine + + Information Instantly + +

+ + {/* Subtitle */} +

+ Search for any medicine and get detailed information about usage, side effects, + ingredients, warnings, and more from verified FDA sources. +

+ + {/* Search Bar Component */} + +
+
+
+ + + +
+ +
+
+ ); +}; + +export default QuickMedPage; diff --git a/client/src/pages/quickmed/MedicineDetails.jsx b/client/src/pages/quickmed/MedicineDetails.jsx index ab66d67..c00cfcf 100644 --- a/client/src/pages/quickmed/MedicineDetails.jsx +++ b/client/src/pages/quickmed/MedicineDetails.jsx @@ -2,7 +2,6 @@ import { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { getMedicineDetails } from '../../service/medicineApiService'; import Loading from '../../components/ui/Loading'; -import Navbar from '../../components/quickmed/Navbar'; import MedicineHeader from '../../components/quickmed/MedicineDetailsPage/MedicineHeader'; import MedicineContent from '../../components/quickmed/MedicineDetailsPage/MedicineContent'; import MedicineError from '../../components/quickmed/MedicineDetailsPage/MedicineError'; diff --git a/client/src/routes/QuickmedRoutes.jsx b/client/src/routes/QuickmedRoutes.jsx index 1ef15aa..22de1a4 100644 --- a/client/src/routes/QuickmedRoutes.jsx +++ b/client/src/routes/QuickmedRoutes.jsx @@ -2,12 +2,14 @@ import { Routes, Route } from 'react-router-dom'; import Navbar from '../components/quickmed/Navbar'; import MedicineDetails from '../pages/quickmed/MedicineDetails'; import NotFoundPage from '../components/ui/NotFoundPage'; +import HomePage from '../pages/quickmed/HomePage'; export default function QuickmedRoutes() { return ( <> } /> + } /> } />