Files
seisee/frontend_src/components/CampaignDocs.tsx

242 lines
9.2 KiB
TypeScript

import React, { useState, useEffect } from 'react';
interface TimelineEvent {
date: string;
event: string;
type: 'start' | 'data' | 'milestone' | 'operation' | 'end';
}
interface Document {
name: string;
file: string;
category: string;
}
interface CampaignManifest {
timeline: TimelineEvent[];
documents: Document[];
}
export default function CampaignDocs() {
const [manifest, setManifest] = useState<CampaignManifest | null>(null);
const [activeTab, setActiveTab] = useState<'timeline' | 'docs'>('timeline');
useEffect(() => {
fetch('/seismic/api/docs/manifest')
.then(r => r.json())
.then(setManifest)
.catch(console.error);
}, []);
if (!manifest) return <div style={{ padding: '20px', color: '#64748b' }}>Chargement...</div>;
const typeColors: Record<TimelineEvent['type'], string> = {
start: '#10b981',
data: '#3b82f6',
milestone: '#f59e0b',
operation: '#8b5cf6',
end: '#ef4444'
};
const typeIcons: Record<TimelineEvent['type'], string> = {
start: '🚀',
data: '📊',
milestone: '🎯',
operation: '⚙️',
end: '🏁'
};
return (
<div style={{ padding: '20px', maxWidth: '1200px', margin: '0 auto' }}>
{/* Header */}
<div style={{ marginBottom: '30px' }}>
<h1 style={{ fontSize: '2rem', fontWeight: 'bold', color: '#1e293b', marginBottom: '10px' }}>
📚 Campagne SeaKESP - Sète 2020
</h1>
<p style={{ color: '#64748b', fontSize: '1.1rem' }}>
Documentation, chronologie et ressources de la campagne OBN
</p>
</div>
{/* Tabs */}
<div style={{ display: 'flex', gap: '10px', marginBottom: '20px', borderBottom: '2px solid #e2e8f0' }}>
<button
onClick={() => setActiveTab('timeline')}
style={{
padding: '10px 20px',
background: activeTab === 'timeline' ? '#3b82f6' : 'transparent',
color: activeTab === 'timeline' ? 'white' : '#64748b',
border: 'none',
borderRadius: '8px 8px 0 0',
cursor: 'pointer',
fontWeight: 'bold',
fontSize: '1rem'
}}
>
📅 Chronologie
</button>
<button
onClick={() => setActiveTab('docs')}
style={{
padding: '10px 20px',
background: activeTab === 'docs' ? '#3b82f6' : 'transparent',
color: activeTab === 'docs' ? 'white' : '#64748b',
border: 'none',
borderRadius: '8px 8px 0 0',
cursor: 'pointer',
fontWeight: 'bold',
fontSize: '1rem'
}}
>
📄 Documents
</button>
</div>
{/* Timeline Tab */}
{activeTab === 'timeline' && (
<div style={{ background: 'white', padding: '30px', borderRadius: '12px', boxShadow: '0 2px 8px rgba(0,0,0,0.1)' }}>
<h2 style={{ fontSize: '1.5rem', fontWeight: 'bold', color: '#1e293b', marginBottom: '20px' }}>
Chronologie de la campagne
</h2>
<div style={{ position: 'relative', paddingLeft: '40px' }}>
{/* Timeline line */}
<div style={{
position: 'absolute',
left: '15px',
top: '10px',
bottom: '10px',
width: '3px',
background: 'linear-gradient(to bottom, #10b981, #ef4444)'
}} />
{manifest.timeline.map((event, idx) => (
<div key={idx} style={{ position: 'relative', marginBottom: '25px' }}>
{/* Timeline dot */}
<div style={{
position: 'absolute',
left: '-30px',
width: '15px',
height: '15px',
borderRadius: '50%',
background: typeColors[event.type],
border: '3px solid white',
boxShadow: '0 2px 8px rgba(0,0,0,0.2)'
}} />
{/* Event card */}
<div style={{
background: '#f8fafc',
padding: '15px',
borderRadius: '8px',
border: `2px solid ${typeColors[event.type]}`,
marginLeft: '10px'
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '5px' }}>
<span style={{ fontSize: '1.5rem' }}>{typeIcons[event.type]}</span>
<span style={{ fontSize: '0.9rem', fontWeight: 'bold', color: typeColors[event.type] }}>
{event.date}
</span>
</div>
<p style={{ fontSize: '1rem', color: '#334155', margin: 0 }}>
{event.event}
</p>
</div>
</div>
))}
</div>
{/* Stats */}
<div style={{ marginTop: '30px', display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '15px' }}>
<div style={{ background: '#f0f9ff', padding: '15px', borderRadius: '8px', textAlign: 'center' }}>
<div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#3b82f6' }}>46 jours</div>
<div style={{ color: '#64748b', fontSize: '0.9rem' }}>Durée totale</div>
</div>
<div style={{ background: '#f0fdf4', padding: '15px', borderRadius: '8px', textAlign: 'center' }}>
<div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#10b981' }}>345 fichiers</div>
<div style={{ color: '#64748b', fontSize: '0.9rem' }}>RAW collectés</div>
</div>
<div style={{ background: '#fef3c7', padding: '15px', borderRadius: '8px', textAlign: 'center' }}>
<div style={{ fontSize: '2rem', fontWeight: 'bold', color: '#f59e0b' }}>~800h</div>
<div style={{ color: '#64748b', fontSize: '0.9rem' }}>Enregistrements</div>
</div>
</div>
</div>
)}
{/* Documents Tab */}
{activeTab === 'docs' && (
<div style={{ background: 'white', padding: '30px', borderRadius: '12px', boxShadow: '0 2px 8px rgba(0,0,0,0.1)' }}>
<h2 style={{ fontSize: '1.5rem', fontWeight: 'bold', color: '#1e293b', marginBottom: '20px' }}>
Documents de référence
</h2>
{['Sources', 'Acquisition', 'Specifications', 'Geometry', 'Maps'].map(category => {
const categoryDocs = manifest.documents.filter(d => d.category === category);
if (categoryDocs.length === 0) return null;
const categoryIcons: Record<string, string> = {
Sources: '🎺',
Acquisition: '📋',
Specifications: '📖',
Geometry: '🗺️',
Maps: '🗺️'
};
return (
<div key={category} style={{ marginBottom: '25px' }}>
<h3 style={{ fontSize: '1.2rem', fontWeight: 'bold', color: '#475569', marginBottom: '10px', display: 'flex', alignItems: 'center', gap: '10px' }}>
<span>{categoryIcons[category]}</span>
{category}
</h3>
<div style={{ display: 'grid', gap: '10px' }}>
{categoryDocs.map((doc, idx) => (
<a
key={idx}
href={`/seismic/api/docs/${doc.file}`}
target="_blank"
rel="noopener noreferrer"
style={{
display: 'flex',
alignItems: 'center',
gap: '15px',
padding: '15px',
background: '#f8fafc',
border: '1px solid #e2e8f0',
borderRadius: '8px',
textDecoration: 'none',
color: '#334155',
transition: 'all 0.2s'
}}
onMouseEnter={(e) => {
e.currentTarget.style.background = '#f1f5f9';
e.currentTarget.style.borderColor = '#3b82f6';
}}
onMouseLeave={(e) => {
e.currentTarget.style.background = '#f8fafc';
e.currentTarget.style.borderColor = '#e2e8f0';
}}
>
<div style={{ fontSize: '1.5rem' }}>
{doc.file.endsWith('.pdf') ? '📄' :
doc.file.endsWith('.xlsx') || doc.file.endsWith('.xlsm') ? '📊' :
doc.file.endsWith('.docx') ? '📝' :
doc.file.endsWith('.png') ? '🖼️' : '📁'}
</div>
<div style={{ flex: 1 }}>
<div style={{ fontWeight: 'bold', marginBottom: '3px' }}>{doc.name}</div>
<div style={{ fontSize: '0.85rem', color: '#64748b' }}>{doc.file}</div>
</div>
<div style={{ color: '#3b82f6', fontSize: '1.2rem' }}></div>
</a>
))}
</div>
</div>
);
})}
</div>
)}
</div>
);
}