feat: Implement comprehensive OAuth and email verification authentication system

- Add email verification with token-based validation
- Integrate Google, Facebook, and Yahoo OAuth providers
- Add OAuth configuration and email service modules
- Update User model with email_verified, oauth_provider, oauth_id fields
- Implement async password hashing/verification to prevent blocking
- Add database migration script for new user fields
- Create email verification page with professional UI
- Update login page with social login buttons (Google, Facebook, Yahoo)
- Add OAuth callback token handling
- Implement scroll-to-top navigation component
- Add 5-second real-time polling for Products and Services pages
- Enhance About page with Apple-style scroll animations
- Update Home and Contact pages with branding and business info
- Optimize API cache with prefix-based clearing
- Create comprehensive setup documentation and quick start guide
- Fix login performance with ThreadPoolExecutor for bcrypt operations

Performance improvements:
- Login time optimized to ~220ms with async password verification
- Real-time data updates every 5 seconds
- Non-blocking password operations

Security enhancements:
- Email verification required for new accounts
- OAuth integration for secure social login
- Verification tokens expire after 24 hours
- Password field nullable for OAuth users
This commit is contained in:
2026-02-04 00:41:16 -06:00
parent 72f17c8be9
commit 9a7b00649b
22 changed files with 2273 additions and 128 deletions

View File

@@ -37,7 +37,7 @@ const Products = () => {
const [loading, setLoading] = useState(true);
const [search, setSearch] = useState(searchParams.get("search") || "");
const [category, setCategory] = useState(
searchParams.get("category") || "all"
searchParams.get("category") || "all",
);
const [priceRange, setPriceRange] = useState([0, 3000]);
const [sortBy, setSortBy] = useState("name");
@@ -62,25 +62,37 @@ const Products = () => {
fetchProducts();
}, [category, search]);
const fetchProducts = async () => {
setLoading(true);
// Auto-refresh every 5 seconds for real-time updates
useEffect(() => {
const interval = setInterval(() => {
fetchProducts(true); // Silent refresh without loading spinner
}, 5000); // 5 seconds
return () => clearInterval(interval);
}, [category, search]);
// Refresh products when user returns to the tab
useEffect(() => {
const handleVisibilityChange = () => {
if (!document.hidden) {
fetchProducts();
}
};
document.addEventListener("visibilitychange", handleVisibilityChange);
return () =>
document.removeEventListener("visibilitychange", handleVisibilityChange);
}, [category, search]);
const fetchProducts = async (silent = false) => {
if (!silent) setLoading(true);
try {
const params = new URLSearchParams();
if (category && category !== "all") params.append("category", category);
if (search) params.append("search", search);
const cacheKey = `products-${params.toString()}`;
const cached = getCached(cacheKey);
if (cached) {
setProducts(cached);
setLoading(false);
return;
}
const response = await axios.get(`${API}/products?${params.toString()}`);
setProducts(response.data);
setCache(cacheKey, response.data);
} catch (error) {
console.error("Failed to fetch products:", error);
} finally {