NextGraph integration (WIP), broker banner, and feature-based architecture
- Add NextGraph data layer with @ng-org/orm, SHEX shapes (Event, UserProfile, Participation), session management, and FestipodDataContext with dual-mode operation (connected via NextGraph or local seed data) - Add BrokerBanner and NgStatus components showing connection status - Refactor to feature-based architecture: organize code by business domain (event, user, home, auth, workshop, meeting, notification) instead of technical layer. Modules only import from shared/, never from each other - Collocate BDD features and step definitions with their modules: event-specific steps in event/steps/, user steps in user/steps/, shared generic steps remain in shared/steps/ - Set up multi-layer BDD structure (frontend/backend/e2e steps per module) - Add project documentation (AGENTS.md, .project/knowledge/) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,275 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Header, Text, Input, Button, Placeholder } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
// Demo data for suggestions
|
||||
const existingEvents = [
|
||||
{ name: 'Résidence Reconnexion', relayedBy: 'Thomas Martin' },
|
||||
];
|
||||
|
||||
const importableEvents = [
|
||||
{
|
||||
name: 'Festival des Utopies Concrètes',
|
||||
source: 'Mobilizon',
|
||||
date: '2026-03-15',
|
||||
location: 'Paris, Parc de la Villette',
|
||||
description: 'Festival annuel présentant des alternatives concrètes pour un monde durable.',
|
||||
},
|
||||
{
|
||||
name: 'Rencontres de l\'Écologie',
|
||||
source: 'Transiscope',
|
||||
date: '2026-04-20',
|
||||
location: 'Lyon, Halle Tony Garnier',
|
||||
description: 'Deux jours de conférences et ateliers sur la transition écologique.',
|
||||
},
|
||||
];
|
||||
|
||||
export function CreateEventScreen({ navigate }: ScreenProps) {
|
||||
const [name, setName] = useState('');
|
||||
const [startDate, setStartDate] = useState('');
|
||||
const [location, setLocation] = useState('');
|
||||
const [description, setDescription] = useState('');
|
||||
const [showSuggestions, setShowSuggestions] = useState(false);
|
||||
const [importedFrom, setImportedFrom] = useState<string | null>(null);
|
||||
|
||||
// Show warning only when key fields are filled AND not imported from external source
|
||||
const showDuplicateWarning = name.length > 3 && startDate && location.length > 3 && !importedFrom;
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Relayer un événement"
|
||||
left={<span onClick={() => navigate('home')} style={{ cursor: 'pointer' }}>✕</span>}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, padding: 16, overflow: 'auto' }}>
|
||||
{/* Cover image upload */}
|
||||
<Placeholder
|
||||
height={140}
|
||||
label="+ Ajouter une photo"
|
||||
style={{ marginBottom: 20, cursor: 'pointer' }}
|
||||
/>
|
||||
|
||||
{/* Duplicate warning - shown when key fields are filled */}
|
||||
{showDuplicateWarning && (
|
||||
<div style={{
|
||||
background: '#FEF3C7',
|
||||
border: '2px solid #F59E0B',
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
marginBottom: 16,
|
||||
}}>
|
||||
<Text style={{ margin: 0, fontWeight: 'bold', fontSize: 14, marginBottom: 4 }}>
|
||||
Événement similaire détecté
|
||||
</Text>
|
||||
<Text style={{ margin: 0, fontSize: 13, lineHeight: 1.5 }}>
|
||||
Un événement similaire a déjà été relayé par <strong>Thomas Martin</strong>.
|
||||
Vous pouvez continuer si vous pensez qu'il s'agit d'un événement différent.
|
||||
</Text>
|
||||
<Text
|
||||
style={{ margin: '8px 0 0 0', fontSize: 13, cursor: 'pointer', textDecoration: 'underline' }}
|
||||
onClick={() => navigate('event-detail')}
|
||||
>
|
||||
Voir l'événement existant →
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
<div style={{ position: 'relative' }}>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Nom de l'événement *</Text>
|
||||
<Input
|
||||
placeholder="Donnez un nom à votre événement"
|
||||
value={name}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setName(e.target.value);
|
||||
setShowSuggestions(e.target.value.length > 0);
|
||||
setImportedFrom(null); // Reset import flag when user types manually
|
||||
}}
|
||||
onFocus={() => name.length > 0 && setShowSuggestions(true)}
|
||||
onBlur={() => setTimeout(() => setShowSuggestions(false), 200)}
|
||||
/>
|
||||
|
||||
{/* Suggestions dropdown */}
|
||||
{showSuggestions && (
|
||||
<div style={{
|
||||
position: 'absolute',
|
||||
top: '100%',
|
||||
left: 0,
|
||||
right: 0,
|
||||
background: 'white',
|
||||
border: '2px solid var(--sketch-black)',
|
||||
borderRadius: 8,
|
||||
marginTop: 4,
|
||||
zIndex: 10,
|
||||
maxHeight: 250,
|
||||
overflow: 'auto',
|
||||
}}>
|
||||
{/* Existing events - not selectable */}
|
||||
{existingEvents.length > 0 && (
|
||||
<>
|
||||
<div style={{ padding: '8px 12px', background: 'var(--sketch-light-gray)', fontSize: 12, fontWeight: 'bold' }}>
|
||||
Déjà relayé sur Festipod
|
||||
</div>
|
||||
{existingEvents.map((event, i) => (
|
||||
<div
|
||||
key={`existing-${i}`}
|
||||
style={{
|
||||
padding: '10px 12px',
|
||||
borderBottom: '1px solid var(--sketch-light-gray)',
|
||||
opacity: 0.6,
|
||||
cursor: 'not-allowed',
|
||||
}}
|
||||
>
|
||||
<Text style={{ margin: 0, fontSize: 14 }}>{event.name}</Text>
|
||||
<Text style={{ margin: '2px 0 0 0', fontSize: 12, color: 'var(--sketch-gray)' }}>
|
||||
Relayé par {event.relayedBy}
|
||||
</Text>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Importable events */}
|
||||
{importableEvents.length > 0 && (
|
||||
<>
|
||||
<div style={{ padding: '8px 12px', background: 'var(--sketch-light-gray)', fontSize: 12, fontWeight: 'bold' }}>
|
||||
Importer depuis une source externe
|
||||
</div>
|
||||
{importableEvents.map((event, i) => (
|
||||
<div
|
||||
key={`import-${i}`}
|
||||
style={{
|
||||
padding: '10px 12px',
|
||||
borderBottom: '1px solid var(--sketch-light-gray)',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
onClick={() => {
|
||||
setName(event.name);
|
||||
setStartDate(event.date);
|
||||
setLocation(event.location);
|
||||
setDescription(event.description);
|
||||
setImportedFrom(event.source);
|
||||
setShowSuggestions(false);
|
||||
}}
|
||||
>
|
||||
<Text style={{ margin: 0, fontSize: 14 }}>{event.name}</Text>
|
||||
<Text style={{ margin: '2px 0 0 0', fontSize: 12, color: 'var(--sketch-gray)' }}>
|
||||
via {event.source} · {event.location}
|
||||
</Text>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 12 }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Date de début *</Text>
|
||||
<Input
|
||||
type="date"
|
||||
placeholder="Début"
|
||||
value={startDate}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setStartDate(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Date de fin</Text>
|
||||
<Input type="date" placeholder="Fin" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 12 }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Heure de début *</Text>
|
||||
<Input type="time" placeholder="Début" />
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Heure de fin</Text>
|
||||
<Input type="time" placeholder="Fin" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Lieu *</Text>
|
||||
<Input
|
||||
placeholder="Ajouter un lieu"
|
||||
value={location}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setLocation(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Description</Text>
|
||||
<textarea
|
||||
className="sketchy-input"
|
||||
placeholder="Décrivez votre événement..."
|
||||
rows={4}
|
||||
style={{ resize: 'none' }}
|
||||
value={description}
|
||||
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setDescription(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Thématique *</Text>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
|
||||
{[
|
||||
{ id: 'culture', label: 'Culture', emoji: '🎭' },
|
||||
{ id: 'sport', label: 'Sport', emoji: '⚽' },
|
||||
{ id: 'nature', label: 'Nature', emoji: '🌿' },
|
||||
{ id: 'social', label: 'Social', emoji: '👥' },
|
||||
{ id: 'food', label: 'Gastronomie', emoji: '🍽️' },
|
||||
{ id: 'music', label: 'Musique', emoji: '🎵' },
|
||||
{ id: 'tech', label: 'Tech', emoji: '💻' },
|
||||
{ id: 'other', label: 'Autre', emoji: '✨' },
|
||||
].map((theme) => (
|
||||
<Button
|
||||
key={theme.id}
|
||||
variant={theme.id === 'social' ? 'primary' : 'default'}
|
||||
style={{ fontSize: 13 }}
|
||||
>
|
||||
{theme.emoji} {theme.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div style={{ padding: 16, borderTop: '2px solid var(--sketch-black)' }}>
|
||||
{showDuplicateWarning && (
|
||||
<div style={{
|
||||
background: '#FEF3C7',
|
||||
border: '2px solid #F59E0B',
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
marginBottom: 12,
|
||||
}}>
|
||||
<Text style={{ margin: 0, fontSize: 13, lineHeight: 1.5 }}>
|
||||
Un événement similaire a déjà été relayé par <strong>Thomas Martin</strong>.{' '}
|
||||
<span
|
||||
style={{ cursor: 'pointer', textDecoration: 'underline' }}
|
||||
onClick={() => navigate('event-detail')}
|
||||
>
|
||||
Voir →
|
||||
</span>
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
<Button
|
||||
variant="primary"
|
||||
style={{ width: '100%' }}
|
||||
onClick={() => navigate('event-detail')}
|
||||
>
|
||||
Relayer l'événement
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Header, Title, Text, Button, Avatar, Placeholder, Divider } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function EventDetailScreen({ navigate }: ScreenProps) {
|
||||
const [isJoined, setIsJoined] = useState(false);
|
||||
|
||||
// In a real app, this would come from comparing current user with event creator
|
||||
const isOwner = true;
|
||||
|
||||
const knownAttendees = [
|
||||
{ initials: 'MD', name: 'Marie' },
|
||||
{ initials: 'TM', name: 'Thomas' },
|
||||
];
|
||||
const unknownCount = 22;
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Événement"
|
||||
left={<span onClick={() => navigate('events')} style={{ cursor: 'pointer' }}>←</span>}
|
||||
right={isOwner && <span onClick={() => navigate('update-event')} style={{ cursor: 'pointer' }}>✎</span>}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, overflow: 'auto' }}>
|
||||
{/* Cover image */}
|
||||
<Placeholder height={180} label="Photo de couverture" />
|
||||
|
||||
<div style={{ padding: 16 }}>
|
||||
<Title className="user-content" style={{ marginBottom: 8 }}>Résidence Reconnexion</Title>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 16 }}>
|
||||
<Text style={{ margin: 0, fontSize: 15 }}>
|
||||
📅 <span className="user-content">Lundi 16 - Vendredi 20 février 2026</span>
|
||||
</Text>
|
||||
<Text style={{ margin: 0, fontSize: 15 }}>
|
||||
🕓 <span className="user-content">Semaine complète (arrivée dimanche possible)</span>
|
||||
</Text>
|
||||
<Text style={{ margin: 0, fontSize: 15 }}>
|
||||
📍 <span className="user-content">Le Revel, Rogues (30)</span>
|
||||
<span style={{ color: 'var(--sketch-gray)' }}> · 142 km</span>
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 8, marginBottom: 16 }}>
|
||||
<Button
|
||||
variant={isJoined ? 'default' : 'primary'}
|
||||
onClick={() => setIsJoined(!isJoined)}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
{isJoined ? '✓ Inscrit' : 'Participer'}
|
||||
</Button>
|
||||
<Button onClick={() => navigate('invite')}>Inviter</Button>
|
||||
</div>
|
||||
|
||||
{isJoined && (
|
||||
<Button
|
||||
onClick={() => navigate('meeting-points')}
|
||||
style={{ width: '100%', marginBottom: 16 }}
|
||||
>
|
||||
📍 Points de rencontre
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Host */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 16 }}>
|
||||
<Avatar initials="RC" />
|
||||
<div>
|
||||
<Text className="user-content" style={{ margin: 0, fontWeight: 'bold' }}>Reconnexion</Text>
|
||||
<Text style={{ margin: 0, fontSize: 14, color: 'var(--sketch-gray)' }}>Relayé par</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Description */}
|
||||
<Text style={{ fontWeight: 'bold', marginBottom: 8 }}>À propos</Text>
|
||||
<Text className="user-content" style={{ lineHeight: 1.6 }}>
|
||||
Une semaine collaborative pour se rencontrer, co-créer et faire avancer le projet de Réseau Social Universel.
|
||||
Au programme : sessions plénières en intelligence collective, ateliers en forum ouvert, et randonnée
|
||||
au Cirque de Navacelles. Hébergement sur place au Revel, écolieu à Rogues dans le Gard.
|
||||
</Text>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Attendees */}
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
|
||||
<Text style={{ fontWeight: 'bold', margin: 0 }}>Participants (24)</Text>
|
||||
<Text
|
||||
style={{ margin: 0, fontSize: 14, cursor: 'pointer' }}
|
||||
onClick={() => navigate('participants-list')}
|
||||
>
|
||||
Voir tout →
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 12 }}>
|
||||
{knownAttendees.map((a, i) => (
|
||||
<div
|
||||
key={i}
|
||||
style={{ textAlign: 'center', cursor: 'pointer' }}
|
||||
onClick={() => navigate('user-profile')}
|
||||
>
|
||||
<Avatar initials={a.initials} size="sm" />
|
||||
<Text className="user-content" style={{ margin: '4px 0 0 0', fontSize: 12 }}>{a.name}</Text>
|
||||
</div>
|
||||
))}
|
||||
<div
|
||||
style={{ textAlign: 'center', cursor: 'pointer' }}
|
||||
onClick={() => navigate('participants-list')}
|
||||
>
|
||||
<div style={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: '50%',
|
||||
background: 'var(--sketch-light-gray)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontSize: 12,
|
||||
}}>
|
||||
+{unknownCount}
|
||||
</div>
|
||||
<Text style={{ margin: '4px 0 0 0', fontSize: 12, color: 'var(--sketch-gray)' }}>inconnus</Text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Header, Input, Card, Text, Badge, NavBar } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
function EventCard({ title, date, location, distance, attendees, onClick }: {
|
||||
title: string;
|
||||
date: string;
|
||||
location: string;
|
||||
distance: number;
|
||||
attendees: number;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
return (
|
||||
<Card onClick={onClick} style={{ marginBottom: 12 }}>
|
||||
<Text className="user-content" style={{ margin: 0, fontWeight: 'bold' }}>{title}</Text>
|
||||
<Text style={{ margin: '4px 0', fontSize: 14 }}>
|
||||
📅 <span className="user-content">{date}</span>
|
||||
</Text>
|
||||
<Text style={{ margin: '0 0 8px 0', fontSize: 14 }}>
|
||||
📍 <span className="user-content">{location}</span>
|
||||
<span style={{ color: 'var(--sketch-gray)' }}> · {distance} km</span>
|
||||
</Text>
|
||||
<Badge>{attendees} inscrits</Badge>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export function EventsScreen({ navigate }: ScreenProps) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Découvrir"
|
||||
left={<span onClick={() => navigate('home')} style={{ cursor: 'pointer' }}>←</span>}
|
||||
/>
|
||||
|
||||
{/* Search */}
|
||||
<div style={{ padding: '12px 16px', borderBottom: '1px solid var(--sketch-light-gray)' }}>
|
||||
<Input placeholder="Rechercher un événement..." />
|
||||
</div>
|
||||
|
||||
{/* Filter tabs */}
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
gap: 8,
|
||||
padding: '12px 16px',
|
||||
borderBottom: '1px solid var(--sketch-light-gray)',
|
||||
}}>
|
||||
<Badge style={{ background: 'var(--sketch-black)', color: 'var(--sketch-white)' }}>Tous</Badge>
|
||||
<Badge>Cette semaine</Badge>
|
||||
<Badge>Proches</Badge>
|
||||
<Badge>Amis</Badge>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, padding: 16, overflow: 'auto' }}>
|
||||
{/* Helper text */}
|
||||
<div style={{
|
||||
background: 'var(--sketch-light-gray)',
|
||||
padding: 12,
|
||||
borderRadius: 8,
|
||||
marginBottom: 16,
|
||||
}}>
|
||||
<Text style={{ margin: 0, fontSize: 13, color: 'var(--sketch-gray)', lineHeight: 1.5 }}>
|
||||
Événements relayés par vos contacts. Explorez, participez, et relayez
|
||||
à votre tour pour faire grandir votre réseau.
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<EventCard
|
||||
title="Résidence Reconnexion"
|
||||
date="Lun. 16 - Ven. 20 fév."
|
||||
location="Le Revel, Rogues (30)"
|
||||
distance={142}
|
||||
attendees={24}
|
||||
onClick={() => navigate('event-detail')}
|
||||
/>
|
||||
<EventCard
|
||||
title="Atelier low-tech"
|
||||
date="Sam. 8 fév. · 14h00"
|
||||
location="La Maison du Vélo, Lyon"
|
||||
distance={3}
|
||||
attendees={12}
|
||||
onClick={() => navigate('event-detail')}
|
||||
/>
|
||||
<EventCard
|
||||
title="Forum Ouvert Transition"
|
||||
date="Sam. 22 fév. · 9h00"
|
||||
location="Tiers-lieu L'Hermitage"
|
||||
distance={89}
|
||||
attendees={45}
|
||||
onClick={() => navigate('event-detail')}
|
||||
/>
|
||||
<EventCard
|
||||
title="Formation CNV"
|
||||
date="Sam. 1 mars · 9h30"
|
||||
location="MJC Montplaisir, Lyon"
|
||||
distance={5}
|
||||
attendees={16}
|
||||
onClick={() => navigate('event-detail')}
|
||||
/>
|
||||
<EventCard
|
||||
title="Rencontre des Colibris"
|
||||
date="Mer. 12 fév. · 19h00"
|
||||
location="La Maison de l'Environnement"
|
||||
distance={7}
|
||||
attendees={30}
|
||||
onClick={() => navigate('event-detail')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Bottom Nav */}
|
||||
<NavBar
|
||||
items={[
|
||||
{ icon: '⌂', label: 'Accueil', onClick: () => navigate('home') },
|
||||
{ icon: '◎', label: 'Découvrir', active: true },
|
||||
{ icon: '+', label: 'Relayer', onClick: () => navigate('create-event') },
|
||||
{ icon: '☺', label: 'Profil', onClick: () => navigate('profile') },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Header, Text, Avatar, Input, Button, Badge } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function FriendsListScreen({ navigate }: ScreenProps) {
|
||||
const [activeTab, setActiveTab] = useState<'friends' | 'public'>('friends');
|
||||
|
||||
const friends = [
|
||||
{ initials: 'JD', name: 'Jean Durand', username: '@jeandurand', events: 5, mutual: true },
|
||||
{ initials: 'AM', name: 'Alice Martin', username: '@alice', events: 12, mutual: true },
|
||||
{ initials: 'BM', name: 'Baptiste Morel', username: '@baptiste', events: 3, mutual: true },
|
||||
{ initials: 'CD', name: 'Camille Dubois', username: '@camille', events: 8, mutual: true },
|
||||
{ initials: 'DL', name: 'David Leroy', username: '@david', events: 2, mutual: true },
|
||||
{ initials: 'EG', name: 'Emma Girard', username: '@emma', events: 7, mutual: true },
|
||||
];
|
||||
|
||||
const publicProfiles = [
|
||||
{ initials: 'LB', name: 'Léa Bernard', username: '@leabernard', events: 45, role: 'Relayeuse' },
|
||||
{ initials: 'MR', name: 'Marc Richard', username: '@marcrichard', events: 67, role: 'Animateur' },
|
||||
{ initials: 'SF', name: 'Sophie Fontaine', username: '@sophief', events: 23, role: 'Créatrice' },
|
||||
{ initials: 'PG', name: 'Pierre Gagnon', username: '@pierreg', events: 89, role: 'Relayeur' },
|
||||
];
|
||||
|
||||
const displayedList = activeTab === 'friends' ? friends : publicProfiles;
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Mon réseau"
|
||||
left={<span onClick={() => navigate('profile')} style={{ cursor: 'pointer' }}>←</span>}
|
||||
/>
|
||||
|
||||
{/* Tabs */}
|
||||
<div style={{ display: 'flex', borderBottom: '2px solid var(--sketch-black)' }}>
|
||||
<button
|
||||
onClick={() => setActiveTab('friends')}
|
||||
style={{
|
||||
flex: 1,
|
||||
padding: '12px 16px',
|
||||
background: activeTab === 'friends' ? 'var(--sketch-light-gray)' : 'transparent',
|
||||
border: 'none',
|
||||
borderBottom: activeTab === 'friends' ? '3px solid var(--sketch-black)' : '3px solid transparent',
|
||||
fontFamily: 'var(--font-sketch)',
|
||||
fontSize: 14,
|
||||
fontWeight: activeTab === 'friends' ? 'bold' : 'normal',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
Mes amis ({friends.length})
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('public')}
|
||||
style={{
|
||||
flex: 1,
|
||||
padding: '12px 16px',
|
||||
background: activeTab === 'public' ? 'var(--sketch-light-gray)' : 'transparent',
|
||||
border: 'none',
|
||||
borderBottom: activeTab === 'public' ? '3px solid var(--sketch-black)' : '3px solid transparent',
|
||||
fontFamily: 'var(--font-sketch)',
|
||||
fontSize: 14,
|
||||
fontWeight: activeTab === 'public' ? 'bold' : 'normal',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
Profils publics
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Search bar */}
|
||||
<div style={{ padding: 16, borderBottom: '1px solid var(--sketch-light-gray)' }}>
|
||||
<Input placeholder="Rechercher..." />
|
||||
</div>
|
||||
|
||||
{/* List */}
|
||||
<div style={{ flex: 1, overflow: 'auto' }}>
|
||||
{displayedList.map((person, i) => (
|
||||
<div
|
||||
key={i}
|
||||
onClick={() => navigate('user-profile')}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
padding: '12px 16px',
|
||||
cursor: 'pointer',
|
||||
borderBottom: '1px solid var(--sketch-light-gray)',
|
||||
}}
|
||||
>
|
||||
<Avatar initials={person.initials} size="sm" />
|
||||
<div style={{ flex: 1 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<Text className="user-content" style={{ margin: 0, fontWeight: 'bold' }}>{person.name}</Text>
|
||||
{'role' in person && (
|
||||
<Badge>{person.role}</Badge>
|
||||
)}
|
||||
</div>
|
||||
<Text style={{ margin: 0, fontSize: 13 }}>
|
||||
<span className="user-content">{person.username}</span>
|
||||
<span style={{ color: 'var(--sketch-gray)' }}> · {person.events} événements</span>
|
||||
</Text>
|
||||
</div>
|
||||
<Text style={{ margin: 0, fontSize: 20, color: 'var(--sketch-gray)' }}>›</Text>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Add friend button */}
|
||||
{activeTab === 'friends' && (
|
||||
<div style={{ padding: 16, borderTop: '2px solid var(--sketch-black)' }}>
|
||||
<Button variant="primary" style={{ width: '100%' }}>
|
||||
+ Ajouter un ami
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Button, Title, Text, Card, NavBar, Badge } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
function EventCard({ title, date, location, distance, attendees, onClick }: { title: string; date: string; location: string; distance: number; attendees: number; onClick: () => void }) {
|
||||
return (
|
||||
<Card onClick={onClick} style={{ marginBottom: 12 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
|
||||
<div>
|
||||
<Text className="user-content" style={{ margin: 0, fontWeight: 'bold' }}>{title}</Text>
|
||||
<Text className="user-content" style={{ margin: '4px 0 0 0', fontSize: 14 }}>{date}</Text>
|
||||
<Text style={{ margin: '2px 0 0 0', fontSize: 14 }}>
|
||||
📍 <span className="user-content">{location}</span>
|
||||
<span style={{ color: 'var(--sketch-gray)' }}> · {distance} km</span>
|
||||
</Text>
|
||||
</div>
|
||||
<Badge>{attendees} inscrits</Badge>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export function HomeScreen({ navigate }: ScreenProps) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
{/* Header */}
|
||||
<div style={{ padding: '16px', borderBottom: '2px solid var(--sketch-black)' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Title style={{ margin: 0 }}>Festipod</Title>
|
||||
<span onClick={() => navigate('profile')} style={{ cursor: 'pointer', fontSize: 24 }}>☺</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, padding: 16, overflow: 'auto' }}>
|
||||
{/* Helper text */}
|
||||
<div style={{
|
||||
background: 'var(--sketch-light-gray)',
|
||||
padding: 12,
|
||||
borderRadius: 8,
|
||||
marginBottom: 16,
|
||||
}}>
|
||||
<Text style={{ margin: 0, fontSize: 13, color: 'var(--sketch-gray)', lineHeight: 1.5 }}>
|
||||
Voici les événements auxquels vous participez. Retrouvez les infos pratiques
|
||||
et les autres participants.
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
|
||||
<Text style={{ margin: 0, fontWeight: 'bold' }}>Mes événements à venir</Text>
|
||||
<Text
|
||||
style={{ margin: 0, fontSize: 14, cursor: 'pointer' }}
|
||||
onClick={() => navigate('events')}
|
||||
>
|
||||
Voir tout →
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<EventCard
|
||||
title="Résidence Reconnexion"
|
||||
date="Lun. 16 - Ven. 20 fév."
|
||||
location="Le Revel, Rogues (30)"
|
||||
distance={142}
|
||||
attendees={24}
|
||||
onClick={() => navigate('event-detail')}
|
||||
/>
|
||||
<EventCard
|
||||
title="Atelier low-tech"
|
||||
date="Sam. 8 fév. · 14h00"
|
||||
location="La Maison du Vélo, Lyon"
|
||||
distance={3}
|
||||
attendees={12}
|
||||
onClick={() => navigate('event-detail')}
|
||||
/>
|
||||
<EventCard
|
||||
title="Forum Ouvert Transition"
|
||||
date="Sam. 22 fév. · 9h00"
|
||||
location="Tiers-lieu L'Hermitage"
|
||||
distance={89}
|
||||
attendees={45}
|
||||
onClick={() => navigate('event-detail')}
|
||||
/>
|
||||
|
||||
<div style={{ marginTop: 24 }}>
|
||||
<Button variant="primary" onClick={() => navigate('create-event')} style={{ width: '100%' }}>
|
||||
+ Relayer un événement
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Nav */}
|
||||
<NavBar
|
||||
items={[
|
||||
{ icon: '⌂', label: 'Accueil', active: true },
|
||||
{ icon: '◎', label: 'Découvrir', onClick: () => navigate('events') },
|
||||
{ icon: '+', label: 'Relayer', onClick: () => navigate('create-event') },
|
||||
{ icon: '☺', label: 'Profil', onClick: () => navigate('profile') },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Header, Input, Text, Avatar, Checkbox, Button } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
interface Friend {
|
||||
id: string;
|
||||
name: string;
|
||||
initials: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
const friends: Friend[] = [
|
||||
{ id: '1', name: 'Alice Martin', initials: 'AM', username: '@alice' },
|
||||
{ id: '2', name: 'Baptiste Morel', initials: 'BM', username: '@baptiste' },
|
||||
{ id: '3', name: 'Camille Dubois', initials: 'CD', username: '@camille' },
|
||||
{ id: '4', name: 'David Leroy', initials: 'DL', username: '@david' },
|
||||
{ id: '5', name: 'Emma Bernard', initials: 'EB', username: '@emma' },
|
||||
{ id: '6', name: 'François Petit', initials: 'FP', username: '@francois' },
|
||||
];
|
||||
|
||||
export function InviteScreen({ navigate }: ScreenProps) {
|
||||
const [selected, setSelected] = useState<Set<string>>(new Set());
|
||||
|
||||
const toggleFriend = (id: string) => {
|
||||
const newSelected = new Set(selected);
|
||||
if (newSelected.has(id)) {
|
||||
newSelected.delete(id);
|
||||
} else {
|
||||
newSelected.add(id);
|
||||
}
|
||||
setSelected(newSelected);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Inviter des amis"
|
||||
left={<span onClick={() => navigate('event-detail')} style={{ cursor: 'pointer' }}>←</span>}
|
||||
/>
|
||||
|
||||
{/* Search */}
|
||||
<div style={{ padding: '12px 16px', borderBottom: '1px solid var(--sketch-light-gray)' }}>
|
||||
<Input placeholder="Rechercher un ami..." />
|
||||
</div>
|
||||
|
||||
{/* Selected count */}
|
||||
{selected.size > 0 && (
|
||||
<div style={{
|
||||
padding: '8px 16px',
|
||||
background: 'var(--sketch-light-gray)',
|
||||
fontSize: 14,
|
||||
fontFamily: 'var(--font-sketch)',
|
||||
}}>
|
||||
{selected.size} ami{selected.size > 1 ? 's' : ''} sélectionné{selected.size > 1 ? 's' : ''}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Friends list */}
|
||||
<div style={{ flex: 1, overflow: 'auto' }}>
|
||||
{friends.map((friend) => (
|
||||
<div
|
||||
key={friend.id}
|
||||
onClick={() => toggleFriend(friend.id)}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: '12px 16px',
|
||||
borderBottom: '1px solid var(--sketch-light-gray)',
|
||||
cursor: 'pointer',
|
||||
background: selected.has(friend.id) ? 'var(--sketch-light-gray)' : 'transparent',
|
||||
}}
|
||||
>
|
||||
<Avatar initials={friend.initials} size="sm" />
|
||||
<div style={{ flex: 1, marginLeft: 12 }}>
|
||||
<Text className="user-content" style={{ margin: 0, fontWeight: 'bold' }}>{friend.name}</Text>
|
||||
<Text className="user-content" style={{ margin: 0, fontSize: 14 }}>
|
||||
{friend.username}
|
||||
</Text>
|
||||
</div>
|
||||
<Checkbox checked={selected.has(friend.id)} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div style={{ padding: 16, borderTop: '2px solid var(--sketch-black)' }}>
|
||||
<Button
|
||||
variant="primary"
|
||||
style={{ width: '100%' }}
|
||||
onClick={() => navigate('event-detail')}
|
||||
disabled={selected.size === 0}
|
||||
>
|
||||
Envoyer {selected.size > 0 ? `${selected.size} ` : ''}invitation{selected.size !== 1 ? 's' : ''}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Button, Input, Title, Text } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function LoginScreen({ navigate }: ScreenProps) {
|
||||
return (
|
||||
<div style={{ padding: 24, display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
|
||||
<Title style={{ textAlign: 'center', fontSize: 32, marginBottom: 8 }}>Festipod</Title>
|
||||
<Text style={{ textAlign: 'center', marginBottom: 32 }}>Créez et rejoignez des événements entre amis</Text>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
<div>
|
||||
<Text style={{ marginBottom: 4, fontSize: 14 }}>Email</Text>
|
||||
<Input type="email" placeholder="vous@exemple.com" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 4, fontSize: 14 }}>Mot de passe</Text>
|
||||
<Input type="password" placeholder="••••••••" />
|
||||
</div>
|
||||
|
||||
<Button variant="primary" onClick={() => navigate('home')}>
|
||||
Se connecter
|
||||
</Button>
|
||||
|
||||
<Text style={{ textAlign: 'center', fontSize: 14, color: 'var(--sketch-gray)' }}>
|
||||
Mot de passe oublié ?
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<Text style={{ textAlign: 'center', fontSize: 14, color: 'var(--sketch-gray)' }}>
|
||||
Pas encore de compte ? S'inscrire
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Header, Text, Button, Card, Avatar, Input, Divider } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function MeetingPointsScreen({ navigate }: ScreenProps) {
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
const meetingPoints = [
|
||||
{
|
||||
id: '1',
|
||||
location: 'Café de la Place',
|
||||
time: '30 min avant l\'événement',
|
||||
host: { initials: 'MD', name: 'Marie' },
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
location: 'Station de métro Bellecour',
|
||||
time: '15h30',
|
||||
host: { initials: 'JD', name: 'Jean' },
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Points de rencontre"
|
||||
left={<span onClick={() => navigate('event-detail')} style={{ cursor: 'pointer' }}>←</span>}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, overflow: 'auto', padding: 16 }}>
|
||||
<Text style={{ color: 'var(--sketch-gray)', marginBottom: 16 }}>
|
||||
Proposez un lieu de rendez-vous pour y aller ensemble !
|
||||
</Text>
|
||||
|
||||
{/* Existing meeting points */}
|
||||
{meetingPoints.map((mp) => (
|
||||
<Card key={mp.id} style={{ marginBottom: 12 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
|
||||
<Avatar initials={mp.host.initials} size="sm" />
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text className="user-content" style={{ margin: 0, fontWeight: 'bold' }}>{mp.location}</Text>
|
||||
<Text style={{ margin: '4px 0', fontSize: 14, color: 'var(--sketch-gray)' }}>
|
||||
<span className="user-content">{mp.time}</span> · Proposé par <span className="user-content">{mp.host.name}</span>
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Create new meeting point */}
|
||||
{!showForm ? (
|
||||
<Button variant="primary" style={{ width: '100%' }} onClick={() => setShowForm(true)}>
|
||||
+ Proposer un point de rencontre
|
||||
</Button>
|
||||
) : (
|
||||
<>
|
||||
<Text style={{ fontWeight: 'bold', marginBottom: 12 }}>Proposer un point de rencontre</Text>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Lieu</Text>
|
||||
<Input placeholder="Ex: Café de la Gare, Entrée du parc..." />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Heure</Text>
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<Button style={{ flex: 1 }}>30 min avant</Button>
|
||||
<Button variant="primary" style={{ flex: 1 }}>1h avant</Button>
|
||||
<Button style={{ flex: 1 }}>Personnalisé</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
|
||||
<Button style={{ flex: 1 }} onClick={() => setShowForm(false)}>Annuler</Button>
|
||||
<Button variant="primary" style={{ flex: 1 }}>
|
||||
Créer le point de rencontre
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Header, Avatar, Text, Input, Divider } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function ParticipantsListScreen({ navigate }: ScreenProps) {
|
||||
const participants = [
|
||||
{ initials: 'MD', name: 'Marie Dupont', username: '@mariedupont', known: true },
|
||||
{ initials: 'TM', name: 'Thomas Martin', username: '@thomas', known: true },
|
||||
{ known: false },
|
||||
{ known: false },
|
||||
{ known: false },
|
||||
{ known: false },
|
||||
{ known: false },
|
||||
{ known: false },
|
||||
{ known: false },
|
||||
{ known: false },
|
||||
{ known: false },
|
||||
{ known: false },
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Participants (12)"
|
||||
left={<span onClick={() => navigate('event-detail')} style={{ cursor: 'pointer' }}>←</span>}
|
||||
/>
|
||||
|
||||
{/* Search bar */}
|
||||
<div style={{ padding: 16, borderBottom: '1px solid var(--sketch-light-gray)' }}>
|
||||
<Input placeholder="Rechercher un participant..." />
|
||||
</div>
|
||||
|
||||
{/* Participants list */}
|
||||
<div style={{ flex: 1, overflow: 'auto' }}>
|
||||
{participants.map((p, i) => (
|
||||
<div
|
||||
key={i}
|
||||
onClick={p.known ? () => navigate('user-profile') : undefined}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
padding: '12px 16px',
|
||||
cursor: p.known ? 'pointer' : 'default',
|
||||
borderBottom: '1px solid var(--sketch-light-gray)',
|
||||
}}
|
||||
>
|
||||
<Avatar initials={p.known ? p.initials : '?'} size="sm" />
|
||||
<div style={{ flex: 1 }}>
|
||||
{p.known ? (
|
||||
<>
|
||||
<Text className="user-content" style={{ margin: 0, fontWeight: 'bold' }}>{p.name}</Text>
|
||||
<Text className="user-content" style={{ margin: 0, fontSize: 13 }}>
|
||||
{p.username}
|
||||
</Text>
|
||||
</>
|
||||
) : (
|
||||
<Text style={{ margin: 0, color: 'var(--sketch-gray)' }}>Participant inconnu</Text>
|
||||
)}
|
||||
</div>
|
||||
{p.known && <Text style={{ margin: 0, fontSize: 20, color: 'var(--sketch-gray)' }}>›</Text>}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Header, Avatar, Title, Text, Button, Card, Badge, Divider, NavBar } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function ProfileScreen({ navigate }: ScreenProps) {
|
||||
const upcomingEvents = [
|
||||
{ title: 'Résidence Reconnexion', date: '16-20 fév.' },
|
||||
{ title: 'Atelier low-tech', date: '8 fév.' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Mon profil"
|
||||
left={<span onClick={() => navigate('home')} style={{ cursor: 'pointer' }}>←</span>}
|
||||
right={<span onClick={() => navigate('settings')} style={{ cursor: 'pointer' }}>⚙</span>}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, overflow: 'auto' }}>
|
||||
{/* Profile header */}
|
||||
<div style={{ padding: 24, textAlign: 'center' }}>
|
||||
<Avatar initials="MD" size="lg" />
|
||||
<Title className="user-content" style={{ marginTop: 16, marginBottom: 4 }}>Marie Dupont</Title>
|
||||
<Text className="user-content" style={{ margin: 0 }}>@mariedupont</Text>
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'center', gap: 32, marginTop: 20 }}>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Text style={{ fontWeight: 'bold', margin: 0 }}>12</Text>
|
||||
<Text style={{ fontSize: 12, color: 'var(--sketch-gray)', margin: 0 }}>Événements</Text>
|
||||
</div>
|
||||
<div style={{ textAlign: 'center', cursor: 'pointer' }} onClick={() => navigate('friends-list')}>
|
||||
<Text style={{ fontWeight: 'bold', margin: 0 }}>48</Text>
|
||||
<Text style={{ fontSize: 12, color: 'var(--sketch-gray)', margin: 0 }}>Amis</Text>
|
||||
</div>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Text style={{ fontWeight: 'bold', margin: 0 }}>156</Text>
|
||||
<Text style={{ fontSize: 12, color: 'var(--sketch-gray)', margin: 0 }}>Participations</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 8, marginTop: 20, justifyContent: 'center' }}>
|
||||
<Button variant="primary" onClick={() => navigate('update-profile')}>Modifier le profil</Button>
|
||||
<Button onClick={() => navigate('share-profile')}>Partager</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Upcoming events */}
|
||||
<div style={{ padding: 16 }}>
|
||||
<Text style={{ fontWeight: 'bold', marginBottom: 12 }}>Mes événements à venir</Text>
|
||||
{upcomingEvents.map((event, i) => (
|
||||
<Card key={i} onClick={() => navigate('event-detail')} style={{ marginBottom: 12 }}>
|
||||
<Text className="user-content" style={{ margin: 0, fontWeight: 'bold' }}>{event.title}</Text>
|
||||
<Text className="user-content" style={{ margin: '4px 0 0 0', fontSize: 14 }}>
|
||||
{event.date}
|
||||
</Text>
|
||||
</Card>
|
||||
))}
|
||||
<Button style={{ width: '100%' }} onClick={() => navigate('events')}>
|
||||
Voir tous les événements
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Quick actions */}
|
||||
<div style={{ padding: '0 16px 16px' }}>
|
||||
<div
|
||||
className="sketchy-list-item"
|
||||
onClick={() => navigate('create-event')}
|
||||
>
|
||||
<span style={{ marginRight: 12 }}>+</span>
|
||||
<Text style={{ margin: 0 }}>Relayer un événement</Text>
|
||||
</div>
|
||||
<div className="sketchy-list-item" onClick={() => navigate('friends-list')}>
|
||||
<span style={{ marginRight: 12 }}>👥</span>
|
||||
<Text style={{ margin: 0 }}>Mes amis</Text>
|
||||
</div>
|
||||
<div className="sketchy-list-item">
|
||||
<span style={{ marginRight: 12 }}>📜</span>
|
||||
<Text style={{ margin: 0 }}>Événements passés</Text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Nav */}
|
||||
<NavBar
|
||||
items={[
|
||||
{ icon: '⌂', label: 'Accueil', onClick: () => navigate('home') },
|
||||
{ icon: '◎', label: 'Découvrir', onClick: () => navigate('events') },
|
||||
{ icon: '+', label: 'Relayer', onClick: () => navigate('create-event') },
|
||||
{ icon: '☺', label: 'Profil', active: true },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Header, Text, ListItem, Toggle, Divider, NavBar } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function SettingsScreen({ navigate }: ScreenProps) {
|
||||
const [notifications, setNotifications] = useState(true);
|
||||
const [darkMode, setDarkMode] = useState(false);
|
||||
const [location, setLocation] = useState(true);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Paramètres"
|
||||
left={<span onClick={() => navigate('home')} style={{ cursor: 'pointer' }}>←</span>}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, overflow: 'auto' }}>
|
||||
<Text style={{ padding: '16px 16px 8px', fontSize: 14, color: 'var(--sketch-gray)', margin: 0 }}>
|
||||
PRÉFÉRENCES
|
||||
</Text>
|
||||
|
||||
<ListItem>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text style={{ margin: 0 }}>Notifications</Text>
|
||||
<Text style={{ margin: 0, fontSize: 12, color: 'var(--sketch-gray)' }}>
|
||||
Recevoir les invitations par e-mail
|
||||
</Text>
|
||||
</div>
|
||||
<Toggle checked={notifications} onChange={setNotifications} />
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text style={{ margin: 0 }}>Mode sombre</Text>
|
||||
<Text style={{ margin: 0, fontSize: 12, color: 'var(--sketch-gray)' }}>
|
||||
Activer le thème sombre
|
||||
</Text>
|
||||
</div>
|
||||
<Toggle checked={darkMode} onChange={setDarkMode} />
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text style={{ margin: 0 }}>Localisation</Text>
|
||||
<Text style={{ margin: 0, fontSize: 12, color: 'var(--sketch-gray)' }}>
|
||||
Autoriser l'accès à la position
|
||||
</Text>
|
||||
</div>
|
||||
<Toggle checked={location} onChange={setLocation} />
|
||||
</ListItem>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Text style={{ padding: '16px 16px 8px', fontSize: 14, color: 'var(--sketch-gray)', margin: 0 }}>
|
||||
COMPTE
|
||||
</Text>
|
||||
|
||||
<ListItem onClick={() => navigate('profile')}>
|
||||
<Text style={{ margin: 0, flex: 1 }}>Modifier le profil</Text>
|
||||
<span>→</span>
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<Text style={{ margin: 0, flex: 1 }}>Changer le mot de passe</Text>
|
||||
<span>→</span>
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<Text style={{ margin: 0, flex: 1 }}>Confidentialité</Text>
|
||||
<span>→</span>
|
||||
</ListItem>
|
||||
|
||||
<Divider />
|
||||
|
||||
<ListItem onClick={() => navigate('login')}>
|
||||
<Text style={{ margin: 0, color: '#c00' }}>Se déconnecter</Text>
|
||||
</ListItem>
|
||||
</div>
|
||||
|
||||
{/* Bottom Nav */}
|
||||
<NavBar
|
||||
items={[
|
||||
{ icon: '⌂', label: 'Accueil', onClick: () => navigate('home') },
|
||||
{ icon: '◎', label: 'Découvrir', onClick: () => navigate('events') },
|
||||
{ icon: '+', label: 'Relayer', onClick: () => navigate('create-event') },
|
||||
{ icon: '☺', label: 'Profil', onClick: () => navigate('profile') },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Header, Text, Button, Card, Divider, Avatar } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function ShareProfileScreen({ navigate }: ScreenProps) {
|
||||
const profileLink = 'festipod.app/u/mariedupont';
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Partager mon profil"
|
||||
left={<span onClick={() => navigate('profile')} style={{ cursor: 'pointer' }}>←</span>}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, overflow: 'auto', padding: 16 }}>
|
||||
{/* QR Code */}
|
||||
<Card style={{ textAlign: 'center', padding: 24 }}>
|
||||
<div style={{
|
||||
width: 180,
|
||||
height: 180,
|
||||
margin: '0 auto 16px',
|
||||
border: '3px solid var(--sketch-black)',
|
||||
borderRadius: 12,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
background: 'var(--sketch-white)',
|
||||
position: 'relative',
|
||||
}}>
|
||||
{/* Simulated QR code pattern */}
|
||||
<div style={{
|
||||
width: 150,
|
||||
height: 150,
|
||||
background: `
|
||||
linear-gradient(90deg, var(--sketch-black) 10%, transparent 10%, transparent 20%, var(--sketch-black) 20%, var(--sketch-black) 30%, transparent 30%, transparent 40%, var(--sketch-black) 40%, var(--sketch-black) 50%, transparent 50%, transparent 60%, var(--sketch-black) 60%, var(--sketch-black) 70%, transparent 70%, transparent 80%, var(--sketch-black) 80%, var(--sketch-black) 90%, transparent 90%),
|
||||
linear-gradient(var(--sketch-black) 10%, transparent 10%, transparent 20%, var(--sketch-black) 20%, var(--sketch-black) 30%, transparent 30%, transparent 40%, var(--sketch-black) 40%, var(--sketch-black) 50%, transparent 50%, transparent 60%, var(--sketch-black) 60%, var(--sketch-black) 70%, transparent 70%, transparent 80%, var(--sketch-black) 80%, var(--sketch-black) 90%, transparent 90%)
|
||||
`,
|
||||
backgroundSize: '15px 15px',
|
||||
opacity: 0.8,
|
||||
}} />
|
||||
{/* Center avatar */}
|
||||
<div style={{
|
||||
position: 'absolute',
|
||||
background: 'var(--sketch-white)',
|
||||
padding: 4,
|
||||
borderRadius: '50%',
|
||||
}}>
|
||||
<Avatar initials="MD" size="sm" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Text className="user-content" style={{ fontWeight: 'bold', margin: '0 0 4px 0' }}>Marie Dupont</Text>
|
||||
<Text style={{ color: 'var(--sketch-gray)', margin: 0, fontSize: 14 }}>
|
||||
Scannez pour me retrouver sur Festipod
|
||||
</Text>
|
||||
</Card>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Link section */}
|
||||
<Text style={{ fontWeight: 'bold', marginBottom: 12 }}>Mon lien de profil</Text>
|
||||
<Card style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<Text style={{
|
||||
margin: 0,
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}>
|
||||
{profileLink}
|
||||
</Text>
|
||||
<Button style={{ flexShrink: 0, padding: '8px 10px' }} title="Copier le lien">📋</Button>
|
||||
<Button variant="primary" style={{ flexShrink: 0, padding: '8px 10px' }} title="Partager">↗</Button>
|
||||
</Card>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Stats */}
|
||||
<Text style={{ fontWeight: 'bold', marginBottom: 12 }}>Statistiques de parrainage</Text>
|
||||
<Card>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-around', textAlign: 'center' }}>
|
||||
<div>
|
||||
<Text style={{ fontWeight: 'bold', fontSize: 24, margin: 0, color: 'var(--sketch-black)' }}>12</Text>
|
||||
<Text style={{ fontSize: 12, color: 'var(--sketch-gray)', margin: 0 }}>
|
||||
Personnes parrainées
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text style={{ fontWeight: 'bold', fontSize: 24, margin: 0, color: 'var(--sketch-black)' }}>47</Text>
|
||||
<Text style={{ fontSize: 12, color: 'var(--sketch-gray)', margin: 0 }}>
|
||||
Scans du QR code
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Header, Text, Input, Button, Placeholder } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function UpdateEventScreen({ navigate }: ScreenProps) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Modifier l'événement"
|
||||
left={<span onClick={() => navigate('event-detail')} style={{ cursor: 'pointer' }}>✕</span>}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, padding: 16, overflow: 'auto' }}>
|
||||
{/* Cover image upload */}
|
||||
<Placeholder
|
||||
height={140}
|
||||
label="Photo de couverture"
|
||||
style={{ marginBottom: 20, cursor: 'pointer' }}
|
||||
/>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Nom de l'événement *</Text>
|
||||
<Input defaultValue="Résidence Reconnexion" />
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 12 }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Date de début *</Text>
|
||||
<Input type="date" defaultValue="2026-02-16" />
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Date de fin</Text>
|
||||
<Input type="date" defaultValue="2026-02-20" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 12 }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Heure de début *</Text>
|
||||
<Input type="time" defaultValue="09:00" />
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Heure de fin</Text>
|
||||
<Input type="time" defaultValue="18:00" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Lieu *</Text>
|
||||
<Input defaultValue="Le Revel, Rogues (30)" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Description</Text>
|
||||
<textarea
|
||||
className="sketchy-input"
|
||||
defaultValue="Une semaine collaborative pour se rencontrer, co-créer et faire avancer le projet de Réseau Social Universel. Au programme : sessions plénières en intelligence collective, ateliers en forum ouvert, et randonnée au Cirque de Navacelles."
|
||||
rows={4}
|
||||
style={{ resize: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Thématique *</Text>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
|
||||
{[
|
||||
{ id: 'culture', label: 'Culture', emoji: '🎭' },
|
||||
{ id: 'sport', label: 'Sport', emoji: '⚽' },
|
||||
{ id: 'nature', label: 'Nature', emoji: '🌿' },
|
||||
{ id: 'social', label: 'Social', emoji: '👥' },
|
||||
{ id: 'food', label: 'Gastronomie', emoji: '🍽️' },
|
||||
{ id: 'music', label: 'Musique', emoji: '🎵' },
|
||||
{ id: 'tech', label: 'Tech', emoji: '💻' },
|
||||
{ id: 'other', label: 'Autre', emoji: '✨' },
|
||||
].map((theme) => (
|
||||
<Button
|
||||
key={theme.id}
|
||||
variant={theme.id === 'social' ? 'primary' : 'default'}
|
||||
style={{ fontSize: 13 }}
|
||||
>
|
||||
{theme.emoji} {theme.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div style={{ padding: 16, borderTop: '2px solid var(--sketch-black)' }}>
|
||||
<Button
|
||||
variant="primary"
|
||||
style={{ width: '100%' }}
|
||||
onClick={() => navigate('event-detail')}
|
||||
>
|
||||
Enregistrer les modifications
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Header, Text, Input, Button, Avatar } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function UpdateProfileScreen({ navigate }: ScreenProps) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Modifier le profil"
|
||||
left={<span onClick={() => navigate('profile')} style={{ cursor: 'pointer' }}>✕</span>}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, padding: 16, overflow: 'auto' }}>
|
||||
{/* Photo */}
|
||||
<div style={{ textAlign: 'center', marginBottom: 24 }}>
|
||||
<Avatar initials="MD" size="lg" />
|
||||
<Button style={{ marginTop: 12 }}>
|
||||
Changer la photo
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Prénom *</Text>
|
||||
<Input defaultValue="Marie" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Nom *</Text>
|
||||
<Input defaultValue="Dupont" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Pseudo</Text>
|
||||
<Input defaultValue="@mariedupont" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Localisation</Text>
|
||||
<Input defaultValue="Lyon, France" placeholder="Ville, Pays" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text style={{ marginBottom: 6, fontSize: 14 }}>Bio</Text>
|
||||
<textarea
|
||||
className="sketchy-input"
|
||||
defaultValue="Passionnée de transition écologique et de rencontres humaines."
|
||||
rows={3}
|
||||
style={{ resize: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div style={{ padding: 16, borderTop: '2px solid var(--sketch-black)' }}>
|
||||
<Button
|
||||
variant="primary"
|
||||
style={{ width: '100%' }}
|
||||
onClick={() => navigate('profile')}
|
||||
>
|
||||
Enregistrer
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Header, Avatar, Title, Text, Button, Card, Badge, Divider } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function UserProfileScreen({ navigate }: ScreenProps) {
|
||||
const upcomingEvents = [
|
||||
{ title: 'Résidence Reconnexion', date: '16-20 fév.', location: 'Le Revel, Rogues (30)', distance: 142, common: true },
|
||||
{ title: 'Atelier permaculture', date: '28 fév.', location: 'Ferme des Music, Vénissieux', distance: 12, common: false },
|
||||
];
|
||||
|
||||
const pastEvents = [
|
||||
{ title: 'Forum Ouvert Transition', date: '22 jan.', location: 'Tiers-lieu L\'Hermitage', distance: 89, common: true },
|
||||
{ title: 'Rencontre des Colibris', date: '12 jan.', location: 'La Maison de l\'Environnement', distance: 7, common: true },
|
||||
{ title: 'Formation CNV', date: '8 jan.', location: 'MJC Montplaisir, Lyon', distance: 5, common: false },
|
||||
{ title: 'Café des possibles', date: '15 déc.', location: 'Café de la Mairie, Lyon 3', distance: 2, common: false },
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<Header
|
||||
title="Profil"
|
||||
left={<span onClick={() => navigate('event-detail')} style={{ cursor: 'pointer' }}>←</span>}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, overflow: 'auto' }}>
|
||||
{/* User profile header */}
|
||||
<div style={{ padding: 24, textAlign: 'center' }}>
|
||||
<Avatar initials="JD" size="lg" />
|
||||
<Title className="user-content" style={{ marginTop: 16, marginBottom: 4 }}>Jean Durand</Title>
|
||||
<Text className="user-content" style={{ margin: 0 }}>@jeandurand</Text>
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'center', gap: 32, marginTop: 20 }}>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Text style={{ fontWeight: 'bold', margin: 0 }}>8</Text>
|
||||
<Text style={{ fontSize: 12, color: 'var(--sketch-gray)', margin: 0 }}>Événements</Text>
|
||||
</div>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Text style={{ fontWeight: 'bold', margin: 0 }}>23</Text>
|
||||
<Text style={{ fontSize: 12, color: 'var(--sketch-gray)', margin: 0 }}>Contacts</Text>
|
||||
</div>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Text style={{ fontWeight: 'bold', margin: 0 }}>42</Text>
|
||||
<Text style={{ fontSize: 12, color: 'var(--sketch-gray)', margin: 0 }}>Participations</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 8, marginTop: 20, justifyContent: 'center' }}>
|
||||
<Button variant="primary">Ajouter au réseau</Button>
|
||||
<Button>Contacter</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Upcoming events */}
|
||||
<div style={{ padding: 16 }}>
|
||||
<Text style={{ fontWeight: 'bold', marginBottom: 12 }}>Événements à venir</Text>
|
||||
|
||||
{upcomingEvents.map((event, i) => (
|
||||
<Card key={i} onClick={() => navigate('event-detail')} style={{ marginBottom: 12 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
|
||||
<div>
|
||||
<Text className="user-content" style={{ margin: 0, fontWeight: 'bold' }}>{event.title}</Text>
|
||||
<Text className="user-content" style={{ margin: '4px 0 0 0', fontSize: 14 }}>
|
||||
{event.date}
|
||||
</Text>
|
||||
<Text style={{ margin: '2px 0 0 0', fontSize: 14 }}>
|
||||
📍 <span className="user-content">{event.location}</span>
|
||||
<span style={{ color: 'var(--sketch-gray)' }}> · {event.distance} km</span>
|
||||
</Text>
|
||||
</div>
|
||||
{event.common && <Badge>moi aussi</Badge>}
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Past events */}
|
||||
<div style={{ padding: 16 }}>
|
||||
<Text style={{ fontWeight: 'bold', marginBottom: 12 }}>Événements passés</Text>
|
||||
|
||||
{pastEvents.map((event, i) => (
|
||||
<Card key={i} onClick={() => navigate('event-detail')} style={{ marginBottom: 12 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
|
||||
<div>
|
||||
<Text className="user-content" style={{ margin: 0, fontWeight: 'bold' }}>{event.title}</Text>
|
||||
<Text className="user-content" style={{ margin: '4px 0 0 0', fontSize: 14 }}>
|
||||
{event.date}
|
||||
</Text>
|
||||
<Text style={{ margin: '2px 0 0 0', fontSize: 14 }}>
|
||||
📍 <span className="user-content">{event.location}</span>
|
||||
<span style={{ color: 'var(--sketch-gray)' }}> · {event.distance} km</span>
|
||||
</Text>
|
||||
</div>
|
||||
{event.common && <Badge>moi aussi</Badge>}
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Contact form section */}
|
||||
<div style={{ padding: 16 }}>
|
||||
<Text style={{ fontWeight: 'bold', marginBottom: 12 }}>Envoyer un message</Text>
|
||||
<div style={{
|
||||
border: '2px solid var(--sketch-black)',
|
||||
borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px',
|
||||
padding: 12,
|
||||
minHeight: 80,
|
||||
fontFamily: 'var(--font-sketch)',
|
||||
fontSize: 14,
|
||||
color: 'var(--sketch-gray)',
|
||||
}}>
|
||||
Écrivez votre message ici...
|
||||
</div>
|
||||
<Button variant="primary" style={{ width: '100%', marginTop: 12 }}>
|
||||
Envoyer
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Button, Title, Text } from '../components/sketchy';
|
||||
import type { ScreenProps } from './index';
|
||||
|
||||
export function WelcomeScreen({ navigate }: ScreenProps) {
|
||||
return (
|
||||
<div style={{ padding: 24, display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
|
||||
<Title style={{ textAlign: 'center', fontSize: 32, marginBottom: 24 }}>Festipod</Title>
|
||||
|
||||
<Text style={{ textAlign: 'center', fontSize: 18, marginBottom: 32, lineHeight: 1.5 }}>
|
||||
Découvrez des événements près de chez vous, relayés par des gens de confiance.
|
||||
</Text>
|
||||
|
||||
<div style={{
|
||||
background: 'var(--sketch-light-gray)',
|
||||
padding: 16,
|
||||
borderRadius: 8,
|
||||
marginBottom: 24,
|
||||
}}>
|
||||
<Text style={{ margin: 0, fontSize: 14, lineHeight: 1.6, color: 'var(--sketch-gray)' }}>
|
||||
Festipod est un projet collaboratif en construction. Nous croyons qu'on découvre
|
||||
les meilleurs événements grâce au bouche-à-oreille, pas via des algorithmes.
|
||||
Rejoignez les premiers utilisateurs et aidez-nous à créer une alternative
|
||||
humaine aux réseaux sociaux traditionnels.
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 24 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||
<span style={{ fontSize: 20 }}>🎪</span>
|
||||
<Text style={{ margin: 0, fontSize: 14 }}>Relayez des événements à votre réseau</Text>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||
<span style={{ fontSize: 20 }}>🤝</span>
|
||||
<Text style={{ margin: 0, fontSize: 14 }}>Rencontrez des personnes partageant vos centres d'intérêt</Text>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||
<span style={{ fontSize: 20 }}>🔒</span>
|
||||
<Text style={{ margin: 0, fontSize: 14 }}>Vos données restent les vôtres</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button variant="primary" onClick={() => navigate('login')} style={{ marginBottom: 12 }}>
|
||||
Rejoindre la communauté
|
||||
</Button>
|
||||
|
||||
<Text style={{ textAlign: 'center', fontSize: 13, color: 'var(--sketch-gray)' }}>
|
||||
Déjà membre ? Se connecter
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<Text style={{ textAlign: 'center', fontSize: 12, color: 'var(--sketch-gray)' }}>
|
||||
Version beta - 127 membres actifs
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+24
-16
@@ -1,20 +1,28 @@
|
||||
import React from 'react';
|
||||
import { HomeScreen } from './HomeScreen';
|
||||
import { LoginScreen } from './LoginScreen';
|
||||
import { ProfileScreen } from './ProfileScreen';
|
||||
import { SettingsScreen } from './SettingsScreen';
|
||||
import { UserProfileScreen } from './UserProfileScreen';
|
||||
import { EventsScreen } from './EventsScreen';
|
||||
import { EventDetailScreen } from './EventDetailScreen';
|
||||
import { CreateEventScreen } from './CreateEventScreen';
|
||||
import { UpdateEventScreen } from './UpdateEventScreen';
|
||||
import { InviteScreen } from './InviteScreen';
|
||||
import { ParticipantsListScreen } from './ParticipantsListScreen';
|
||||
import { MeetingPointsScreen } from './MeetingPointsScreen';
|
||||
import { FriendsListScreen } from './FriendsListScreen';
|
||||
import { ShareProfileScreen } from './ShareProfileScreen';
|
||||
import { UpdateProfileScreen } from './UpdateProfileScreen';
|
||||
import { WelcomeScreen } from './WelcomeScreen';
|
||||
|
||||
// Home module
|
||||
import { HomeScreen } from '../modules/home/screens/HomeScreen';
|
||||
import { SettingsScreen } from '../modules/home/screens/SettingsScreen';
|
||||
|
||||
// Auth module
|
||||
import { LoginScreen } from '../modules/auth/screens/LoginScreen';
|
||||
import { WelcomeScreen } from '../modules/auth/screens/WelcomeScreen';
|
||||
|
||||
// Event module
|
||||
import { EventsScreen } from '../modules/event/screens/EventsScreen';
|
||||
import { EventDetailScreen } from '../modules/event/screens/EventDetailScreen';
|
||||
import { CreateEventScreen } from '../modules/event/screens/CreateEventScreen';
|
||||
import { UpdateEventScreen } from '../modules/event/screens/UpdateEventScreen';
|
||||
import { InviteScreen } from '../modules/event/screens/InviteScreen';
|
||||
import { ParticipantsListScreen } from '../modules/event/screens/ParticipantsListScreen';
|
||||
import { MeetingPointsScreen } from '../modules/event/screens/MeetingPointsScreen';
|
||||
|
||||
// User module
|
||||
import { ProfileScreen } from '../modules/user/screens/ProfileScreen';
|
||||
import { UpdateProfileScreen } from '../modules/user/screens/UpdateProfileScreen';
|
||||
import { UserProfileScreen } from '../modules/user/screens/UserProfileScreen';
|
||||
import { FriendsListScreen } from '../modules/user/screens/FriendsListScreen';
|
||||
import { ShareProfileScreen } from '../modules/user/screens/ShareProfileScreen';
|
||||
|
||||
export interface Screen {
|
||||
id: string;
|
||||
|
||||
Reference in New Issue
Block a user