feat: implement core platform features including business directory, admin dashboard, authentication, and API infrastructure
Some checks failed
Build and Push App / build (push) Failing after 16m2s

This commit is contained in:
2026-04-18 22:10:19 +02:00
parent 6ec1a3ae84
commit 3e2063e4fa
89 changed files with 4405 additions and 967 deletions

View File

@@ -4,26 +4,44 @@
import React, { useState, useEffect, useMemo, Suspense } from 'react';
import { useSearchParams } from 'next/navigation';
import { Search, Loader2 } from 'lucide-react';
import { CATEGORIES, Business } from '../../types';
import { CATEGORIES, Business, Country } from '../../types';
import BusinessCard from '../../components/BusinessCard';
import AnnuaireHero from '../../components/AnnuaireHero';
const AnnuairePageContent = () => {
const [businesses, setBusinesses] = useState<Business[]>([]);
const [featuredBusiness, setFeaturedBusiness] = useState<Business | null>(null);
const [countries, setCountries] = useState<Country[]>([]);
const [loading, setLoading] = useState(true);
const [filterCategory, setFilterCategory] = useState('All');
const [filterCountry, setFilterCountry] = useState('All');
const [searchQuery, setSearchQuery] = useState('');
const searchParams = useSearchParams();
// 1. Fetch Featured Headliner once
// 1. Fetch Countries
useEffect(() => {
const fetchCountries = async () => {
try {
const res = await fetch('/api/countries');
const data = await res.json();
if (Array.isArray(data)) setCountries(data);
} catch (e) {}
};
fetchCountries();
}, []);
// 2. Fetch Featured Headliner once
useEffect(() => {
const fetchHeadliner = async () => {
try {
const res = await fetch('/api/businesses?featured=true');
const data = await res.json();
if (Array.isArray(data) && data.length > 0) {
setFeaturedBusiness(data[0]);
// Stable random based on the current date (YYYYMMDD)
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
const seed = parseInt(today);
const randomIndex = seed % data.length;
setFeaturedBusiness(data[randomIndex]);
}
} catch (error) {
console.error('Error fetching headliner:', error);
@@ -32,13 +50,14 @@ const AnnuairePageContent = () => {
fetchHeadliner();
}, []);
// 2. Fetch businesses from API
// 3. Fetch businesses from API
useEffect(() => {
const fetchBusinesses = async () => {
setLoading(true);
try {
const params = new URLSearchParams();
if (filterCategory !== 'All') params.append('category', filterCategory);
if (filterCountry !== 'All') params.append('countryId', filterCountry);
if (searchQuery) params.append('q', searchQuery);
const res = await fetch(`/api/businesses?${params.toString()}`);
@@ -55,11 +74,17 @@ const AnnuairePageContent = () => {
const timeoutId = setTimeout(fetchBusinesses, 300); // Debounce
return () => clearTimeout(timeoutId);
}, [filterCategory, searchQuery]);
}, [filterCategory, searchQuery, filterCountry]);
useEffect(() => {
const q = searchParams.get('q');
if (q) setSearchQuery(q);
const cat = searchParams.get('category');
if (cat) setFilterCategory(cat);
const country = searchParams.get('country');
if (country) setFilterCountry(country);
}, [searchParams]);
const filteredBusinesses = businesses;
@@ -87,9 +112,23 @@ const AnnuairePageContent = () => {
/>
</div>
<div className="mb-6">
<label className="block text-sm font-medium text-gray-700 mb-2">Pays</label>
<select
value={filterCountry}
onChange={(e) => setFilterCountry(e.target.value)}
className="w-full border-gray-300 rounded-md shadow-sm focus:ring-brand-500 focus:border-brand-500 sm:text-sm p-2 border"
>
<option value="All">Tous les pays</option>
{countries.map(c => (
<option key={c.id} value={c.id}>{c.flag} {c.name}</option>
))}
</select>
</div>
<div className="mb-6">
<label className="block text-sm font-medium text-gray-700 mb-2">Catégorie</label>
<div className="space-y-2">
<div className="space-y-1 max-h-60 overflow-y-auto pr-1">
<div className="flex items-center">
<input
id="cat-all"