mise à jour README + enlève signup
This commit is contained in:
203
README.md
203
README.md
@@ -5,28 +5,68 @@ Une application web moderne pour gérer des campagnes de budgets participatifs,
|
|||||||
## 🚀 Technologies utilisées
|
## 🚀 Technologies utilisées
|
||||||
|
|
||||||
- **Frontend**: Next.js 14 avec TypeScript et App Router
|
- **Frontend**: Next.js 14 avec TypeScript et App Router
|
||||||
- **Styling**: Tailwind CSS + Headless UI
|
- **UI/UX**: Tailwind CSS + Shadcn/ui + Lucide React
|
||||||
- **Base de données**: PostgreSQL via Supabase
|
- **Base de données**: PostgreSQL via Supabase
|
||||||
- **Authentification**: Supabase Auth (prévu pour les futures versions)
|
- **Authentification**: Supabase Auth (implémenté)
|
||||||
- **Icons**: Heroicons
|
- **Déploiement**: Compatible Vercel, Netlify, etc.
|
||||||
|
|
||||||
## 📋 Fonctionnalités
|
## 📋 Fonctionnalités
|
||||||
|
|
||||||
### ✅ Implémentées
|
### ✅ Implémentées
|
||||||
- Page d'accueil avec présentation de l'application
|
|
||||||
- Interface d'administration pour gérer les campagnes
|
|
||||||
- Création de nouvelles campagnes avec tous les paramètres
|
|
||||||
- Ajout de propositions à une campagne
|
|
||||||
- Ajout de participants à une campagne
|
|
||||||
- Gestion des états de campagne (dépôt, vote, fermé)
|
|
||||||
- Interface moderne et responsive
|
|
||||||
|
|
||||||
### 🔄 À venir
|
#### 🏠 **Page d'accueil**
|
||||||
- Authentification des utilisateurs
|
- Présentation moderne de l'application
|
||||||
- Interface de vote pour les participants
|
- Design responsive avec sections Hero, Features et CTA
|
||||||
- Résultats et statistiques des votes
|
- Navigation vers l'espace administration sécurisé
|
||||||
- Notifications par email
|
|
||||||
- Gestion des permissions
|
#### 🔐 **Authentification**
|
||||||
|
- **Connexion sécurisée** : Authentification Supabase avec email/mot de passe
|
||||||
|
- **Protection des routes admin** : Toutes les pages d'administration sont protégées
|
||||||
|
- **Session persistante** : Maintien de la connexion entre les pages
|
||||||
|
- **Interface moderne** : Formulaire de connexion avec Shadcn/ui
|
||||||
|
|
||||||
|
#### 🛠️ **Administration complète**
|
||||||
|
- **Gestion des campagnes** : Création, modification, suppression
|
||||||
|
- **États de campagne** : Dépôt de propositions, vote, terminé
|
||||||
|
- **Statistiques en temps réel** : Nombre de propositions, participants, taux de participation
|
||||||
|
- **Recherche** : Filtrage des campagnes par titre ou description
|
||||||
|
- **Interface moderne** : Design Shadcn/ui avec cartes et badges
|
||||||
|
|
||||||
|
#### 📝 **Gestion des propositions**
|
||||||
|
- **Page dédiée** : Interface complète pour gérer les propositions par campagne
|
||||||
|
- **CRUD complet** : Création, lecture, modification, suppression
|
||||||
|
- **Informations détaillées** : Auteur, email, date de création
|
||||||
|
- **Interface moderne** : Cartes avec avatars et badges
|
||||||
|
|
||||||
|
#### 👥 **Gestion des participants**
|
||||||
|
- **Page dédiée** : Interface complète pour gérer les participants par campagne
|
||||||
|
- **Statuts de vote** : Indication visuelle des participants ayant voté
|
||||||
|
- **Liens de vote personnels** : URLs uniques pour chaque participant
|
||||||
|
- **Statistiques** : Taux de participation et budget total voté
|
||||||
|
|
||||||
|
#### 🌐 **Pages publiques**
|
||||||
|
- **Dépôt de propositions** : Interface publique pour soumettre des propositions
|
||||||
|
- URL unique et partageable
|
||||||
|
- Formulaire avec validation
|
||||||
|
- Informations d'auteur obligatoires
|
||||||
|
- **Vote public** : Interface de vote pour les participants
|
||||||
|
- Slider interactif pour les choix de budget
|
||||||
|
- Validation du budget total
|
||||||
|
- Sauvegarde des votes
|
||||||
|
|
||||||
|
#### 🎨 **Interface moderne**
|
||||||
|
- **Shadcn/ui** : Composants modernes et accessibles
|
||||||
|
- **Design responsive** : Adaptation mobile/desktop
|
||||||
|
- **Thème sombre** : Support du mode sombre
|
||||||
|
- **Animations** : Transitions fluides
|
||||||
|
- **Icônes Lucide** : Icônes modernes et cohérentes
|
||||||
|
|
||||||
|
### 🔄 Fonctionnalités avancées
|
||||||
|
- **URLs publiques** : Liens partageables pour le dépôt et le vote
|
||||||
|
- **Copie de liens** : Boutons pour copier les URLs dans le presse-papiers
|
||||||
|
- **Validation en temps réel** : Vérification des budgets lors du vote
|
||||||
|
- **Gestion d'erreurs** : Messages d'erreur informatifs
|
||||||
|
- **États de chargement** : Feedback visuel pendant les opérations
|
||||||
|
|
||||||
## 🛠️ Installation
|
## 🛠️ Installation
|
||||||
|
|
||||||
@@ -57,6 +97,11 @@ npm install
|
|||||||
1. Dans votre projet Supabase, allez dans l'éditeur SQL
|
1. Dans votre projet Supabase, allez dans l'éditeur SQL
|
||||||
2. Copiez et exécutez le contenu du fichier `supabase-schema.sql`
|
2. Copiez et exécutez le contenu du fichier `supabase-schema.sql`
|
||||||
|
|
||||||
|
#### Configurer l'authentification
|
||||||
|
1. Dans Supabase Dashboard > Authentication > Settings
|
||||||
|
2. Activez l'authentification par email
|
||||||
|
3. Créez un utilisateur admin via l'interface Supabase ou l'API
|
||||||
|
|
||||||
#### Configurer les variables d'environnement
|
#### Configurer les variables d'environnement
|
||||||
Créez un fichier `.env.local` à la racine du projet :
|
Créez un fichier `.env.local` à la racine du projet :
|
||||||
|
|
||||||
@@ -89,6 +134,9 @@ L'application sera accessible sur `http://localhost:3000`
|
|||||||
- `campaign_id`: Référence vers la campagne
|
- `campaign_id`: Référence vers la campagne
|
||||||
- `title`: Titre de la proposition
|
- `title`: Titre de la proposition
|
||||||
- `description`: Description détaillée
|
- `description`: Description détaillée
|
||||||
|
- `author_first_name`: Prénom de l'auteur
|
||||||
|
- `author_last_name`: Nom de l'auteur
|
||||||
|
- `author_email`: Email de l'auteur
|
||||||
- `created_at`: Date de création
|
- `created_at`: Date de création
|
||||||
|
|
||||||
### Table `participants`
|
### Table `participants`
|
||||||
@@ -99,49 +147,72 @@ L'application sera accessible sur `http://localhost:3000`
|
|||||||
- `email`: Adresse email
|
- `email`: Adresse email
|
||||||
- `created_at`: Date de création
|
- `created_at`: Date de création
|
||||||
|
|
||||||
|
### Table `votes`
|
||||||
|
- `id`: Identifiant unique (UUID)
|
||||||
|
- `participant_id`: Référence vers le participant
|
||||||
|
- `proposition_id`: Référence vers la proposition
|
||||||
|
- `amount`: Montant voté (en euros)
|
||||||
|
- `created_at`: Date de création
|
||||||
|
- `updated_at`: Date de dernière modification
|
||||||
|
|
||||||
## 🎨 Interface utilisateur
|
## 🎨 Interface utilisateur
|
||||||
|
|
||||||
### Page d'accueil
|
### Page d'accueil
|
||||||
- Présentation de l'application
|
- **Design moderne** : Hero section avec gradient et call-to-action
|
||||||
- Bouton d'accès à l'administration
|
- **Présentation claire** : Fonctionnalités principales expliquées
|
||||||
- Design moderne avec gradient et cartes informatives
|
- **Navigation intuitive** : Accès à l'administration sécurisée
|
||||||
|
|
||||||
### Page d'administration
|
### Espace d'administration (protégé)
|
||||||
- Liste des campagnes existantes
|
- **Dashboard complet** : Vue d'ensemble avec statistiques
|
||||||
- Bouton pour créer une nouvelle campagne
|
- **Gestion des campagnes** : CRUD complet avec interface moderne
|
||||||
- Actions rapides pour chaque campagne :
|
- **Navigation fluide** : Liens vers les pages de gestion détaillées
|
||||||
- Ajouter une proposition
|
- **Recherche** : Filtrage en temps réel des campagnes
|
||||||
- Ajouter un participant
|
|
||||||
- Indicateurs visuels pour les états des campagnes
|
|
||||||
|
|
||||||
### Modals
|
### Pages de gestion détaillées
|
||||||
- **Création de campagne** : Formulaire complet avec validation
|
- **Propositions** : Interface complète avec avatars et informations détaillées
|
||||||
- **Ajout de proposition** : Titre et description
|
- **Participants** : Gestion avec statuts de vote et liens personnels
|
||||||
- **Ajout de participant** : Informations personnelles
|
- **Statistiques** : Métriques en temps réel (participation, budget voté)
|
||||||
|
|
||||||
## 🔧 Développement
|
### Pages publiques
|
||||||
|
- **Dépôt de propositions** : Interface épurée et accessible
|
||||||
|
- **Vote** : Interface intuitive avec slider et validation
|
||||||
|
|
||||||
|
## 🔧 Architecture technique
|
||||||
|
|
||||||
### Structure des fichiers
|
### Structure des fichiers
|
||||||
```
|
```
|
||||||
src/
|
src/
|
||||||
├── app/ # Pages Next.js (App Router)
|
├── app/ # Pages Next.js (App Router)
|
||||||
│ ├── page.tsx # Page d'accueil
|
│ ├── page.tsx # Page d'accueil
|
||||||
│ └── admin/ # Pages d'administration
|
│ ├── admin/ # Pages d'administration (protégées)
|
||||||
├── components/ # Composants React réutilisables
|
│ │ ├── page.tsx # Dashboard principal
|
||||||
|
│ │ └── campaigns/[id]/ # Pages de gestion par campagne
|
||||||
|
│ └── campaigns/[id]/ # Pages publiques
|
||||||
|
│ ├── propose/ # Dépôt de propositions
|
||||||
|
│ └── vote/[participantId] # Vote public
|
||||||
|
├── components/ # Composants React
|
||||||
|
│ ├── ui/ # Composants Shadcn/ui
|
||||||
|
│ ├── AuthGuard.tsx # Protection des routes
|
||||||
|
│ ├── Navigation.tsx # Navigation principale
|
||||||
|
│ └── [Modals] # Modales de gestion
|
||||||
├── lib/ # Services et configuration
|
├── lib/ # Services et configuration
|
||||||
│ ├── supabase.ts # Configuration Supabase
|
│ ├── supabase.ts # Configuration Supabase
|
||||||
│ └── services.ts # Services de données
|
│ ├── services.ts # Services de données
|
||||||
|
│ └── utils.ts # Utilitaires
|
||||||
└── types/ # Types TypeScript
|
└── types/ # Types TypeScript
|
||||||
└── index.ts # Définitions des types
|
└── index.ts # Définitions des types
|
||||||
```
|
```
|
||||||
|
|
||||||
### Scripts disponibles
|
### Services de données
|
||||||
```bash
|
- **campaignService** : Gestion des campagnes et statistiques
|
||||||
npm run dev # Lancer en mode développement
|
- **propositionService** : CRUD des propositions
|
||||||
npm run build # Construire pour la production
|
- **participantService** : CRUD des participants
|
||||||
npm run start # Lancer en mode production
|
- **voteService** : Gestion des votes et statuts
|
||||||
npm run lint # Vérifier le code avec ESLint
|
|
||||||
```
|
### Authentification
|
||||||
|
- **AuthGuard** : Composant de protection des routes
|
||||||
|
- **Supabase Auth** : Authentification sécurisée
|
||||||
|
- **Session management** : Gestion des sessions utilisateur
|
||||||
|
|
||||||
## 🚀 Déploiement
|
## 🚀 Déploiement
|
||||||
|
|
||||||
@@ -150,6 +221,12 @@ npm run lint # Vérifier le code avec ESLint
|
|||||||
2. Configurez les variables d'environnement dans Vercel
|
2. Configurez les variables d'environnement dans Vercel
|
||||||
3. Déployez automatiquement
|
3. Déployez automatiquement
|
||||||
|
|
||||||
|
### Variables d'environnement de production
|
||||||
|
```env
|
||||||
|
NEXT_PUBLIC_SUPABASE_URL=votre_url_supabase_production
|
||||||
|
NEXT_PUBLIC_SUPABASE_ANON_KEY=votre_cle_anon_supabase_production
|
||||||
|
```
|
||||||
|
|
||||||
### Autres plateformes
|
### Autres plateformes
|
||||||
L'application peut être déployée sur n'importe quelle plateforme supportant Next.js :
|
L'application peut être déployée sur n'importe quelle plateforme supportant Next.js :
|
||||||
- Netlify
|
- Netlify
|
||||||
@@ -157,6 +234,48 @@ L'application peut être déployée sur n'importe quelle plateforme supportant N
|
|||||||
- DigitalOcean App Platform
|
- DigitalOcean App Platform
|
||||||
- AWS Amplify
|
- AWS Amplify
|
||||||
|
|
||||||
|
## 🔒 Sécurité
|
||||||
|
|
||||||
|
### Authentification
|
||||||
|
- **Routes protégées** : Toutes les pages admin nécessitent une authentification
|
||||||
|
- **Session sécurisée** : Gestion des sessions via Supabase
|
||||||
|
- **Pas d'inscription publique** : Seuls les comptes pré-autorisés peuvent accéder
|
||||||
|
|
||||||
|
### Base de données
|
||||||
|
- **Row Level Security (RLS)** : Protection des données au niveau de la base
|
||||||
|
- **Validation côté serveur** : Vérification des données avant sauvegarde
|
||||||
|
- **URLs sécurisées** : Liens publics avec identifiants uniques
|
||||||
|
|
||||||
|
## 🎯 Workflow d'utilisation
|
||||||
|
|
||||||
|
### 1. Configuration initiale
|
||||||
|
1. Créer un compte Supabase
|
||||||
|
2. Configurer la base de données
|
||||||
|
3. Créer un utilisateur admin
|
||||||
|
4. Déployer l'application
|
||||||
|
|
||||||
|
### 2. Création d'une campagne
|
||||||
|
1. Se connecter à l'administration
|
||||||
|
2. Créer une nouvelle campagne
|
||||||
|
3. Définir le budget et les paliers
|
||||||
|
4. Passer en mode "Dépôt de propositions"
|
||||||
|
|
||||||
|
### 3. Collecte des propositions
|
||||||
|
1. Partager le lien public de dépôt
|
||||||
|
2. Les participants soumettent leurs propositions
|
||||||
|
3. Gérer les propositions via l'interface admin
|
||||||
|
|
||||||
|
### 4. Phase de vote
|
||||||
|
1. Ajouter les participants
|
||||||
|
2. Passer en mode "En cours de vote"
|
||||||
|
3. Partager les liens de vote personnels
|
||||||
|
4. Suivre la participation en temps réel
|
||||||
|
|
||||||
|
### 5. Résultats
|
||||||
|
1. Consulter les statistiques de vote
|
||||||
|
2. Analyser les résultats
|
||||||
|
3. Clôturer la campagne
|
||||||
|
|
||||||
## 🤝 Contribution
|
## 🤝 Contribution
|
||||||
|
|
||||||
1. Fork le projet
|
1. Fork le projet
|
||||||
@@ -179,3 +298,5 @@ Pour toute question ou problème :
|
|||||||
---
|
---
|
||||||
|
|
||||||
**Développé avec ❤️ pour faciliter la démocratie participative**
|
**Développé avec ❤️ pour faciliter la démocratie participative**
|
||||||
|
|
||||||
|
*Application complète et prête pour la production avec authentification, interface moderne et toutes les fonctionnalités de gestion de budgets participatifs.*
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ function AdminPageContent() {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-4">
|
{/* <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-4">
|
||||||
<div className="text-center p-3 bg-slate-50 dark:bg-slate-800 rounded-lg">
|
<div className="text-center p-3 bg-slate-50 dark:bg-slate-800 rounded-lg">
|
||||||
<p className="text-sm text-slate-600 dark:text-slate-300">Propositions</p>
|
<p className="text-sm text-slate-600 dark:text-slate-300">Propositions</p>
|
||||||
<p className="text-lg font-semibold text-slate-900 dark:text-slate-100">{campaign.stats.propositions}</p>
|
<p className="text-lg font-semibold text-slate-900 dark:text-slate-100">{campaign.stats.propositions}</p>
|
||||||
@@ -280,7 +280,7 @@ function AdminPageContent() {
|
|||||||
<p className="text-sm text-slate-600 dark:text-slate-300">Paliers</p>
|
<p className="text-sm text-slate-600 dark:text-slate-300">Paliers</p>
|
||||||
<p className="text-sm font-semibold text-slate-900 dark:text-slate-100">{getSpendingTiersDisplay(campaign.spending_tiers)}</p>
|
<p className="text-sm font-semibold text-slate-900 dark:text-slate-100">{getSpendingTiersDisplay(campaign.spending_tiers)}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
{/* Public URL for deposit campaigns */}
|
{/* Public URL for deposit campaigns */}
|
||||||
{campaign.status === 'deposit' && (
|
{campaign.status === 'deposit' && (
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ interface AuthGuardProps {
|
|||||||
export default function AuthGuard({ children }: AuthGuardProps) {
|
export default function AuthGuard({ children }: AuthGuardProps) {
|
||||||
const [user, setUser] = useState<User | null>(null);
|
const [user, setUser] = useState<User | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [authMode, setAuthMode] = useState<'signin' | 'signup'>('signin');
|
const [authMode] = useState<'signin'>('signin');
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [authLoading, setAuthLoading] = useState(false);
|
const [authLoading, setAuthLoading] = useState(false);
|
||||||
@@ -52,20 +52,11 @@ export default function AuthGuard({ children }: AuthGuardProps) {
|
|||||||
setMessage('');
|
setMessage('');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (authMode === 'signin') {
|
|
||||||
const { error } = await supabase.auth.signInWithPassword({
|
const { error } = await supabase.auth.signInWithPassword({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
});
|
});
|
||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
} else {
|
|
||||||
const { error } = await supabase.auth.signUp({
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
});
|
|
||||||
if (error) throw error;
|
|
||||||
setMessage('Vérifiez votre email pour confirmer votre inscription.');
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
setError(error.message);
|
setError(error.message);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -96,10 +87,7 @@ export default function AuthGuard({ children }: AuthGuardProps) {
|
|||||||
<CardHeader className="text-center">
|
<CardHeader className="text-center">
|
||||||
<CardTitle className="text-2xl">Administration</CardTitle>
|
<CardTitle className="text-2xl">Administration</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
{authMode === 'signin'
|
Connectez-vous pour accéder à l'administration
|
||||||
? 'Connectez-vous pour accéder à l\'administration'
|
|
||||||
: 'Créez un compte pour accéder à l\'administration'
|
|
||||||
}
|
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
@@ -153,26 +141,15 @@ export default function AuthGuard({ children }: AuthGuardProps) {
|
|||||||
{authLoading ? (
|
{authLoading ? (
|
||||||
<>
|
<>
|
||||||
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
||||||
{authMode === 'signin' ? 'Connexion...' : 'Inscription...'}
|
Connexion...
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
authMode === 'signin' ? 'Se connecter' : 'S\'inscrire'
|
'Se connecter'
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div className="mt-4 text-center">
|
|
||||||
<Button
|
|
||||||
variant="link"
|
|
||||||
onClick={() => setAuthMode(authMode === 'signin' ? 'signup' : 'signin')}
|
|
||||||
className="text-sm"
|
|
||||||
>
|
|
||||||
{authMode === 'signin'
|
|
||||||
? 'Pas de compte ? S\'inscrire'
|
|
||||||
: 'Déjà un compte ? Se connecter'
|
|
||||||
}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-4 text-center">
|
<div className="mt-4 text-center">
|
||||||
<Button variant="ghost" asChild className="text-sm">
|
<Button variant="ghost" asChild className="text-sm">
|
||||||
|
|||||||
Reference in New Issue
Block a user