Fix: Hide PWA install button when installed, improve clustering, add debug logs
Fixes three major issues: 1. PWA Install Button (TopBar.jsx): - Import isRunningAsPWA() and canInstall() from pwaInstall.js - Add state to track if button should be shown - Listen to beforeinstallprompt and appinstalled events - Hide button when app is already installed or running as PWA 2. Search Suggestions Debug (SmartSearchBar.jsx, recoSearch.js): - Add console.log statements to trace search flow - Track: search query, results count, errors - Helps diagnose why suggestions don't appear - recoSearch: Log each endpoint attempt and response 3. Clustering Improvements (usePostsEngine.js, postPriority.js): - Reduce maxFullCards: 15 → 12 (fewer full cards) - Increase clusterRadius: 0.0015 → 0.002 (~200m for better grouping) - Increase minScoreForCard: 35 → 50 (stricter threshold) - Reduce default recoScore: 50 → 40 (lower baseline) - Add console.log for prioritization results - Result: More posts shown as simple markers, less clutter Debug logs will be visible in browser console to diagnose issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
76adb74833
commit
c659c0267d
|
|
@ -4,7 +4,7 @@ import { registerUser } from "../../api/client";
|
|||
import AuthToast from "../Auth/AuthToast";
|
||||
|
||||
// Import pour le bouton PWA
|
||||
import { promptInstall } from '../../pwaInstall';
|
||||
import { promptInstall, isRunningAsPWA, canInstall } from '../../pwaInstall';
|
||||
|
||||
const THEME_LABELS = { dark: "Dark", blue: "Blue", light: "Light" };
|
||||
const LAST_SIGNUP_KEY = "sociowire:lastSignup";
|
||||
|
|
@ -83,6 +83,7 @@ export default function TopBar({ theme = "dark", onChangeTheme }) {
|
|||
const [signupError, setSignupError] = useState("");
|
||||
const [signupInfo, setSignupInfo] = useState("");
|
||||
const [signupLoading, setSignupLoading] = useState(false);
|
||||
const [showInstallBtn, setShowInstallBtn] = useState(false);
|
||||
|
||||
const openModal = (nextMode) => {
|
||||
setMode(nextMode);
|
||||
|
|
@ -100,6 +101,34 @@ export default function TopBar({ theme = "dark", onChangeTheme }) {
|
|||
if (authenticated) setShowAuth(false);
|
||||
}, [authenticated]);
|
||||
|
||||
// Check if install button should be shown
|
||||
useEffect(() => {
|
||||
const checkInstall = () => {
|
||||
// Hide button if already running as PWA
|
||||
if (isRunningAsPWA()) {
|
||||
setShowInstallBtn(false);
|
||||
return;
|
||||
}
|
||||
// Show button if installation is available
|
||||
setShowInstallBtn(canInstall());
|
||||
};
|
||||
|
||||
checkInstall();
|
||||
|
||||
// Listen for beforeinstallprompt to update button visibility
|
||||
const handlePrompt = () => {
|
||||
setTimeout(checkInstall, 100);
|
||||
};
|
||||
|
||||
window.addEventListener('beforeinstallprompt', handlePrompt);
|
||||
window.addEventListener('appinstalled', () => setShowInstallBtn(false));
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('beforeinstallprompt', handlePrompt);
|
||||
window.removeEventListener('appinstalled', () => setShowInstallBtn(false));
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
const { get, qs, hs, hash } = parseMergedParams();
|
||||
|
|
@ -265,26 +294,28 @@ export default function TopBar({ theme = "dark", onChangeTheme }) {
|
|||
))}
|
||||
</div>
|
||||
|
||||
{/* BOUTON INSTALL PWA ici en haut */}
|
||||
<button
|
||||
onClick={() => promptInstall()}
|
||||
style={{
|
||||
marginLeft: '8px',
|
||||
padding: '5px 10px',
|
||||
fontSize: '12px',
|
||||
background: '#0ea5e9',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '999px',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
|
||||
}}
|
||||
>
|
||||
<i className="fa-solid fa-download"></i> Install
|
||||
</button>
|
||||
{/* BOUTON INSTALL PWA ici en haut - seulement si pas déjà installé */}
|
||||
{showInstallBtn && (
|
||||
<button
|
||||
onClick={() => promptInstall()}
|
||||
style={{
|
||||
marginLeft: '8px',
|
||||
padding: '5px 10px',
|
||||
fontSize: '12px',
|
||||
background: '#0ea5e9',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '999px',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
|
||||
}}
|
||||
>
|
||||
<i className="fa-solid fa-download"></i> Install
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export function calculatePostPriority(post, viewCenter, allPosts) {
|
|||
let score = 0;
|
||||
|
||||
// 1. Score intrinsèque du post (si disponible depuis reco-service)
|
||||
const recoScore = typeof post.score === 'number' ? post.score : 50;
|
||||
const recoScore = typeof post.score === 'number' ? post.score : 40; // Réduit de 50 à 40 pour base plus basse
|
||||
score += recoScore * 0.4; // Weight: 40%
|
||||
|
||||
// 2. Catégorie (certaines plus importantes)
|
||||
|
|
|
|||
|
|
@ -87,9 +87,15 @@ export function usePostsEngine({
|
|||
const viewCenter = center ? { lng: center.lng, lat: center.lat } : null;
|
||||
|
||||
const { fullCardPosts, simpleMarkerPosts } = prioritizePosts(visible, viewCenter, {
|
||||
maxFullCards: 15, // Max 15 cartes complètes
|
||||
clusterRadius: 0.0015, // ~150m clustering radius
|
||||
minScoreForCard: 35, // Score minimum pour carte complète
|
||||
maxFullCards: 12, // Max 12 cartes complètes (réduit de 15)
|
||||
clusterRadius: 0.002, // ~200m clustering radius (augmenté pour plus de groupement)
|
||||
minScoreForCard: 50, // Score minimum pour carte complète (augmenté de 35 à 50)
|
||||
});
|
||||
|
||||
console.log('[usePostsEngine] Prioritized:', {
|
||||
total: visible.length,
|
||||
fullCards: fullCardPosts.length,
|
||||
simpleMarkers: simpleMarkerPosts.length
|
||||
});
|
||||
|
||||
// Combine both types for "wanted" tracking
|
||||
|
|
|
|||
|
|
@ -98,12 +98,15 @@ export default function SmartSearchBar({
|
|||
|
||||
const t = setTimeout(async () => {
|
||||
try {
|
||||
console.log('[SmartSearchBar] Searching for:', query);
|
||||
const res = await recoSearch(query, { signal: ctrl.signal, limit: 12 });
|
||||
console.log('[SmartSearchBar] Got results:', res?.length || 0, res);
|
||||
setItems(res);
|
||||
setOpen(true);
|
||||
setActive(res.length ? 0 : -1);
|
||||
} catch (e) {
|
||||
if (ctrl.signal.aborted) return;
|
||||
console.error('[SmartSearchBar] Search error:', e);
|
||||
setErr((e && e.message) ? e.message : "Search error");
|
||||
setItems([]);
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -76,10 +76,18 @@ async function tryFetchAnyPath(q, { signal } = {}) {
|
|||
for (const p of paths) {
|
||||
try {
|
||||
const url = `${p}?q=${encodeURIComponent(query)}`;
|
||||
console.log('[recoSearch] Trying:', url);
|
||||
const res = await fetch(url, { credentials: "include", signal });
|
||||
|
||||
if (res.status === 404) continue;
|
||||
if (!res.ok) return []; // évite spam erreurs
|
||||
console.log('[recoSearch] Response status:', res.status);
|
||||
if (res.status === 404) {
|
||||
console.log('[recoSearch] 404, trying next path');
|
||||
continue;
|
||||
}
|
||||
if (!res.ok) {
|
||||
console.log('[recoSearch] Not OK, returning empty');
|
||||
return []; // évite spam erreurs
|
||||
}
|
||||
const data = await res.json().catch(() => null);
|
||||
|
||||
const arr = Array.isArray(data)
|
||||
|
|
@ -90,11 +98,16 @@ async function tryFetchAnyPath(q, { signal } = {}) {
|
|||
? data.results
|
||||
: [];
|
||||
|
||||
console.log('[recoSearch] Success! Returning', arr.length, 'results from', p);
|
||||
return arr.map(normalizeOne).filter(Boolean);
|
||||
} catch (e) {
|
||||
// Abort => stop net
|
||||
if (e && (e.name === "AbortError" || e.code === 20)) return [];
|
||||
if (e && (e.name === "AbortError" || e.code === 20)) {
|
||||
console.log('[recoSearch] Aborted');
|
||||
return [];
|
||||
}
|
||||
// autres erreurs => on teste prochain path
|
||||
console.log('[recoSearch] Error on', p, ':', e.message, '- trying next');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue