feat: système de signalement bug/idée + modal changelog avec limitations

- AppReport entity + migration (type, message, fingerprint SHA-256, created_at)
- POST /api/report avec rate-limit 5/heure par fingerprint IP
- ReportModal : formulaire type radio (bug/idée) + textarea 1 000 chars max
- ChangelogModal : fonctionnalités en prod, roadmap, 5 limitations honnêtes
- Deux boutons flottants bas-gauche (? info + ✉ signalement)
- Légende remontée pour éviter le chevauchement

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gwadaking
2026-04-14 12:52:32 -04:00
parent 83690b94ab
commit fd476f50c2
12 changed files with 643 additions and 7 deletions

View File

@@ -3,12 +3,16 @@ import SargassesMap from './components/Map/SargassesMap';
import SpotPanel from './components/SpotPanel/SpotPanel';
import Topbar from './components/Topbar/Topbar';
import Legend from './components/Legend/Legend';
import ReportModal from './components/ReportModal/ReportModal';
import ChangelogModal from './components/ChangelogModal/ChangelogModal';
import './App.css';
export default function App() {
const [selectedSpot, setSelectedSpot] = useState(null);
const [activeStep, setActiveStep] = useState('now');
const [flyToTarget, setFlyToTarget] = useState(null);
const [selectedSpot, setSelectedSpot] = useState(null);
const [activeStep, setActiveStep] = useState('now');
const [flyToTarget, setFlyToTarget] = useState(null);
const [showReport, setShowReport] = useState(false);
const [showChangelog, setShowChangelog] = useState(false);
return (
<div className="app">
@@ -29,11 +33,34 @@ export default function App() {
<Legend />
{/* Boutons flottants bas-gauche */}
<div className="app__actions">
<button
className="app__action-btn app__action-btn--info"
onClick={() => setShowChangelog(true)}
title="À propos / changelog"
aria-label="À propos"
>
?
</button>
<button
className="app__action-btn app__action-btn--report"
onClick={() => setShowReport(true)}
title="Signaler un bug ou soumettre une idée"
aria-label="Signalement"
>
</button>
</div>
<SpotPanel
spot={selectedSpot}
activeStep={activeStep}
onClose={() => setSelectedSpot(null)}
/>
{showReport && <ReportModal onClose={() => setShowReport(false)} />}
{showChangelog && <ChangelogModal onClose={() => setShowChangelog(false)} />}
</div>
);
}