Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .yarn/install-state.gz
Binary file not shown.
21 changes: 19 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,36 @@
"tailwind:viewer": "tailwind-config-viewer -o"
},
"dependencies": {
"@contentful/rich-text-from-markdown": "^16.0.1",
"@contentful/rich-text-from-markdown": "^16.1.8",
"@contentful/rich-text-html-renderer": "^17.0.1",
"@contentful/rich-text-plain-text-renderer": "^17.0.1",
"@contentful/rich-text-types": "^17.0.1",
"@headlessui/react": "^2.2.4",
"@heroicons/react": "^2.2.0",
"@react-leaflet/core": "^3.0.0",
"@tailwindcss/line-clamp": "^0.4.4",
"@tiptap/extension-color": "^3.22.3",
"@tiptap/extension-image": "^3.20.5",
"@tiptap/extension-link": "^3.20.5",
"@tiptap/extension-placeholder": "^3.20.5",
"@tiptap/extension-text-align": "^3.20.5",
"@tiptap/extension-text-style": "^3.22.3",
"@tiptap/extension-underline": "^3.20.5",
"@tiptap/extensions": "^3.22.3",
"@tiptap/pm": "^3.20.5",
"@tiptap/react": "^3.20.5",
"@tiptap/starter-kit": "^3.20.5",
"@vercel/analytics": "^1.5.0",
"algoliasearch": "^5.28.0",
"classnames": "^2.5.1",
"contentful": "^11.7.2",
"contentful-management": "^11.54.2",
"hast-util-to-mdast": "^10.1.2",
"instantsearch.js": "^4.79.0",
"leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3",
"next": "15.5.7",
"next-auth": "^4.24.13",
"next-seo": "^6.8.0",
"nodemailer": "^7.0.3",
"nodemailer-react": "^1.0.2",
Expand All @@ -45,7 +58,11 @@
"react-instantsearch-nextjs": "^0.5.0",
"react-json-view": "^1.21.3",
"react-leaflet": "^5.0.0",
"react-share": "^5.2.2"
"react-share": "^5.2.2",
"rehype-parse": "^9.0.1",
"remark-stringify": "^11.0.0",
"tiptap-markdown": "^0.9.0",
"unified": "^11.0.5"
},
"devDependencies": {
"@eslint/compat": "^1.3.0",
Expand Down
107 changes: 107 additions & 0 deletions src/app/admin/fiches/[id]/editor/EditorMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
'use client'

import { useEffect } from 'react'
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet'
import 'leaflet/dist/leaflet.css'
import L from 'leaflet'

// Fix le bug des icônes Leaflet qui ne s'affichent pas en Next.js
const fixLeafletIcons = () => {
// eslint-disable-next-line no-underscore-dangle
delete (L.Icon.Default.prototype as any)._getIconUrl
L.Icon.Default.mergeOptions({
iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png',
iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png',
})
}

type Structure = {
id: string
nom: string
adresse: string
type: string
tel?: string
email?: string
latLon?: { lat: number; lon: number }
}

export default function EditorMap({ structures }: { structures: Structure[] }) {
useEffect(() => {
fixLeafletIcons()
}, [])

// Filtre les structures avec des coordonnées valides
const structuresAvecCoords = structures.filter(
(s) => s.latLon && s.latLon.lat !== 0 && s.latLon.lon !== 0,
)

// Centre de la carte sur Auvergne-Rhône-Alpes
const center: [number, number] = [45.5, 4.5]

return (
<div className="flex gap-4 flex-wrap lg:flex-nowrap">
{/* Carte */}
<div className="w-full lg:w-7/12 rounded-xl overflow-hidden border border-gray-200" style={{ height: 400 }}>
<MapContainer
center={center}
zoom={7}
style={{ height: '100%', width: '100%' }}
>
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{structuresAvecCoords.map((s) => (
<Marker
key={s.id}
position={[s.latLon!.lat, s.latLon!.lon]}
>
<Popup>
<div className="text-sm">
<p className="font-semibold">{s.nom}</p>
<p className="text-gray-500 text-xs">{s.type}</p>
<p className="text-xs mt-1">{s.adresse}</p>
{s.tel && <p className="text-xs">📞 {s.tel}</p>}
{s.email && <p className="text-xs">✉️ {s.email}</p>}
</div>
</Popup>
</Marker>
))}
</MapContainer>
</div>

{/* Liste des structures — identique au vrai site */}
<div className="w-full lg:w-5/12 overflow-y-auto" style={{ maxHeight: 400 }}>
{structures.map((s) => (
<div key={s.id} className="pb-4 mb-4 border-b border-gray-100 last:border-0">
<p className="font-semibold text-gray-800 text-sm">{s.nom}</p>
<span className="inline-block text-xs bg-blue-50 text-blue-700 px-2 py-0.5 rounded-full mt-1">
{s.type}
</span>
{s.adresse && (
<p className="text-xs text-gray-500 mt-1 flex items-start gap-1">
<span>📍</span> {s.adresse}
</p>
)}
{s.tel && (
<p className="text-xs text-gray-500 flex items-center gap-1">
<span>📞</span> {s.tel}
</p>
)}
{s.email && (
<p className="text-xs text-gray-500 flex items-center gap-1">
<span>✉️</span> {s.email}
</p>
)}
</div>
))}
{structures.length === 0 && (
<p className="text-sm text-gray-400 italic text-center py-8">
Sélectionnez des types de dispositif pour voir les structures associées.
</p>
)}
</div>
</div>
)
}
Loading