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:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user