feat: Implement Database Service and ViewModels for Messages and Support Requests
- Added DatabaseService to handle database operations for messages and support requests. - Created IDatabaseService interface to define the contract for database operations. - Developed ViewModels for Dashboard, Messages, and Support pages to manage data and commands. - Implemented XAML views for Dashboard, Messages, and Support, including data binding and UI elements. - Created SQL script for setting up the database schema and inserting test data.
This commit is contained in:
54
.gitignore
vendored
Normal file
54
.gitignore
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio cache/options directory
|
||||
.vs/
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/
|
||||
|
||||
# Rider
|
||||
.idea/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# MAUI Specific
|
||||
**/AppPackages/
|
||||
**/BundleArtifacts/
|
||||
**/Package.StoreAssociation.xml
|
||||
|
||||
# Configuration sensible - NE PAS COMMIT !
|
||||
# Décommentez si vous voulez ignorer votre configuration locale
|
||||
# **/Configuration/AppSettings.cs
|
||||
294
ARCHITECTURE.md
Normal file
294
ARCHITECTURE.md
Normal file
@@ -0,0 +1,294 @@
|
||||
# Architecture de TravelMate Admin
|
||||
|
||||
## 🏗️ Pattern MVVM (Model-View-ViewModel)
|
||||
|
||||
Cette application utilise strictement le pattern MVVM avec CommunityToolkit.Mvvm pour une séparation claire des responsabilités.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ VIEW │
|
||||
│ (XAML + Code-behind) │
|
||||
│ DashboardPage │ MessagesPage │ SupportPage │
|
||||
└─────────────┬───────────────────────────────────────────┘
|
||||
│ Data Binding
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ VIEWMODEL │
|
||||
│ (Business Logic + State) │
|
||||
│ DashboardVM │ MessagesVM │ SupportVM │
|
||||
└─────────────┬───────────────────────────────────────────┘
|
||||
│ Calls
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ SERVICE │
|
||||
│ (Data Access Layer) │
|
||||
│ DatabaseService │
|
||||
└─────────────┬───────────────────────────────────────────┘
|
||||
│ SQL Queries
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ DATABASE │
|
||||
│ MariaDB / MySQL │
|
||||
│ messages │ support_requests │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 📂 Structure des Dossiers
|
||||
|
||||
### `/Models`
|
||||
**Responsabilité** : Représentation des données métier
|
||||
|
||||
- `Message.cs` : Représente un message de demande
|
||||
- `SupportRequest.cs` : Représente une demande support
|
||||
|
||||
**Caractéristiques** :
|
||||
- POCOs (Plain Old CLR Objects)
|
||||
- Propriétés avec getters/setters
|
||||
- Propriétés calculées (FullName, StatusText, etc.)
|
||||
- Pas de logique métier
|
||||
|
||||
### `/Services`
|
||||
**Responsabilité** : Couche d'accès aux données
|
||||
|
||||
- `IDatabaseService.cs` : Contrat du service
|
||||
- `DatabaseService.cs` : Implémentation avec MySqlConnector
|
||||
|
||||
**Caractéristiques** :
|
||||
- Méthodes asynchrones (Task<T>)
|
||||
- Gestion des connexions MySQL
|
||||
- Gestion des erreurs avec try/catch
|
||||
- Logs de débogage
|
||||
|
||||
**Méthodes principales** :
|
||||
```csharp
|
||||
Task<List<T>> GetAllAsync()
|
||||
Task<List<T>> GetFilteredAsync(bool? isDone)
|
||||
Task<int> GetPendingCountAsync()
|
||||
Task<int> GetDoneCountAsync()
|
||||
Task<bool> UpdateStatusAsync(int id, bool done)
|
||||
Task<bool> TestConnectionAsync()
|
||||
```
|
||||
|
||||
### `/ViewModels`
|
||||
**Responsabilité** : Logique de présentation et état de l'UI
|
||||
|
||||
- `DashboardViewModel.cs` : Gestion du dashboard
|
||||
- `MessagesViewModel.cs` : Gestion de la liste des messages
|
||||
- `SupportViewModel.cs` : Gestion des demandes support
|
||||
|
||||
**Caractéristiques** :
|
||||
- Hérite de `ObservableObject` (CommunityToolkit.Mvvm)
|
||||
- Utilise `[ObservableProperty]` pour les propriétés bindables
|
||||
- Utilise `[RelayCommand]` pour les commandes
|
||||
- Injection de dépendance via constructeur
|
||||
|
||||
**Exemple de propriété observable** :
|
||||
```csharp
|
||||
[ObservableProperty]
|
||||
private bool isLoading;
|
||||
// Génère automatiquement IsLoading avec INotifyPropertyChanged
|
||||
```
|
||||
|
||||
**Exemple de commande** :
|
||||
```csharp
|
||||
[RelayCommand]
|
||||
public async Task LoadMessagesAsync()
|
||||
{
|
||||
// Logique de chargement
|
||||
}
|
||||
// Génère automatiquement LoadMessagesCommand : ICommand
|
||||
```
|
||||
|
||||
### `/Views`
|
||||
**Responsabilité** : Interface utilisateur
|
||||
|
||||
- `DashboardPage.xaml/.cs`
|
||||
- `MessagesPage.xaml/.cs`
|
||||
- `SupportPage.xaml/.cs`
|
||||
|
||||
**Caractéristiques** :
|
||||
- XAML pour la structure UI
|
||||
- Code-behind minimal (uniquement OnAppearing)
|
||||
- Data Binding vers le ViewModel
|
||||
- Converters pour la présentation
|
||||
|
||||
### `/Converters`
|
||||
**Responsabilité** : Conversion de données pour l'affichage
|
||||
|
||||
- `BoolConverters.cs` :
|
||||
- `BoolToStatusTextConverter` : bool → "Marquer comme fait"
|
||||
- `BoolToColorConverter` : bool → Color
|
||||
|
||||
### `/Configuration`
|
||||
**Responsabilité** : Configuration de l'application
|
||||
|
||||
- `AppSettings.cs` : Paramètres de connexion DB
|
||||
|
||||
## 🔄 Flux de Données
|
||||
|
||||
### 1. Chargement des Données
|
||||
|
||||
```
|
||||
User Opens Page
|
||||
↓
|
||||
OnAppearing() appelé
|
||||
↓
|
||||
LoadCommand.Execute()
|
||||
↓
|
||||
ViewModel appelle Service
|
||||
↓
|
||||
Service exécute requête SQL
|
||||
↓
|
||||
Données retournées au ViewModel
|
||||
↓
|
||||
ViewModel met à jour ObservableCollection
|
||||
↓
|
||||
INotifyPropertyChanged déclenché
|
||||
↓
|
||||
UI se met à jour automatiquement
|
||||
```
|
||||
|
||||
### 2. Action Utilisateur (Changer statut)
|
||||
|
||||
```
|
||||
User clique sur Button
|
||||
↓
|
||||
Command bindée exécutée
|
||||
↓
|
||||
ViewModel.ToggleStatusCommand
|
||||
↓
|
||||
Service.UpdateStatusAsync(id, !done)
|
||||
↓
|
||||
SQL UPDATE exécuté
|
||||
↓
|
||||
Success → ViewModel met à jour l'objet local
|
||||
↓
|
||||
INotifyPropertyChanged → UI refresh
|
||||
```
|
||||
|
||||
## 🧩 Injection de Dépendances
|
||||
|
||||
Configuration dans `MauiProgram.cs` :
|
||||
|
||||
```csharp
|
||||
// Services (Singleton car un seul pour toute l'app)
|
||||
builder.Services.AddSingleton<IDatabaseService, DatabaseService>();
|
||||
|
||||
// ViewModels
|
||||
builder.Services.AddSingleton<DashboardViewModel>(); // Singleton = même instance
|
||||
builder.Services.AddTransient<MessagesViewModel>(); // Transient = nouvelle instance
|
||||
|
||||
// Views
|
||||
builder.Services.AddSingleton<DashboardPage>();
|
||||
builder.Services.AddTransient<MessagesPage>();
|
||||
```
|
||||
|
||||
**Pourquoi Singleton vs Transient ?**
|
||||
- **Singleton** : Dashboard (état partagé, chargé une fois)
|
||||
- **Transient** : Pages de liste (rafraîchies à chaque visite)
|
||||
|
||||
## 🎨 Navigation
|
||||
|
||||
Gestion via `AppShell.xaml` :
|
||||
|
||||
```xaml
|
||||
<TabBar>
|
||||
<ShellContent Title="Dashboard" Route="DashboardPage" ... />
|
||||
<ShellContent Title="Messages" Route="MessagesPage" ... />
|
||||
<ShellContent Title="Support" Route="SupportPage" ... />
|
||||
</TabBar>
|
||||
```
|
||||
|
||||
Navigation programmatique :
|
||||
```csharp
|
||||
await Shell.Current.GoToAsync("//MessagesPage");
|
||||
```
|
||||
|
||||
## 🔐 Sécurité
|
||||
|
||||
**Actuellement** :
|
||||
- Mot de passe en clair dans AppSettings.cs
|
||||
|
||||
**Pour la Production** :
|
||||
- Utiliser variables d'environnement
|
||||
- Chiffrer la chaîne de connexion
|
||||
- Utiliser Azure Key Vault ou équivalent
|
||||
- Implémenter authentification utilisateur
|
||||
- Logger les actions sensibles
|
||||
|
||||
## 📊 Performance
|
||||
|
||||
**Optimisations actuelles** :
|
||||
- Connexions fermées automatiquement (using)
|
||||
- Requêtes asynchrones (async/await)
|
||||
- Filtres côté base de données (WHERE clause)
|
||||
- Tri côté base de données (ORDER BY)
|
||||
|
||||
**Optimisations futures possibles** :
|
||||
- Pagination pour grandes listes
|
||||
- Mise en cache des données
|
||||
- Connection pooling (déjà géré par MySqlConnector)
|
||||
- Lazy loading
|
||||
|
||||
## 🧪 Testabilité
|
||||
|
||||
Architecture testable grâce à :
|
||||
- Interface `IDatabaseService` (mockable)
|
||||
- ViewModels découplés des Views
|
||||
- Injection de dépendances
|
||||
- Logique métier dans ViewModels
|
||||
|
||||
Exemple de test unitaire (potentiel) :
|
||||
```csharp
|
||||
[Test]
|
||||
public async Task LoadMessages_ShouldPopulateCollection()
|
||||
{
|
||||
// Arrange
|
||||
var mockService = new Mock<IDatabaseService>();
|
||||
mockService.Setup(s => s.GetAllMessagesAsync())
|
||||
.ReturnsAsync(new List<Message> { /* ... */ });
|
||||
var vm = new MessagesViewModel(mockService.Object);
|
||||
|
||||
// Act
|
||||
await vm.LoadMessagesCommand.ExecuteAsync(null);
|
||||
|
||||
// Assert
|
||||
Assert.That(vm.Messages.Count, Is.GreaterThan(0));
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 Extensibilité
|
||||
|
||||
Pour ajouter une nouvelle entité :
|
||||
|
||||
1. **Model** : Créer `NewEntity.cs`
|
||||
2. **Service** : Ajouter méthodes dans `IDatabaseService` et `DatabaseService`
|
||||
3. **ViewModel** : Créer `NewEntityViewModel.cs`
|
||||
4. **View** : Créer `NewEntityPage.xaml/.cs`
|
||||
5. **DI** : Enregistrer dans `MauiProgram.cs`
|
||||
6. **Navigation** : Ajouter dans `AppShell.xaml`
|
||||
|
||||
## 📝 Conventions de Code
|
||||
|
||||
- **Naming** :
|
||||
- ViewModels : `*ViewModel.cs`
|
||||
- Pages : `*Page.xaml/.cs`
|
||||
- Services : `*Service.cs` avec interface `I*Service.cs`
|
||||
|
||||
- **Async** :
|
||||
- Toujours utiliser `async/await`
|
||||
- Suffixe `Async` pour les méthodes
|
||||
|
||||
- **MVVM** :
|
||||
- Pas de logique dans code-behind (sauf OnAppearing)
|
||||
- Tout passe par le ViewModel
|
||||
- Binding bidirectionnel quand nécessaire
|
||||
|
||||
---
|
||||
|
||||
**Cette architecture garantit** :
|
||||
- ✅ Maintenabilité
|
||||
- ✅ Testabilité
|
||||
- ✅ Séparation des responsabilités
|
||||
- ✅ Réutilisabilité
|
||||
- ✅ Extensibilité
|
||||
182
CHANGELOG.md
Normal file
182
CHANGELOG.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# 📅 Changelog - TravelMate Admin
|
||||
|
||||
Toutes les modifications notables de ce projet seront documentées dans ce fichier.
|
||||
|
||||
Le format est basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/),
|
||||
et ce projet adhère à [Semantic Versioning](https://semver.org/lang/fr/).
|
||||
|
||||
## [1.0.0] - 2026-01-12
|
||||
|
||||
### ✨ Ajouté
|
||||
|
||||
#### Architecture & Structure
|
||||
- Architecture MVVM complète avec CommunityToolkit.Mvvm
|
||||
- Pattern strict avec séparation Models/Views/ViewModels/Services
|
||||
- Injection de dépendances configurée dans MauiProgram.cs
|
||||
- Navigation Shell avec TabBar
|
||||
|
||||
#### Models
|
||||
- `Message.cs` : Modèle pour les messages de demande avec propriétés calculées
|
||||
- `SupportRequest.cs` : Modèle pour les demandes support avec propriétés calculées
|
||||
|
||||
#### Services
|
||||
- `IDatabaseService.cs` : Interface du service de base de données
|
||||
- `DatabaseService.cs` : Implémentation complète avec MySqlConnector
|
||||
- Connexion à MariaDB/MySQL
|
||||
- Méthodes CRUD asynchrones
|
||||
- Gestion des erreurs et logs
|
||||
- Test de connexion
|
||||
|
||||
#### ViewModels
|
||||
- `DashboardViewModel.cs` : Gestion du tableau de bord avec statistiques
|
||||
- `MessagesViewModel.cs` : Gestion de la liste des messages avec filtres
|
||||
- `SupportViewModel.cs` : Gestion des demandes support avec filtres
|
||||
- Utilisation de `[ObservableProperty]` et `[RelayCommand]`
|
||||
- Commandes asynchrones pour toutes les opérations
|
||||
|
||||
#### Views
|
||||
- `DashboardPage.xaml/.cs` : Page principale avec cartes de statistiques
|
||||
- `MessagesPage.xaml/.cs` : Liste des messages avec CollectionView
|
||||
- `SupportPage.xaml/.cs` : Liste des demandes support
|
||||
- Design moderne avec dark theme (#1a1a1a)
|
||||
- Layout responsive
|
||||
- Indicateurs de chargement
|
||||
|
||||
#### UI/UX
|
||||
- Dark theme par défaut avec palette de couleurs cohérente
|
||||
- Cartes avec ombres et coins arrondis
|
||||
- Animations smooth pour les interactions
|
||||
- Empty states pour listes vides
|
||||
- Pull-to-refresh sur les listes
|
||||
- Filtres dynamiques (Tout / À faire / Fait)
|
||||
|
||||
#### Converters
|
||||
- `BoolToStatusTextConverter` : Conversion bool → texte bouton
|
||||
- `BoolToColorConverter` : Conversion bool → couleur bouton
|
||||
|
||||
#### Configuration
|
||||
- `AppSettings.cs` : Configuration centralisée de la connexion DB
|
||||
- Paramètres modifiables (Server, Port, Database, User, Password)
|
||||
|
||||
#### Base de Données
|
||||
- Script SQL `database_setup.sql` complet :
|
||||
- Création de la base `travelmateadmin`
|
||||
- Table `messages` avec 8 colonnes et index
|
||||
- Table `support_requests` avec 8 colonnes et index
|
||||
- 4 messages de test
|
||||
- 4 demandes support de test
|
||||
- Encodage UTF-8 (utf8mb4)
|
||||
|
||||
#### Fonctionnalités
|
||||
- Dashboard avec statistiques en temps réel
|
||||
- Filtrage des demandes (tout/à faire/fait)
|
||||
- Changement de statut d'une demande (toggle done)
|
||||
- Tri par date (plus récent en haut)
|
||||
- Rafraîchissement manuel des données
|
||||
- Navigation entre les sections
|
||||
- Indicateur de connexion DB
|
||||
|
||||
#### Packages NuGet
|
||||
- `CommunityToolkit.Mvvm` v8.3.2
|
||||
- `MySqlConnector` v2.4.0
|
||||
|
||||
#### Documentation
|
||||
- `README.md` : Documentation complète du projet (sections détaillées)
|
||||
- `QUICKSTART.md` : Guide de démarrage rapide (5 minutes)
|
||||
- `CONFIGURATION.md` : Guide de configuration DB avec exemples
|
||||
- `ARCHITECTURE.md` : Documentation architecture MVVM détaillée
|
||||
- `COMMANDS.md` : Référence des commandes de développement
|
||||
- `SQL_REFERENCE.md` : Référence complète des requêtes SQL
|
||||
- `PROJECT_SUMMARY.md` : Résumé du projet et checklist
|
||||
- `.gitignore` : Configuration Git adaptée .NET MAUI
|
||||
|
||||
#### DevOps
|
||||
- Configuration csproj pour multi-plateforme (Mac/Win/Android/iOS)
|
||||
- Build scripts pour toutes les plateformes
|
||||
- Compilation vérifiée et réussie
|
||||
|
||||
### 🎯 Plateformes Supportées
|
||||
- ✅ macOS (MacCatalyst) - net10.0-maccatalyst
|
||||
- ✅ Windows - net10.0-windows10.0.19041.0
|
||||
- ⚠️ Android - net10.0-android (non testé)
|
||||
- ⚠️ iOS - net10.0-ios (non testé)
|
||||
|
||||
### 📊 Statistiques
|
||||
- **Fichiers créés** : 35+
|
||||
- **Lignes de code** : ~2000+ (C# + XAML)
|
||||
- **Modèles** : 2
|
||||
- **Services** : 1 (+ interface)
|
||||
- **ViewModels** : 3
|
||||
- **Views** : 3 (+ code-behind)
|
||||
- **Documentation** : 8 fichiers MD
|
||||
|
||||
---
|
||||
|
||||
## [Unreleased] - Fonctionnalités Futures
|
||||
|
||||
### 🚀 Planifié pour v1.1.0
|
||||
- [ ] Mode light/dark configurable
|
||||
- [ ] Recherche/filtrage avancé
|
||||
- [ ] Export de données (CSV, PDF)
|
||||
- [ ] Pagination pour grandes listes
|
||||
- [ ] Statistiques graphiques (charts)
|
||||
|
||||
### 🔮 Planifié pour v1.2.0
|
||||
- [ ] Authentification utilisateur
|
||||
- [ ] Gestion des permissions
|
||||
- [ ] Historique des modifications
|
||||
- [ ] Notifications push
|
||||
- [ ] Multi-langue (i18n)
|
||||
|
||||
### 🧪 Planifié pour v1.3.0
|
||||
- [ ] Tests unitaires (ViewModels)
|
||||
- [ ] Tests d'intégration (Services)
|
||||
- [ ] CI/CD avec GitHub Actions
|
||||
- [ ] Couverture de code
|
||||
|
||||
### 🎨 Améliorations UI/UX
|
||||
- [ ] Animations de transitions
|
||||
- [ ] Thèmes personnalisables
|
||||
- [ ] Accessibilité (screen readers)
|
||||
- [ ] Raccourcis clavier
|
||||
|
||||
### 🔧 Améliorations Techniques
|
||||
- [ ] Connection pooling optimisé
|
||||
- [ ] Cache des données
|
||||
- [ ] Offline mode
|
||||
- [ ] Synchronisation automatique
|
||||
- [ ] Logs structurés (Serilog)
|
||||
|
||||
### 🔐 Sécurité
|
||||
- [ ] Chiffrement de la chaîne de connexion
|
||||
- [ ] Variables d'environnement
|
||||
- [ ] Azure Key Vault integration
|
||||
- [ ] Audit trail
|
||||
- [ ] Rate limiting
|
||||
|
||||
---
|
||||
|
||||
## Types de Changements
|
||||
|
||||
- `Added` ✨ : Nouvelles fonctionnalités
|
||||
- `Changed` 🔄 : Modifications de fonctionnalités existantes
|
||||
- `Deprecated` ⚠️ : Fonctionnalités bientôt supprimées
|
||||
- `Removed` 🗑️ : Fonctionnalités supprimées
|
||||
- `Fixed` 🐛 : Corrections de bugs
|
||||
- `Security` 🔐 : Corrections de sécurité
|
||||
|
||||
---
|
||||
|
||||
## Format des Versions
|
||||
|
||||
```
|
||||
[MAJOR.MINOR.PATCH] - YYYY-MM-DD
|
||||
|
||||
MAJOR : Changements incompatibles de l'API
|
||||
MINOR : Nouvelles fonctionnalités rétrocompatibles
|
||||
PATCH : Corrections de bugs rétrocompatibles
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Note** : Ce fichier sera mis à jour à chaque release avec les changements apportés.
|
||||
311
COMMANDS.md
Normal file
311
COMMANDS.md
Normal file
@@ -0,0 +1,311 @@
|
||||
# Commandes Utiles - TravelMate Admin
|
||||
|
||||
## 🔧 Développement
|
||||
|
||||
### Restaurer les packages
|
||||
```bash
|
||||
dotnet restore
|
||||
```
|
||||
|
||||
### Build le projet
|
||||
```bash
|
||||
# MacCatalyst
|
||||
dotnet build -f net10.0-maccatalyst
|
||||
|
||||
# Windows
|
||||
dotnet build -f net10.0-windows10.0.19041.0
|
||||
|
||||
# Android
|
||||
dotnet build -f net10.0-android
|
||||
|
||||
# iOS
|
||||
dotnet build -f net10.0-ios
|
||||
```
|
||||
|
||||
### Lancer l'application
|
||||
```bash
|
||||
# MacCatalyst
|
||||
dotnet build -t:Run -f net10.0-maccatalyst
|
||||
|
||||
# Windows
|
||||
dotnet build -t:Run -f net10.0-windows10.0.19041.0
|
||||
```
|
||||
|
||||
### Nettoyer le projet
|
||||
```bash
|
||||
dotnet clean
|
||||
rm -rf TravelMateAdmin/bin TravelMateAdmin/obj
|
||||
```
|
||||
|
||||
### Rebuild complet
|
||||
```bash
|
||||
dotnet clean
|
||||
dotnet restore
|
||||
dotnet build
|
||||
```
|
||||
|
||||
## 🗄️ Base de Données
|
||||
|
||||
### Créer la base de données
|
||||
```bash
|
||||
mysql -u root -p < database_setup.sql
|
||||
```
|
||||
|
||||
### Se connecter à MySQL
|
||||
```bash
|
||||
mysql -u root -p travelmateadmin
|
||||
```
|
||||
|
||||
### Afficher les tables
|
||||
```sql
|
||||
USE travelmateadmin;
|
||||
SHOW TABLES;
|
||||
```
|
||||
|
||||
### Voir les données
|
||||
```sql
|
||||
-- Tous les messages
|
||||
SELECT * FROM messages ORDER BY created_at DESC;
|
||||
|
||||
-- Messages en attente
|
||||
SELECT * FROM messages WHERE done = FALSE;
|
||||
|
||||
-- Statistiques
|
||||
SELECT
|
||||
COUNT(*) as total,
|
||||
SUM(done = FALSE) as pending,
|
||||
SUM(done = TRUE) as completed
|
||||
FROM messages;
|
||||
```
|
||||
|
||||
### Ajouter un message de test
|
||||
```sql
|
||||
INSERT INTO messages (nom, prenom, email, message, done, created_at)
|
||||
VALUES ('Test', 'User', 'test@example.com', 'Ceci est un test', FALSE, NOW());
|
||||
```
|
||||
|
||||
### Marquer tous les messages comme non traités
|
||||
```sql
|
||||
UPDATE messages SET done = FALSE;
|
||||
UPDATE support_requests SET done = FALSE;
|
||||
```
|
||||
|
||||
### Réinitialiser les données
|
||||
```bash
|
||||
mysql -u root -p travelmateadmin < database_setup.sql
|
||||
```
|
||||
|
||||
### Backup de la base
|
||||
```bash
|
||||
mysqldump -u root -p travelmateadmin > backup_$(date +%Y%m%d_%H%M%S).sql
|
||||
```
|
||||
|
||||
### Restore depuis un backup
|
||||
```bash
|
||||
mysql -u root -p travelmateadmin < backup_20260112_143000.sql
|
||||
```
|
||||
|
||||
## 📦 NuGet Packages
|
||||
|
||||
### Voir les packages installés
|
||||
```bash
|
||||
dotnet list TravelMateAdmin/TravelMateAdmin.csproj package
|
||||
```
|
||||
|
||||
### Mettre à jour un package
|
||||
```bash
|
||||
dotnet add TravelMateAdmin/TravelMateAdmin.csproj package CommunityToolkit.Mvvm
|
||||
dotnet add TravelMateAdmin/TravelMateAdmin.csproj package MySqlConnector
|
||||
```
|
||||
|
||||
### Mettre à jour tous les packages
|
||||
```bash
|
||||
dotnet list TravelMateAdmin/TravelMateAdmin.csproj package --outdated
|
||||
```
|
||||
|
||||
## 🐛 Debugging
|
||||
|
||||
### Voir les logs
|
||||
Dans le terminal où vous avez lancé l'app, les logs apparaissent via :
|
||||
```csharp
|
||||
System.Diagnostics.Debug.WriteLine("Mon log");
|
||||
```
|
||||
|
||||
### Tests de connexion MySQL
|
||||
```bash
|
||||
# Tester si MySQL est accessible
|
||||
nc -zv localhost 3306
|
||||
|
||||
# Voir les processus MySQL
|
||||
ps aux | grep mysql
|
||||
|
||||
# Démarrer MySQL (Mac avec Homebrew)
|
||||
brew services start mysql
|
||||
|
||||
# Démarrer MySQL (Linux)
|
||||
sudo service mysql start
|
||||
|
||||
# Démarrer MySQL (MAMP)
|
||||
# Utiliser l'interface MAMP
|
||||
```
|
||||
|
||||
## 📱 Plateforme Spécifique
|
||||
|
||||
### MacCatalyst - Voir les logs système
|
||||
```bash
|
||||
log stream --predicate 'processImagePath contains "TravelMateAdmin"' --level debug
|
||||
```
|
||||
|
||||
### Android - Voir les logs
|
||||
```bash
|
||||
adb logcat | grep TravelMateAdmin
|
||||
```
|
||||
|
||||
### iOS Simulator - Voir les logs
|
||||
```bash
|
||||
xcrun simctl spawn booted log stream --level debug | grep TravelMateAdmin
|
||||
```
|
||||
|
||||
## 🔍 Code Analysis
|
||||
|
||||
### Format le code
|
||||
```bash
|
||||
dotnet format TravelMateAdmin/TravelMateAdmin.csproj
|
||||
```
|
||||
|
||||
### Analyser le code
|
||||
```bash
|
||||
dotnet build /p:TreatWarningsAsErrors=true
|
||||
```
|
||||
|
||||
## 📊 Statistiques du Projet
|
||||
|
||||
### Compter les lignes de code
|
||||
```bash
|
||||
find TravelMateAdmin -name "*.cs" -not -path "*/obj/*" -not -path "*/bin/*" | xargs wc -l
|
||||
```
|
||||
|
||||
### Voir l'arborescence
|
||||
```bash
|
||||
tree -I 'bin|obj' TravelMateAdmin/
|
||||
```
|
||||
|
||||
### Taille du projet
|
||||
```bash
|
||||
du -sh TravelMateAdmin/
|
||||
```
|
||||
|
||||
## 🚀 Publication
|
||||
|
||||
### Publish MacCatalyst
|
||||
```bash
|
||||
dotnet publish -f net10.0-maccatalyst -c Release -p:CreatePackage=true
|
||||
```
|
||||
|
||||
### Publish Windows
|
||||
```bash
|
||||
dotnet publish -f net10.0-windows10.0.19041.0 -c Release
|
||||
```
|
||||
|
||||
### Créer un package pour Mac App Store
|
||||
```bash
|
||||
dotnet publish -f net10.0-maccatalyst -c Release \
|
||||
-p:RuntimeIdentifier=maccatalyst-arm64 \
|
||||
-p:CreatePackage=true \
|
||||
-p:CodesignKey="Apple Distribution: Your Name" \
|
||||
-p:CodesignProvision="Your Provisioning Profile"
|
||||
```
|
||||
|
||||
## 🧪 Tests (futur)
|
||||
|
||||
### Ajouter un projet de tests
|
||||
```bash
|
||||
dotnet new xunit -n TravelMateAdmin.Tests
|
||||
dotnet sln add TravelMateAdmin.Tests/TravelMateAdmin.Tests.csproj
|
||||
dotnet add TravelMateAdmin.Tests reference TravelMateAdmin/TravelMateAdmin.csproj
|
||||
```
|
||||
|
||||
### Lancer les tests
|
||||
```bash
|
||||
dotnet test
|
||||
```
|
||||
|
||||
## 📝 Git
|
||||
|
||||
### Initialiser le repo
|
||||
```bash
|
||||
git init
|
||||
git add .
|
||||
git commit -m "Initial commit: TravelMate Admin MAUI app"
|
||||
```
|
||||
|
||||
### Ignorer les fichiers de build
|
||||
Le `.gitignore` est déjà configuré pour :
|
||||
- bin/, obj/
|
||||
- .vs/, .vscode/
|
||||
- Configuration sensible
|
||||
|
||||
### Créer une branche
|
||||
```bash
|
||||
git checkout -b feature/nouvelle-fonctionnalite
|
||||
```
|
||||
|
||||
## 🔐 Sécurité
|
||||
|
||||
### Chiffrer la configuration (exemple)
|
||||
```bash
|
||||
# Générer une clé
|
||||
openssl rand -base64 32
|
||||
|
||||
# Chiffrer un fichier
|
||||
openssl enc -aes-256-cbc -salt -in AppSettings.cs -out AppSettings.cs.enc
|
||||
|
||||
# Déchiffrer
|
||||
openssl enc -d -aes-256-cbc -in AppSettings.cs.enc -out AppSettings.cs
|
||||
```
|
||||
|
||||
## 🛠️ Maintenance
|
||||
|
||||
### Vérifier les dépendances obsolètes
|
||||
```bash
|
||||
dotnet list package --outdated
|
||||
```
|
||||
|
||||
### Mettre à jour .NET
|
||||
```bash
|
||||
# Vérifier la version actuelle
|
||||
dotnet --version
|
||||
|
||||
# Télécharger la dernière version
|
||||
# https://dotnet.microsoft.com/download
|
||||
```
|
||||
|
||||
### Nettoyer NuGet cache
|
||||
```bash
|
||||
dotnet nuget locals all --clear
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips & Tricks
|
||||
|
||||
### Hot Reload
|
||||
Lors du développement, les changements XAML sont appliqués en temps réel avec Hot Reload.
|
||||
|
||||
### Raccourcis Visual Studio
|
||||
- `F5` : Run avec debug
|
||||
- `Ctrl+F5` (Cmd+F5 Mac) : Run sans debug
|
||||
- `Shift+F5` : Stop debugging
|
||||
|
||||
### Performance
|
||||
```bash
|
||||
# Build en Release pour tester les performances réelles
|
||||
dotnet build -c Release -f net10.0-maccatalyst
|
||||
```
|
||||
|
||||
### Multi-targeting
|
||||
Pour cibler plusieurs plateformes en une fois :
|
||||
```bash
|
||||
dotnet build
|
||||
# Build toutes les plateformes définies dans TargetFrameworks
|
||||
```
|
||||
102
CONFIGURATION.md
Normal file
102
CONFIGURATION.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# Configuration de l'Application TravelMate Admin
|
||||
|
||||
## Configuration de Base de Données
|
||||
|
||||
Pour configurer la connexion à votre base de données, modifiez le fichier :
|
||||
`TravelMateAdmin/Configuration/AppSettings.cs`
|
||||
|
||||
### Exemple pour une connexion locale :
|
||||
|
||||
```csharp
|
||||
public const string Server = "localhost";
|
||||
public const string Port = "3306";
|
||||
public const string Database = "travelmateadmin";
|
||||
public const string User = "root";
|
||||
public const string Password = "monmotdepasse";
|
||||
```
|
||||
|
||||
### Exemple pour une connexion distante :
|
||||
|
||||
```csharp
|
||||
public const string Server = "192.168.1.100"; // IP du serveur
|
||||
public const string Port = "3306";
|
||||
public const string Database = "travelmateadmin";
|
||||
public const string User = "admin";
|
||||
public const string Password = "motdepassesecurise";
|
||||
```
|
||||
|
||||
### Exemple avec un serveur cloud (ex: AWS RDS, Azure Database) :
|
||||
|
||||
```csharp
|
||||
public const string Server = "myserver.mysql.database.azure.com";
|
||||
public const string Port = "3306";
|
||||
public const string Database = "travelmateadmin";
|
||||
public const string User = "myadmin@myserver";
|
||||
public const string Password = "P@ssw0rd!";
|
||||
```
|
||||
|
||||
## Sécurité
|
||||
|
||||
⚠️ **Important** : Ne commitez JAMAIS vos mots de passe dans Git !
|
||||
|
||||
Pour une meilleure sécurité en production :
|
||||
|
||||
1. Utilisez des variables d'environnement
|
||||
2. Utilisez un système de gestion des secrets (Azure Key Vault, AWS Secrets Manager)
|
||||
3. Chiffrez la chaîne de connexion
|
||||
|
||||
### Exemple avec variables d'environnement :
|
||||
|
||||
```csharp
|
||||
public static string GetConnectionString()
|
||||
{
|
||||
var server = Environment.GetEnvironmentVariable("DB_SERVER") ?? Server;
|
||||
var port = Environment.GetEnvironmentVariable("DB_PORT") ?? Port;
|
||||
var database = Environment.GetEnvironmentVariable("DB_NAME") ?? Database;
|
||||
var user = Environment.GetEnvironmentVariable("DB_USER") ?? User;
|
||||
var password = Environment.GetEnvironmentVariable("DB_PASSWORD") ?? Password;
|
||||
|
||||
return $"Server={server};Port={port};Database={database};User={user};Password={password};";
|
||||
}
|
||||
```
|
||||
|
||||
## Paramètres Supplémentaires MySQL
|
||||
|
||||
Vous pouvez ajouter des paramètres supplémentaires à la chaîne de connexion :
|
||||
|
||||
```csharp
|
||||
public static string GetConnectionString()
|
||||
{
|
||||
return $"Server={Server};Port={Port};Database={Database};User={User};Password={Password};" +
|
||||
"SslMode=Required;" + // Pour SSL/TLS
|
||||
"AllowPublicKeyRetrieval=True;" + // Pour l'authentification
|
||||
"ConnectionTimeout=30;" + // Timeout en secondes
|
||||
"DefaultCommandTimeout=30;"; // Timeout des commandes
|
||||
}
|
||||
```
|
||||
|
||||
## Test de Connexion
|
||||
|
||||
Pour tester votre connexion, lancez l'application et vérifiez :
|
||||
1. Le dashboard doit afficher "✓ Connecté" en haut à droite
|
||||
2. Les statistiques doivent se charger
|
||||
3. Si "✗ Déconnecté", vérifiez vos paramètres et les logs de débogage
|
||||
|
||||
## Dépannage Connexion
|
||||
|
||||
### Erreur "Access denied"
|
||||
- Vérifiez le nom d'utilisateur et le mot de passe
|
||||
- Vérifiez que l'utilisateur a les droits sur la base de données :
|
||||
```sql
|
||||
GRANT ALL PRIVILEGES ON travelmateadmin.* TO 'user'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
### Erreur "Cannot connect to server"
|
||||
- Vérifiez que MySQL est démarré
|
||||
- Vérifiez le serveur et le port
|
||||
- Vérifiez les règles de firewall
|
||||
|
||||
### Erreur "Unknown database"
|
||||
- Vérifiez que la base de données existe
|
||||
- Exécutez le script `database_setup.sql`
|
||||
232
INDEX.md
Normal file
232
INDEX.md
Normal file
@@ -0,0 +1,232 @@
|
||||
# 📚 Index de Documentation - TravelMate Admin
|
||||
|
||||
Guide complet pour naviguer dans la documentation du projet.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Pour Commencer
|
||||
|
||||
**Nouveau sur le projet ? Commencez ici :**
|
||||
|
||||
1. 📖 [README.md](README.md) - **Lisez-moi d'abord** - Vue d'ensemble du projet
|
||||
2. ⚡ [QUICKSTART.md](QUICKSTART.md) - Installation en 5 minutes
|
||||
3. 🎉 Lancez l'application !
|
||||
|
||||
---
|
||||
|
||||
## 📂 Documentation par Catégorie
|
||||
|
||||
### 🏗️ Architecture & Développement
|
||||
|
||||
| Fichier | Description | Quand le consulter |
|
||||
|---------|-------------|-------------------|
|
||||
| [ARCHITECTURE.md](ARCHITECTURE.md) | Architecture MVVM détaillée, flux de données, patterns | Comprendre la structure du code |
|
||||
| [PROJECT_SUMMARY.md](PROJECT_SUMMARY.md) | Résumé complet, fichiers créés, checklist | Vue d'ensemble technique |
|
||||
| [CHANGELOG.md](CHANGELOG.md) | Historique des versions et modifications | Voir les changements apportés |
|
||||
|
||||
### ⚙️ Configuration & Installation
|
||||
|
||||
| Fichier | Description | Quand le consulter |
|
||||
|---------|-------------|-------------------|
|
||||
| [QUICKSTART.md](QUICKSTART.md) | Guide rapide d'installation (5 min) | Première installation |
|
||||
| [CONFIGURATION.md](CONFIGURATION.md) | Configuration de la base de données | Problèmes de connexion DB |
|
||||
| [README.md](README.md) | Guide complet avec tous les détails | Documentation générale |
|
||||
|
||||
### 💻 Développement & Maintenance
|
||||
|
||||
| Fichier | Description | Quand le consulter |
|
||||
|---------|-------------|-------------------|
|
||||
| [COMMANDS.md](COMMANDS.md) | Commandes utiles (build, DB, debug) | Tâches de développement |
|
||||
| [SQL_REFERENCE.md](SQL_REFERENCE.md) | Requêtes SQL complètes | Gérer la base de données |
|
||||
|
||||
### 📊 Base de Données
|
||||
|
||||
| Fichier | Description | Quand le consulter |
|
||||
|---------|-------------|-------------------|
|
||||
| [database_setup.sql](database_setup.sql) | Script SQL de création + données test | Initialiser la DB |
|
||||
| [SQL_REFERENCE.md](SQL_REFERENCE.md) | Guide complet des requêtes SQL | Opérations sur les données |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Guides par Scénario
|
||||
|
||||
### Scénario 1 : Je veux installer l'app rapidement
|
||||
1. [QUICKSTART.md](QUICKSTART.md) - Suivez les 5 étapes
|
||||
2. [database_setup.sql](database_setup.sql) - Exécutez ce script
|
||||
3. Modifiez `TravelMateAdmin/Configuration/AppSettings.cs`
|
||||
4. Lancez l'app !
|
||||
|
||||
### Scénario 2 : J'ai des problèmes de connexion DB
|
||||
1. [CONFIGURATION.md](CONFIGURATION.md) - Guide de dépannage
|
||||
2. Vérifiez `AppSettings.cs`
|
||||
3. [COMMANDS.md](COMMANDS.md) - Commandes de test MySQL
|
||||
|
||||
### Scénario 3 : Je veux comprendre le code
|
||||
1. [ARCHITECTURE.md](ARCHITECTURE.md) - Pattern MVVM expliqué
|
||||
2. [PROJECT_SUMMARY.md](PROJECT_SUMMARY.md) - Structure des fichiers
|
||||
3. Lisez les commentaires dans le code source
|
||||
|
||||
### Scénario 4 : Je veux ajouter une fonctionnalité
|
||||
1. [ARCHITECTURE.md](ARCHITECTURE.md) - Section "Extensibilité"
|
||||
2. [COMMANDS.md](COMMANDS.md) - Commandes de build/test
|
||||
3. Suivez le pattern existant (Models → Services → ViewModels → Views)
|
||||
|
||||
### Scénario 5 : Je veux gérer les données
|
||||
1. [SQL_REFERENCE.md](SQL_REFERENCE.md) - Toutes les requêtes SQL
|
||||
2. [COMMANDS.md](COMMANDS.md) - Section "Base de Données"
|
||||
|
||||
### Scénario 6 : Je veux personnaliser l'UI
|
||||
1. [README.md](README.md) - Section "Personnalisation"
|
||||
2. Modifiez les couleurs dans les fichiers XAML
|
||||
3. Consultez les Views existantes comme exemples
|
||||
|
||||
---
|
||||
|
||||
## 📖 Structure de la Documentation
|
||||
|
||||
```
|
||||
Documentation/
|
||||
├── README.md ⭐ Point d'entrée principal
|
||||
├── QUICKSTART.md 🚀 Installation rapide
|
||||
├── ARCHITECTURE.md 🏗️ Architecture technique
|
||||
├── CONFIGURATION.md ⚙️ Configuration DB
|
||||
├── COMMANDS.md 💻 Commandes de dev
|
||||
├── SQL_REFERENCE.md 📊 Référence SQL
|
||||
├── PROJECT_SUMMARY.md 📝 Résumé complet
|
||||
├── CHANGELOG.md 📅 Historique des versions
|
||||
└── INDEX.md 📚 Ce fichier
|
||||
|
||||
Code Source/
|
||||
├── TravelMateAdmin/
|
||||
│ ├── Models/ 📦 Modèles de données
|
||||
│ ├── Services/ 🔧 Couche d'accès aux données
|
||||
│ ├── ViewModels/ 🎭 Logique de présentation
|
||||
│ ├── Views/ 🎨 Interface utilisateur
|
||||
│ ├── Converters/ 🔄 Converters XAML
|
||||
│ └── Configuration/ ⚙️ Configuration app
|
||||
|
||||
Base de Données/
|
||||
└── database_setup.sql 🗄️ Script SQL
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Index par Mots-Clés
|
||||
|
||||
### A
|
||||
- **Architecture MVVM** → [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
- **Ajouter une fonctionnalité** → [ARCHITECTURE.md](ARCHITECTURE.md#extensibilité)
|
||||
|
||||
### B
|
||||
- **Base de données** → [CONFIGURATION.md](CONFIGURATION.md), [SQL_REFERENCE.md](SQL_REFERENCE.md)
|
||||
- **Build** → [COMMANDS.md](COMMANDS.md#développement)
|
||||
- **Backup** → [COMMANDS.md](COMMANDS.md#base-de-données)
|
||||
|
||||
### C
|
||||
- **Commandes** → [COMMANDS.md](COMMANDS.md)
|
||||
- **Configuration** → [CONFIGURATION.md](CONFIGURATION.md)
|
||||
- **Connexion DB** → [CONFIGURATION.md](CONFIGURATION.md)
|
||||
- **CommunityToolkit.Mvvm** → [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
|
||||
### D
|
||||
- **Dashboard** → [PROJECT_SUMMARY.md](PROJECT_SUMMARY.md)
|
||||
- **DatabaseService** → [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
- **Dépannage** → [CONFIGURATION.md](CONFIGURATION.md), [QUICKSTART.md](QUICKSTART.md)
|
||||
|
||||
### F
|
||||
- **Filtres** → [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
|
||||
### I
|
||||
- **Installation** → [QUICKSTART.md](QUICKSTART.md)
|
||||
- **Injection de dépendances** → [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
|
||||
### M
|
||||
- **MariaDB** → [CONFIGURATION.md](CONFIGURATION.md)
|
||||
- **Messages** → [README.md](README.md)
|
||||
- **MySQL** → [CONFIGURATION.md](CONFIGURATION.md), [SQL_REFERENCE.md](SQL_REFERENCE.md)
|
||||
- **MVVM** → [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
|
||||
### N
|
||||
- **Navigation** → [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
- **NuGet** → [COMMANDS.md](COMMANDS.md)
|
||||
|
||||
### P
|
||||
- **Performance** → [ARCHITECTURE.md](ARCHITECTURE.md), [SQL_REFERENCE.md](SQL_REFERENCE.md)
|
||||
- **Problèmes** → [QUICKSTART.md](QUICKSTART.md), [CONFIGURATION.md](CONFIGURATION.md)
|
||||
|
||||
### Q
|
||||
- **Quick Start** → [QUICKSTART.md](QUICKSTART.md)
|
||||
|
||||
### R
|
||||
- **Requêtes SQL** → [SQL_REFERENCE.md](SQL_REFERENCE.md)
|
||||
|
||||
### S
|
||||
- **Sécurité** → [CONFIGURATION.md](CONFIGURATION.md), [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
- **Services** → [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
- **SQL** → [SQL_REFERENCE.md](SQL_REFERENCE.md)
|
||||
- **Support** → [PROJECT_SUMMARY.md](PROJECT_SUMMARY.md)
|
||||
|
||||
### T
|
||||
- **Tests** → [COMMANDS.md](COMMANDS.md), [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
|
||||
### V
|
||||
- **ViewModels** → [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
- **Views** → [ARCHITECTURE.md](ARCHITECTURE.md)
|
||||
|
||||
### X
|
||||
- **XAML** → [ARCHITECTURE.md](ARCHITECTURE.md), [README.md](README.md)
|
||||
|
||||
---
|
||||
|
||||
## 📊 Statistiques de la Documentation
|
||||
|
||||
| Type | Nombre | Lignes Totales |
|
||||
|------|--------|----------------|
|
||||
| Fichiers Markdown | 8 | ~1500+ lignes |
|
||||
| Sections | 100+ | - |
|
||||
| Exemples de code | 50+ | - |
|
||||
| Commandes | 100+ | - |
|
||||
| Requêtes SQL | 60+ | - |
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Aide Rapide
|
||||
|
||||
**Je ne trouve pas ce que je cherche !**
|
||||
|
||||
1. Utilisez Ctrl+F (Cmd+F sur Mac) dans ce fichier pour chercher un mot-clé
|
||||
2. Consultez la section "Guides par Scénario" ci-dessus
|
||||
3. Ouvrez [README.md](README.md) pour une vue d'ensemble
|
||||
4. Tous les fichiers sont en Markdown, faciles à lire avec n'importe quel éditeur
|
||||
|
||||
**Suggestions de documentation manquante ?**
|
||||
|
||||
N'hésitez pas à créer une issue ou à contribuer !
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Ordre de Lecture Recommandé
|
||||
|
||||
### Pour les Débutants
|
||||
1. [README.md](README.md) - Vue d'ensemble
|
||||
2. [QUICKSTART.md](QUICKSTART.md) - Installation
|
||||
3. [PROJECT_SUMMARY.md](PROJECT_SUMMARY.md) - Résumé
|
||||
4. Lancez l'app et explorez !
|
||||
|
||||
### Pour les Développeurs
|
||||
1. [ARCHITECTURE.md](ARCHITECTURE.md) - Comprendre la structure
|
||||
2. [COMMANDS.md](COMMANDS.md) - Commandes de dev
|
||||
3. [SQL_REFERENCE.md](SQL_REFERENCE.md) - Opérations DB
|
||||
4. Code source dans TravelMateAdmin/
|
||||
|
||||
### Pour les Administrateurs DB
|
||||
1. [CONFIGURATION.md](CONFIGURATION.md) - Configuration
|
||||
2. [database_setup.sql](database_setup.sql) - Script d'installation
|
||||
3. [SQL_REFERENCE.md](SQL_REFERENCE.md) - Référence complète
|
||||
4. [COMMANDS.md](COMMANDS.md#base-de-données) - Maintenance
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : 12 janvier 2026
|
||||
|
||||
**Version de la documentation** : 1.0.0
|
||||
233
PROJECT_SUMMARY.md
Normal file
233
PROJECT_SUMMARY.md
Normal file
@@ -0,0 +1,233 @@
|
||||
# ✅ PROJET COMPLÉTÉ - TravelMate Admin
|
||||
|
||||
## 📋 Résumé
|
||||
|
||||
Application desktop .NET MAUI (Mac/Windows) avec architecture MVVM pour gérer les demandes clients depuis une base de données MariaDB/MySQL.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Ce qui a été créé
|
||||
|
||||
### 1. Structure MVVM Complète
|
||||
|
||||
#### **Models** (2 fichiers)
|
||||
- ✅ `Message.cs` - Modèle pour les messages de demande
|
||||
- ✅ `SupportRequest.cs` - Modèle pour les demandes support
|
||||
|
||||
#### **Services** (2 fichiers)
|
||||
- ✅ `IDatabaseService.cs` - Interface du service de base de données
|
||||
- ✅ `DatabaseService.cs` - Implémentation avec MySqlConnector
|
||||
- Connexion à MariaDB/MySQL
|
||||
- CRUD operations pour messages et support_requests
|
||||
- Gestion asynchrone complète
|
||||
|
||||
#### **ViewModels** (3 fichiers)
|
||||
- ✅ `DashboardViewModel.cs` - Gestion du tableau de bord
|
||||
- ✅ `MessagesViewModel.cs` - Gestion de la liste des messages
|
||||
- ✅ `SupportViewModel.cs` - Gestion des demandes support
|
||||
- Tous utilisent CommunityToolkit.Mvvm (ObservableProperty, RelayCommand)
|
||||
|
||||
#### **Views** (3 paires XAML + Code-behind)
|
||||
- ✅ `DashboardPage.xaml/.cs` - Tableau de bord avec statistiques
|
||||
- ✅ `MessagesPage.xaml/.cs` - Liste des messages avec filtres
|
||||
- ✅ `SupportPage.xaml/.cs` - Liste des demandes support
|
||||
|
||||
#### **Converters** (1 fichier)
|
||||
- ✅ `BoolConverters.cs` - Conversion bool → texte et couleur pour les boutons
|
||||
|
||||
#### **Configuration** (1 fichier)
|
||||
- ✅ `AppSettings.cs` - Configuration de la connexion DB
|
||||
|
||||
### 2. Configuration & Infrastructure
|
||||
|
||||
- ✅ `MauiProgram.cs` - Injection de dépendances configurée
|
||||
- ✅ `AppShell.xaml` - Navigation Shell avec 3 onglets
|
||||
- ✅ `TravelMateAdmin.csproj` - Packages NuGet ajoutés :
|
||||
- CommunityToolkit.Mvvm (8.3.2)
|
||||
- MySqlConnector (2.4.0)
|
||||
|
||||
### 3. Base de Données
|
||||
|
||||
- ✅ `database_setup.sql` - Script SQL complet :
|
||||
- Création de la base `travelmateadmin`
|
||||
- Table `messages` (8 colonnes)
|
||||
- Table `support_requests` (8 colonnes)
|
||||
- Données de test (4 messages + 4 demandes support)
|
||||
|
||||
### 4. Documentation
|
||||
|
||||
- ✅ `README.md` - Documentation complète du projet
|
||||
- ✅ `QUICKSTART.md` - Guide de démarrage rapide (5 minutes)
|
||||
- ✅ `CONFIGURATION.md` - Guide de configuration DB
|
||||
- ✅ `ARCHITECTURE.md` - Documentation architecture MVVM
|
||||
- ✅ `COMMANDS.md` - Commandes utiles pour le développement
|
||||
- ✅ `.gitignore` - Fichiers à ignorer dans Git
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Fonctionnalités Implémentées
|
||||
|
||||
### ✅ Dashboard
|
||||
- Affichage des statistiques en temps réel
|
||||
- 4 cartes : Messages (en attente/traités) + Support (en attente/traités)
|
||||
- Indicateur de statut de connexion
|
||||
- Bouton de rafraîchissement
|
||||
- Navigation vers les pages de détail
|
||||
|
||||
### ✅ Page Messages
|
||||
- Liste complète des messages avec scroll
|
||||
- Tri par date (plus récent en haut)
|
||||
- Filtre : Tout / À faire / Fait
|
||||
- Affichage : Nom, Prénom, Email, Message, Date, Statut
|
||||
- Bouton pour changer le statut (fait ↔ en attente)
|
||||
- Rafraîchissement manuel
|
||||
|
||||
### ✅ Page Support
|
||||
- Liste des demandes support
|
||||
- Même système de filtres que Messages
|
||||
- Affichage : Nom, Prénom, Account Email, Contact Email, Message, Date, Statut
|
||||
- Bouton pour changer le statut
|
||||
- Rafraîchissement manuel
|
||||
|
||||
### ✅ Design
|
||||
- **Dark theme** moderne et professionnel
|
||||
- Couleurs configurables (Primary, Accent, Success, Warning)
|
||||
- Cartes avec shadow et coins arrondis
|
||||
- Layout responsive
|
||||
- Indicateurs de chargement (ActivityIndicator)
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Technologies Utilisées
|
||||
|
||||
| Technologie | Version | Usage |
|
||||
|-------------|---------|-------|
|
||||
| .NET | 10.0 | Framework principal |
|
||||
| .NET MAUI | Dernière | UI multi-plateforme |
|
||||
| CommunityToolkit.Mvvm | 8.3.2 | Pattern MVVM |
|
||||
| MySqlConnector | 2.4.0 | Connexion MariaDB/MySQL |
|
||||
| XAML | - | Interface utilisateur |
|
||||
|
||||
---
|
||||
|
||||
## 📊 Structure du Projet
|
||||
|
||||
```
|
||||
TravelMateAdmin/
|
||||
├── TravelMateAdmin/ # Projet principal
|
||||
│ ├── Configuration/
|
||||
│ │ └── AppSettings.cs # Config DB
|
||||
│ ├── Converters/
|
||||
│ │ └── BoolConverters.cs # Converters XAML
|
||||
│ ├── Models/
|
||||
│ │ ├── Message.cs
|
||||
│ │ └── SupportRequest.cs
|
||||
│ ├── Services/
|
||||
│ │ ├── IDatabaseService.cs
|
||||
│ │ └── DatabaseService.cs
|
||||
│ ├── ViewModels/
|
||||
│ │ ├── DashboardViewModel.cs
|
||||
│ │ ├── MessagesViewModel.cs
|
||||
│ │ └── SupportViewModel.cs
|
||||
│ ├── Views/
|
||||
│ │ ├── DashboardPage.xaml/.cs
|
||||
│ │ ├── MessagesPage.xaml/.cs
|
||||
│ │ └── SupportPage.xaml/.cs
|
||||
│ ├── App.xaml/.cs
|
||||
│ ├── AppShell.xaml/.cs
|
||||
│ ├── MauiProgram.cs
|
||||
│ └── TravelMateAdmin.csproj
|
||||
├── database_setup.sql # Script SQL
|
||||
├── README.md # Documentation principale
|
||||
├── QUICKSTART.md # Guide rapide
|
||||
├── CONFIGURATION.md # Guide configuration
|
||||
├── ARCHITECTURE.md # Documentation architecture
|
||||
├── COMMANDS.md # Commandes utiles
|
||||
└── .gitignore # Git ignore
|
||||
|
||||
Total: 35+ fichiers créés/modifiés
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 État du Projet
|
||||
|
||||
### ✅ Complété (100%)
|
||||
|
||||
- [x] Architecture MVVM complète
|
||||
- [x] Modèles de données (Message, SupportRequest)
|
||||
- [x] Service de base de données avec toutes les méthodes
|
||||
- [x] ViewModels avec CommunityToolkit.Mvvm
|
||||
- [x] Vues XAML avec design moderne
|
||||
- [x] Converters pour l'affichage
|
||||
- [x] Injection de dépendances
|
||||
- [x] Navigation Shell
|
||||
- [x] Script SQL avec données de test
|
||||
- [x] Documentation complète
|
||||
- [x] Compilation réussie ✅
|
||||
|
||||
### ⏭️ Étapes Suivantes (Optionnel)
|
||||
|
||||
- [ ] Ajouter authentification utilisateur
|
||||
- [ ] Implémenter pagination pour grandes listes
|
||||
- [ ] Ajouter recherche/filtrage avancé
|
||||
- [ ] Exporter les données (CSV, PDF)
|
||||
- [ ] Notifications push
|
||||
- [ ] Tests unitaires
|
||||
- [ ] Mode light/dark configurable
|
||||
- [ ] Statistiques avancées (graphiques)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Pour Commencer
|
||||
|
||||
### Option 1 : Rapide (5 minutes)
|
||||
```bash
|
||||
# 1. Configurer la base de données
|
||||
mysql -u root -p < database_setup.sql
|
||||
|
||||
# 2. Modifier AppSettings.cs avec vos identifiants MySQL
|
||||
|
||||
# 3. Lancer l'app
|
||||
dotnet build -t:Run -f net10.0-maccatalyst # Mac
|
||||
# OU
|
||||
dotnet build -t:Run -f net10.0-windows10.0.19041.0 # Windows
|
||||
```
|
||||
|
||||
### Option 2 : Détaillée
|
||||
Consultez `QUICKSTART.md` pour un guide pas-à-pas complet.
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Points Clés de l'Architecture
|
||||
|
||||
1. **Séparation des responsabilités** : MVVM strict
|
||||
2. **Réactivité** : INotifyPropertyChanged automatique
|
||||
3. **Asynchrone** : Toutes les opérations DB sont async
|
||||
4. **Injection de dépendances** : Services injectés automatiquement
|
||||
5. **Testabilité** : Interface IDatabaseService mockable
|
||||
6. **Extensibilité** : Facile d'ajouter de nouvelles entités
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support
|
||||
|
||||
- **README.md** : Documentation générale
|
||||
- **QUICKSTART.md** : Installation rapide
|
||||
- **CONFIGURATION.md** : Problèmes de connexion DB
|
||||
- **ARCHITECTURE.md** : Comprendre le code
|
||||
- **COMMANDS.md** : Commandes de développement
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Félicitations !
|
||||
|
||||
Vous avez maintenant une application d'administration complète et professionnelle avec :
|
||||
- ✅ Code propre et bien structuré
|
||||
- ✅ Pattern MVVM moderne
|
||||
- ✅ Interface utilisateur intuitive
|
||||
- ✅ Base de données intégrée
|
||||
- ✅ Documentation exhaustive
|
||||
- ✅ Prête à être étendue
|
||||
|
||||
**Prochaine étape** : Lancez l'application et explorez les fonctionnalités ! 🚀
|
||||
123
QUICKSTART.md
Normal file
123
QUICKSTART.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# 🚀 Guide de Démarrage Rapide - TravelMate Admin
|
||||
|
||||
## Installation en 5 Minutes
|
||||
|
||||
### Étape 1 : Prérequis ✅
|
||||
|
||||
Installez si nécessaire :
|
||||
- [.NET 8+ SDK](https://dotnet.microsoft.com/download)
|
||||
- [MySQL/MariaDB](https://dev.mysql.com/downloads/) ou [MAMP](https://www.mamp.info/) (Mac) / [XAMPP](https://www.apachefriends.org/) (Windows)
|
||||
|
||||
### Étape 2 : Base de Données 🗄️
|
||||
|
||||
**Option A - Avec MySQL en ligne de commande :**
|
||||
```bash
|
||||
mysql -u root -p < database_setup.sql
|
||||
```
|
||||
|
||||
**Option B - Avec phpMyAdmin ou MySQL Workbench :**
|
||||
1. Créez une base de données nommée `travelmateadmin`
|
||||
2. Importez le fichier `database_setup.sql`
|
||||
|
||||
**Option C - Manuellement :**
|
||||
```sql
|
||||
CREATE DATABASE travelmateadmin;
|
||||
USE travelmateadmin;
|
||||
-- Puis copiez/collez le contenu de database_setup.sql
|
||||
```
|
||||
|
||||
### Étape 3 : Configuration ⚙️
|
||||
|
||||
Ouvrez `TravelMateAdmin/Configuration/AppSettings.cs` et modifiez :
|
||||
|
||||
```csharp
|
||||
public const string Server = "localhost"; // ✏️ Votre serveur
|
||||
public const string Port = "3306"; // ✏️ Votre port
|
||||
public const string Database = "travelmateadmin";
|
||||
public const string User = "root"; // ✏️ Votre utilisateur
|
||||
public const string Password = "VOTRE_MDP"; // ✏️ IMPORTANT: Changez ici !
|
||||
```
|
||||
|
||||
### Étape 4 : Restaurer les Packages 📦
|
||||
|
||||
```bash
|
||||
cd TravelMateAdmin
|
||||
dotnet restore
|
||||
```
|
||||
|
||||
### Étape 5 : Lancer l'Application 🎉
|
||||
|
||||
**Sur Mac :**
|
||||
```bash
|
||||
dotnet build -t:Run -f net10.0-maccatalyst
|
||||
```
|
||||
|
||||
**Sur Windows :**
|
||||
```bash
|
||||
dotnet build -t:Run -f net10.0-windows10.0.19041.0
|
||||
```
|
||||
|
||||
**Avec Visual Studio :**
|
||||
1. Ouvrez `TravelMateAdmin.sln`
|
||||
2. Sélectionnez la plateforme (Mac Catalyst ou Windows)
|
||||
3. Appuyez sur F5 ou cliquez sur ▶️ Run
|
||||
|
||||
---
|
||||
|
||||
## ✅ Vérification
|
||||
|
||||
Au lancement, vous devriez voir :
|
||||
- ✅ Dashboard avec les statistiques
|
||||
- ✅ "✓ Connecté" en haut à droite
|
||||
- ✅ 4 messages et 4 demandes support (données de test)
|
||||
|
||||
## ❌ Problèmes ?
|
||||
|
||||
### "✗ Déconnecté" s'affiche
|
||||
1. Vérifiez que MySQL est démarré
|
||||
2. Vérifiez vos paramètres dans `AppSettings.cs`
|
||||
3. Testez la connexion MySQL : `mysql -u root -p`
|
||||
|
||||
### Erreur "Cannot find project"
|
||||
```bash
|
||||
cd /Users/dayronvanleemput/Documents/Coding/TravelMateAdmin
|
||||
dotnet restore
|
||||
```
|
||||
|
||||
### Erreur de build
|
||||
```bash
|
||||
dotnet clean
|
||||
dotnet restore
|
||||
dotnet build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Prochaines Étapes
|
||||
|
||||
1. **Tester l'application** : Naviguez entre Dashboard, Messages et Support
|
||||
2. **Changer un statut** : Cliquez sur un bouton "Marquer comme fait"
|
||||
3. **Filtrer** : Utilisez le menu déroulant pour filtrer les demandes
|
||||
4. **Personnaliser** : Changez les couleurs dans les fichiers XAML
|
||||
5. **Ajouter des données** : Ajoutez vos propres demandes dans la base
|
||||
|
||||
## 🎨 Captures d'Écran des Fonctionnalités
|
||||
|
||||
### Dashboard
|
||||
- Vue d'ensemble des statistiques
|
||||
- Cartes cliquables pour accéder aux détails
|
||||
- Statut de connexion en temps réel
|
||||
|
||||
### Messages
|
||||
- Liste complète des messages
|
||||
- Filtre : Tout / À faire / Fait
|
||||
- Action : Marquer comme fait/en attente
|
||||
|
||||
### Support
|
||||
- Liste des demandes d'assistance
|
||||
- Affichage des emails (compte et contact)
|
||||
- Même système de filtres et actions
|
||||
|
||||
---
|
||||
|
||||
**Besoin d'aide ?** Consultez le [README.md](README.md) complet ou le guide de [CONFIGURATION.md](CONFIGURATION.md)
|
||||
433
SQL_REFERENCE.md
Normal file
433
SQL_REFERENCE.md
Normal file
@@ -0,0 +1,433 @@
|
||||
# 📊 SQL Queries Reference - TravelMate Admin
|
||||
|
||||
Requêtes SQL utiles pour gérer et interroger la base de données.
|
||||
|
||||
## 🔍 Requêtes de Consultation
|
||||
|
||||
### Messages
|
||||
|
||||
```sql
|
||||
-- Tous les messages
|
||||
SELECT * FROM messages ORDER BY created_at DESC;
|
||||
|
||||
-- Messages en attente uniquement
|
||||
SELECT * FROM messages WHERE done = FALSE ORDER BY created_at DESC;
|
||||
|
||||
-- Messages traités uniquement
|
||||
SELECT * FROM messages WHERE done = TRUE ORDER BY created_at DESC;
|
||||
|
||||
-- Compter les messages par statut
|
||||
SELECT
|
||||
COUNT(*) AS total,
|
||||
SUM(CASE WHEN done = FALSE THEN 1 ELSE 0 END) AS en_attente,
|
||||
SUM(CASE WHEN done = TRUE THEN 1 ELSE 0 END) AS traites
|
||||
FROM messages;
|
||||
|
||||
-- Messages récents (dernières 24h)
|
||||
SELECT * FROM messages
|
||||
WHERE created_at > NOW() - INTERVAL 24 HOUR
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- Messages d'un utilisateur spécifique
|
||||
SELECT * FROM messages
|
||||
WHERE email = 'jean.dupont@example.com'
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- Recherche dans les messages
|
||||
SELECT * FROM messages
|
||||
WHERE message LIKE '%RGPD%'
|
||||
OR nom LIKE '%Dupont%'
|
||||
ORDER BY created_at DESC;
|
||||
```
|
||||
|
||||
### Support Requests
|
||||
|
||||
```sql
|
||||
-- Toutes les demandes support
|
||||
SELECT * FROM support_requests ORDER BY created_at DESC;
|
||||
|
||||
-- Demandes en attente
|
||||
SELECT * FROM support_requests WHERE done = FALSE ORDER BY created_at DESC;
|
||||
|
||||
-- Demandes traitées
|
||||
SELECT * FROM support_requests WHERE done = TRUE ORDER BY created_at DESC;
|
||||
|
||||
-- Compter par statut
|
||||
SELECT
|
||||
COUNT(*) AS total,
|
||||
SUM(CASE WHEN done = FALSE THEN 1 ELSE 0 END) AS en_attente,
|
||||
SUM(CASE WHEN done = TRUE THEN 1 ELSE 0 END) AS traites
|
||||
FROM support_requests;
|
||||
|
||||
-- Demandes d'un compte spécifique
|
||||
SELECT * FROM support_requests
|
||||
WHERE account_email = 'lucas.petit@example.com'
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- Recherche par email de contact
|
||||
SELECT * FROM support_requests
|
||||
WHERE contact_email = 'lucas.contact@example.com'
|
||||
ORDER BY created_at DESC;
|
||||
```
|
||||
|
||||
### Statistiques Globales
|
||||
|
||||
```sql
|
||||
-- Vue d'ensemble complète
|
||||
SELECT
|
||||
'Messages' AS type,
|
||||
COUNT(*) AS total,
|
||||
SUM(CASE WHEN done = FALSE THEN 1 ELSE 0 END) AS en_attente,
|
||||
SUM(CASE WHEN done = TRUE THEN 1 ELSE 0 END) AS traites
|
||||
FROM messages
|
||||
UNION ALL
|
||||
SELECT
|
||||
'Support',
|
||||
COUNT(*),
|
||||
SUM(CASE WHEN done = FALSE THEN 1 ELSE 0 END),
|
||||
SUM(CASE WHEN done = TRUE THEN 1 ELSE 0 END)
|
||||
FROM support_requests;
|
||||
|
||||
-- Activité par jour (7 derniers jours)
|
||||
SELECT
|
||||
DATE(created_at) AS date,
|
||||
COUNT(*) AS messages
|
||||
FROM messages
|
||||
WHERE created_at > NOW() - INTERVAL 7 DAY
|
||||
GROUP BY DATE(created_at)
|
||||
ORDER BY date DESC;
|
||||
|
||||
-- Volume par heure de la journée
|
||||
SELECT
|
||||
HOUR(created_at) AS heure,
|
||||
COUNT(*) AS nombre_messages
|
||||
FROM messages
|
||||
GROUP BY HOUR(created_at)
|
||||
ORDER BY heure;
|
||||
```
|
||||
|
||||
## ✏️ Requêtes de Modification
|
||||
|
||||
### Changer le Statut
|
||||
|
||||
```sql
|
||||
-- Marquer un message comme traité
|
||||
UPDATE messages SET done = TRUE WHERE id = 1;
|
||||
|
||||
-- Marquer une demande support comme traitée
|
||||
UPDATE support_requests SET done = TRUE WHERE id = 1;
|
||||
|
||||
-- Marquer comme non traité
|
||||
UPDATE messages SET done = FALSE WHERE id = 1;
|
||||
|
||||
-- Marquer tous les messages en attente
|
||||
UPDATE messages SET done = FALSE;
|
||||
|
||||
-- Marquer tous comme traités
|
||||
UPDATE messages SET done = TRUE;
|
||||
|
||||
-- Marquer les vieux messages comme traités (plus de 30 jours)
|
||||
UPDATE messages
|
||||
SET done = TRUE
|
||||
WHERE created_at < NOW() - INTERVAL 30 DAY AND done = FALSE;
|
||||
```
|
||||
|
||||
### Ajouter des Données
|
||||
|
||||
```sql
|
||||
-- Nouveau message
|
||||
INSERT INTO messages (nom, prenom, email, message, done, created_at)
|
||||
VALUES (
|
||||
'Nouveau',
|
||||
'Test',
|
||||
'test@example.com',
|
||||
'Ceci est un nouveau message de test',
|
||||
FALSE,
|
||||
NOW()
|
||||
);
|
||||
|
||||
-- Nouvelle demande support
|
||||
INSERT INTO support_requests (nom, prenom, account_email, contact_email, message, done, created_at)
|
||||
VALUES (
|
||||
'Support',
|
||||
'Test',
|
||||
'account@example.com',
|
||||
'contact@example.com',
|
||||
'Problème de connexion',
|
||||
FALSE,
|
||||
NOW()
|
||||
);
|
||||
|
||||
-- Ajouter plusieurs messages en une fois
|
||||
INSERT INTO messages (nom, prenom, email, message, done, created_at) VALUES
|
||||
('User1', 'Test', 'user1@test.com', 'Message 1', FALSE, NOW()),
|
||||
('User2', 'Test', 'user2@test.com', 'Message 2', FALSE, NOW()),
|
||||
('User3', 'Test', 'user3@test.com', 'Message 3', FALSE, NOW());
|
||||
```
|
||||
|
||||
### Supprimer des Données
|
||||
|
||||
```sql
|
||||
-- Supprimer un message spécifique
|
||||
DELETE FROM messages WHERE id = 1;
|
||||
|
||||
-- Supprimer tous les messages traités
|
||||
DELETE FROM messages WHERE done = TRUE;
|
||||
|
||||
-- Supprimer les vieux messages (plus de 90 jours)
|
||||
DELETE FROM messages WHERE created_at < NOW() - INTERVAL 90 DAY;
|
||||
|
||||
-- Attention : Supprimer TOUTES les données
|
||||
-- DELETE FROM messages;
|
||||
-- DELETE FROM support_requests;
|
||||
```
|
||||
|
||||
## 🔧 Maintenance
|
||||
|
||||
### Optimisation
|
||||
|
||||
```sql
|
||||
-- Analyser les tables
|
||||
ANALYZE TABLE messages;
|
||||
ANALYZE TABLE support_requests;
|
||||
|
||||
-- Optimiser les tables
|
||||
OPTIMIZE TABLE messages;
|
||||
OPTIMIZE TABLE support_requests;
|
||||
|
||||
-- Vérifier l'état de la table
|
||||
CHECK TABLE messages;
|
||||
CHECK TABLE support_requests;
|
||||
|
||||
-- Réparer une table (si nécessaire)
|
||||
REPAIR TABLE messages;
|
||||
```
|
||||
|
||||
### Index
|
||||
|
||||
```sql
|
||||
-- Voir les index existants
|
||||
SHOW INDEX FROM messages;
|
||||
SHOW INDEX FROM support_requests;
|
||||
|
||||
-- Créer un index sur l'email (si performance lente)
|
||||
CREATE INDEX idx_messages_email ON messages(email);
|
||||
CREATE INDEX idx_support_account_email ON support_requests(account_email);
|
||||
|
||||
-- Supprimer un index
|
||||
DROP INDEX idx_messages_email ON messages;
|
||||
```
|
||||
|
||||
### Backup
|
||||
|
||||
```sql
|
||||
-- Exporter les données en SQL (en ligne de commande)
|
||||
-- mysqldump -u root -p travelmateadmin > backup.sql
|
||||
|
||||
-- Exporter uniquement les messages
|
||||
-- mysqldump -u root -p travelmateadmin messages > messages_backup.sql
|
||||
|
||||
-- Exporter sans données (structure seulement)
|
||||
-- mysqldump -u root -p --no-data travelmateadmin > structure.sql
|
||||
```
|
||||
|
||||
## 📊 Rapports et Analytics
|
||||
|
||||
### Analyse des Messages
|
||||
|
||||
```sql
|
||||
-- Messages les plus fréquents par email
|
||||
SELECT
|
||||
email,
|
||||
COUNT(*) AS nombre_messages,
|
||||
MAX(created_at) AS dernier_message
|
||||
FROM messages
|
||||
GROUP BY email
|
||||
ORDER BY nombre_messages DESC
|
||||
LIMIT 10;
|
||||
|
||||
-- Temps moyen de traitement
|
||||
SELECT
|
||||
AVG(TIMESTAMPDIFF(HOUR, created_at, NOW())) AS heures_moyennes
|
||||
FROM messages
|
||||
WHERE done = TRUE;
|
||||
|
||||
-- Messages par mois
|
||||
SELECT
|
||||
DATE_FORMAT(created_at, '%Y-%m') AS mois,
|
||||
COUNT(*) AS nombre
|
||||
FROM messages
|
||||
GROUP BY DATE_FORMAT(created_at, '%Y-%m')
|
||||
ORDER BY mois DESC;
|
||||
|
||||
-- Taux de complétion
|
||||
SELECT
|
||||
ROUND(SUM(done) / COUNT(*) * 100, 2) AS taux_completion_pourcent
|
||||
FROM messages;
|
||||
```
|
||||
|
||||
### Analyse du Support
|
||||
|
||||
```sql
|
||||
-- Problèmes les plus fréquents (par mots-clés)
|
||||
SELECT
|
||||
CASE
|
||||
WHEN message LIKE '%connexion%' THEN 'Connexion'
|
||||
WHEN message LIKE '%mot de passe%' THEN 'Mot de passe'
|
||||
WHEN message LIKE '%synchronisation%' THEN 'Synchronisation'
|
||||
WHEN message LIKE '%facturation%' THEN 'Facturation'
|
||||
ELSE 'Autre'
|
||||
END AS categorie,
|
||||
COUNT(*) AS nombre
|
||||
FROM support_requests
|
||||
GROUP BY categorie
|
||||
ORDER BY nombre DESC;
|
||||
|
||||
-- Utilisateurs avec plusieurs demandes
|
||||
SELECT
|
||||
account_email,
|
||||
COUNT(*) AS nombre_demandes,
|
||||
SUM(done) AS traitees,
|
||||
COUNT(*) - SUM(done) AS en_attente
|
||||
FROM support_requests
|
||||
GROUP BY account_email
|
||||
HAVING nombre_demandes > 1
|
||||
ORDER BY nombre_demandes DESC;
|
||||
```
|
||||
|
||||
## 🧪 Tests et Développement
|
||||
|
||||
### Générer des Données de Test
|
||||
|
||||
```sql
|
||||
-- Générer 50 messages aléatoires
|
||||
INSERT INTO messages (nom, prenom, email, message, done, created_at)
|
||||
SELECT
|
||||
CONCAT('Nom', n.n),
|
||||
CONCAT('Prenom', n.n),
|
||||
CONCAT('test', n.n, '@example.com'),
|
||||
CONCAT('Message de test numéro ', n.n),
|
||||
n.n % 3 = 0, -- Un tiers sera "done"
|
||||
NOW() - INTERVAL FLOOR(RAND() * 30) DAY
|
||||
FROM (
|
||||
SELECT @row := @row + 1 AS n
|
||||
FROM (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) t1,
|
||||
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) t2,
|
||||
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) t3,
|
||||
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) t4,
|
||||
(SELECT @row := 0) r
|
||||
LIMIT 50
|
||||
) n;
|
||||
```
|
||||
|
||||
### Réinitialiser pour les Tests
|
||||
|
||||
```sql
|
||||
-- Vider toutes les tables
|
||||
TRUNCATE TABLE messages;
|
||||
TRUNCATE TABLE support_requests;
|
||||
|
||||
-- Réinitialiser les auto-increment
|
||||
ALTER TABLE messages AUTO_INCREMENT = 1;
|
||||
ALTER TABLE support_requests AUTO_INCREMENT = 1;
|
||||
|
||||
-- Recréer les données de test
|
||||
SOURCE database_setup.sql;
|
||||
```
|
||||
|
||||
## 🔐 Sécurité et Utilisateurs
|
||||
|
||||
### Gestion des Utilisateurs
|
||||
|
||||
```sql
|
||||
-- Créer un utilisateur pour l'application
|
||||
CREATE USER 'travelmateapp'@'localhost' IDENTIFIED BY 'votre_mot_de_passe';
|
||||
|
||||
-- Donner les permissions nécessaires
|
||||
GRANT SELECT, INSERT, UPDATE ON travelmateadmin.* TO 'travelmateapp'@'localhost';
|
||||
|
||||
-- Ne PAS donner DELETE en production pour la sécurité
|
||||
-- GRANT DELETE ON travelmateadmin.* TO 'travelmateapp'@'localhost';
|
||||
|
||||
-- Appliquer les changements
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
-- Voir les permissions d'un utilisateur
|
||||
SHOW GRANTS FOR 'travelmateapp'@'localhost';
|
||||
|
||||
-- Révoquer une permission
|
||||
REVOKE DELETE ON travelmateadmin.* FROM 'travelmateapp'@'localhost';
|
||||
|
||||
-- Supprimer un utilisateur
|
||||
DROP USER 'travelmateapp'@'localhost';
|
||||
```
|
||||
|
||||
## 📝 Informations sur la Base
|
||||
|
||||
```sql
|
||||
-- Voir toutes les bases de données
|
||||
SHOW DATABASES;
|
||||
|
||||
-- Utiliser la base TravelMate
|
||||
USE travelmateadmin;
|
||||
|
||||
-- Voir toutes les tables
|
||||
SHOW TABLES;
|
||||
|
||||
-- Voir la structure d'une table
|
||||
DESCRIBE messages;
|
||||
DESCRIBE support_requests;
|
||||
|
||||
-- Voir le CREATE TABLE original
|
||||
SHOW CREATE TABLE messages;
|
||||
|
||||
-- Taille de la base de données
|
||||
SELECT
|
||||
table_schema AS 'Database',
|
||||
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)'
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'travelmateadmin';
|
||||
|
||||
-- Nombre de lignes par table
|
||||
SELECT
|
||||
TABLE_NAME,
|
||||
TABLE_ROWS
|
||||
FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA = 'travelmateadmin';
|
||||
```
|
||||
|
||||
## 🚨 Dépannage
|
||||
|
||||
```sql
|
||||
-- Vérifier les connexions actives
|
||||
SHOW PROCESSLIST;
|
||||
|
||||
-- Tuer une connexion bloquée (remplacer X par l'ID)
|
||||
-- KILL X;
|
||||
|
||||
-- Voir les variables MySQL
|
||||
SHOW VARIABLES LIKE 'max_connections';
|
||||
SHOW VARIABLES LIKE 'wait_timeout';
|
||||
|
||||
-- Voir le statut du serveur
|
||||
SHOW STATUS;
|
||||
|
||||
-- Voir les erreurs récentes
|
||||
SHOW WARNINGS;
|
||||
SHOW ERRORS;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips
|
||||
|
||||
- Toujours tester vos requêtes DELETE/UPDATE avec SELECT d'abord
|
||||
- Faites des backups avant toute modification importante
|
||||
- Utilisez LIMIT dans vos requêtes de test
|
||||
- Les index améliorent les performances SELECT mais ralentissent INSERT/UPDATE
|
||||
- Utilisez EXPLAIN pour analyser les performances des requêtes
|
||||
|
||||
```sql
|
||||
-- Exemple d'analyse de performance
|
||||
EXPLAIN SELECT * FROM messages WHERE done = FALSE ORDER BY created_at DESC;
|
||||
```
|
||||
34
TravelMateAdmin.sln
Normal file
34
TravelMateAdmin.sln
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TravelMateAdmin", "TravelMateAdmin\TravelMateAdmin.csproj", "{760FF747-775F-4B67-A507-584C1D43D88E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{760FF747-775F-4B67-A507-584C1D43D88E}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
14
TravelMateAdmin/App.xaml
Normal file
14
TravelMateAdmin/App.xaml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version = "1.0" encoding = "UTF-8" ?>
|
||||
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:local="clr-namespace:TravelMateAdmin"
|
||||
x:Class="TravelMateAdmin.App">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
|
||||
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
16
TravelMateAdmin/App.xaml.cs
Normal file
16
TravelMateAdmin/App.xaml.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace TravelMateAdmin;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
public App()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override Window CreateWindow(IActivationState? activationState)
|
||||
{
|
||||
return new Window(new AppShell());
|
||||
}
|
||||
}
|
||||
44
TravelMateAdmin/AppShell.xaml
Normal file
44
TravelMateAdmin/AppShell.xaml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<Shell
|
||||
x:Class="TravelMateAdmin.AppShell"
|
||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:views="clr-namespace:TravelMateAdmin.Views"
|
||||
Title="TravelMate Admin"
|
||||
Shell.FlyoutBehavior="Flyout">
|
||||
|
||||
<Shell.Resources>
|
||||
<ResourceDictionary>
|
||||
<Color x:Key="Primary">#1a1a1a</Color>
|
||||
<Color x:Key="Accent">#5E50D9</Color>
|
||||
<Style TargetType="TabBar" ApplyToDerivedTypes="True">
|
||||
<Setter Property="Shell.TabBarBackgroundColor" Value="{StaticResource Primary}" />
|
||||
<Setter Property="Shell.TabBarForegroundColor" Value="{StaticResource Accent}" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Shell.Resources>
|
||||
|
||||
<!-- Dashboard -->
|
||||
<TabBar>
|
||||
<ShellContent
|
||||
Title="Dashboard"
|
||||
Icon="home"
|
||||
ContentTemplate="{DataTemplate views:DashboardPage}"
|
||||
Route="DashboardPage" />
|
||||
|
||||
<!-- Messages -->
|
||||
<ShellContent
|
||||
Title="Messages"
|
||||
Icon="mail"
|
||||
ContentTemplate="{DataTemplate views:MessagesPage}"
|
||||
Route="MessagesPage" />
|
||||
|
||||
<!-- Support -->
|
||||
<ShellContent
|
||||
Title="Support"
|
||||
Icon="help"
|
||||
ContentTemplate="{DataTemplate views:SupportPage}"
|
||||
Route="SupportPage" />
|
||||
</TabBar>
|
||||
|
||||
</Shell>
|
||||
9
TravelMateAdmin/AppShell.xaml.cs
Normal file
9
TravelMateAdmin/AppShell.xaml.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace TravelMateAdmin;
|
||||
|
||||
public partial class AppShell : Shell
|
||||
{
|
||||
public AppShell()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
17
TravelMateAdmin/Configuration/AppSettings.cs
Normal file
17
TravelMateAdmin/Configuration/AppSettings.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace TravelMateAdmin.Configuration;
|
||||
|
||||
public static class AppSettings
|
||||
{
|
||||
// Configuration de la base de données
|
||||
// Modifiez ces valeurs selon votre environnement
|
||||
public const string Server = "localhost";
|
||||
public const string Port = "3306";
|
||||
public const string Database = "travelmateadmin";
|
||||
public const string User = "root";
|
||||
public const string Password = "yourpassword";
|
||||
|
||||
public static string GetConnectionString()
|
||||
{
|
||||
return $"Server={Server};Port={Port};Database={Database};User={User};Password={Password};";
|
||||
}
|
||||
}
|
||||
37
TravelMateAdmin/Converters/BoolConverters.cs
Normal file
37
TravelMateAdmin/Converters/BoolConverters.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace TravelMateAdmin.Converters;
|
||||
|
||||
public class BoolToStatusTextConverter : IValueConverter
|
||||
{
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool isDone)
|
||||
{
|
||||
return isDone ? "Marquer en attente" : "Marquer comme fait";
|
||||
}
|
||||
return "Changer statut";
|
||||
}
|
||||
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class BoolToColorConverter : IValueConverter
|
||||
{
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool isDone)
|
||||
{
|
||||
return isDone ? Color.FromArgb("#FFA726") : Color.FromArgb("#4CAF50");
|
||||
}
|
||||
return Color.FromArgb("#5E50D9");
|
||||
}
|
||||
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
36
TravelMateAdmin/MainPage.xaml
Normal file
36
TravelMateAdmin/MainPage.xaml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="TravelMateAdmin.MainPage">
|
||||
|
||||
<ScrollView>
|
||||
<VerticalStackLayout
|
||||
Padding="30,0"
|
||||
Spacing="25">
|
||||
<Image
|
||||
Source="dotnet_bot.png"
|
||||
HeightRequest="185"
|
||||
Aspect="AspectFit"
|
||||
SemanticProperties.Description="dot net bot in a submarine number ten" />
|
||||
|
||||
<Label
|
||||
Text="Hello, World!"
|
||||
Style="{StaticResource Headline}"
|
||||
SemanticProperties.HeadingLevel="Level1" />
|
||||
|
||||
<Label
|
||||
Text="Welcome to .NET Multi-platform App UI"
|
||||
Style="{StaticResource SubHeadline}"
|
||||
SemanticProperties.HeadingLevel="Level2"
|
||||
SemanticProperties.Description="Welcome to dot net Multi platform App U I" />
|
||||
|
||||
<Button
|
||||
x:Name="CounterBtn"
|
||||
Text="Click me"
|
||||
SemanticProperties.Hint="Counts the number of times you click"
|
||||
Clicked="OnCounterClicked"
|
||||
HorizontalOptions="Fill" />
|
||||
</VerticalStackLayout>
|
||||
</ScrollView>
|
||||
|
||||
</ContentPage>
|
||||
23
TravelMateAdmin/MainPage.xaml.cs
Normal file
23
TravelMateAdmin/MainPage.xaml.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace TravelMateAdmin;
|
||||
|
||||
public partial class MainPage : ContentPage
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnCounterClicked(object? sender, EventArgs e)
|
||||
{
|
||||
count++;
|
||||
|
||||
if (count == 1)
|
||||
CounterBtn.Text = $"Clicked {count} time";
|
||||
else
|
||||
CounterBtn.Text = $"Clicked {count} times";
|
||||
|
||||
SemanticScreenReader.Announce(CounterBtn.Text);
|
||||
}
|
||||
}
|
||||
40
TravelMateAdmin/MauiProgram.cs
Normal file
40
TravelMateAdmin/MauiProgram.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TravelMateAdmin.Services;
|
||||
using TravelMateAdmin.ViewModels;
|
||||
using TravelMateAdmin.Views;
|
||||
|
||||
namespace TravelMateAdmin;
|
||||
|
||||
public static class MauiProgram
|
||||
{
|
||||
public static MauiApp CreateMauiApp()
|
||||
{
|
||||
var builder = MauiApp.CreateBuilder();
|
||||
builder
|
||||
.UseMauiApp<App>()
|
||||
.ConfigureFonts(fonts =>
|
||||
{
|
||||
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
|
||||
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
|
||||
});
|
||||
|
||||
#if DEBUG
|
||||
builder.Logging.AddDebug();
|
||||
#endif
|
||||
|
||||
// Register Services
|
||||
builder.Services.AddSingleton<IDatabaseService, DatabaseService>();
|
||||
|
||||
// Register ViewModels
|
||||
builder.Services.AddSingleton<DashboardViewModel>();
|
||||
builder.Services.AddTransient<MessagesViewModel>();
|
||||
builder.Services.AddTransient<SupportViewModel>();
|
||||
|
||||
// Register Views
|
||||
builder.Services.AddSingleton<DashboardPage>();
|
||||
builder.Services.AddTransient<MessagesPage>();
|
||||
builder.Services.AddTransient<SupportPage>();
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
16
TravelMateAdmin/Models/Message.cs
Normal file
16
TravelMateAdmin/Models/Message.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace TravelMateAdmin.Models;
|
||||
|
||||
public class Message
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Nom { get; set; } = string.Empty;
|
||||
public string Prenom { get; set; } = string.Empty;
|
||||
public string Email { get; set; } = string.Empty;
|
||||
public string MessageText { get; set; } = string.Empty;
|
||||
public bool Done { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
public string FullName => $"{Prenom} {Nom}";
|
||||
public string StatusText => Done ? "Traité" : "En attente";
|
||||
public string CreatedAtFormatted => CreatedAt.ToString("dd/MM/yyyy HH:mm");
|
||||
}
|
||||
17
TravelMateAdmin/Models/SupportRequest.cs
Normal file
17
TravelMateAdmin/Models/SupportRequest.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace TravelMateAdmin.Models;
|
||||
|
||||
public class SupportRequest
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Nom { get; set; } = string.Empty;
|
||||
public string Prenom { get; set; } = string.Empty;
|
||||
public string AccountEmail { get; set; } = string.Empty;
|
||||
public string ContactEmail { get; set; } = string.Empty;
|
||||
public string MessageText { get; set; } = string.Empty;
|
||||
public bool Done { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
public string FullName => $"{Prenom} {Nom}";
|
||||
public string StatusText => Done ? "Traité" : "En attente";
|
||||
public string CreatedAtFormatted => CreatedAt.ToString("dd/MM/yyyy HH:mm");
|
||||
}
|
||||
6
TravelMateAdmin/Platforms/Android/AndroidManifest.xml
Normal file
6
TravelMateAdmin/Platforms/Android/AndroidManifest.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
</manifest>
|
||||
10
TravelMateAdmin/Platforms/Android/MainActivity.cs
Normal file
10
TravelMateAdmin/Platforms/Android/MainActivity.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Android.App;
|
||||
using Android.Content.PM;
|
||||
using Android.OS;
|
||||
|
||||
namespace TravelMateAdmin;
|
||||
|
||||
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
|
||||
public class MainActivity : MauiAppCompatActivity
|
||||
{
|
||||
}
|
||||
15
TravelMateAdmin/Platforms/Android/MainApplication.cs
Normal file
15
TravelMateAdmin/Platforms/Android/MainApplication.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Android.App;
|
||||
using Android.Runtime;
|
||||
|
||||
namespace TravelMateAdmin;
|
||||
|
||||
[Application]
|
||||
public class MainApplication : MauiApplication
|
||||
{
|
||||
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
|
||||
: base(handle, ownership)
|
||||
{
|
||||
}
|
||||
|
||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#512BD4</color>
|
||||
<color name="colorPrimaryDark">#2B0B98</color>
|
||||
<color name="colorAccent">#2B0B98</color>
|
||||
</resources>
|
||||
9
TravelMateAdmin/Platforms/MacCatalyst/AppDelegate.cs
Normal file
9
TravelMateAdmin/Platforms/MacCatalyst/AppDelegate.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Foundation;
|
||||
|
||||
namespace TravelMateAdmin;
|
||||
|
||||
[Register("AppDelegate")]
|
||||
public class AppDelegate : MauiUIApplicationDelegate
|
||||
{
|
||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
||||
}
|
||||
14
TravelMateAdmin/Platforms/MacCatalyst/Entitlements.plist
Normal file
14
TravelMateAdmin/Platforms/MacCatalyst/Entitlements.plist
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<!-- See https://aka.ms/maui-publish-app-store#add-entitlements for more information about adding entitlements.-->
|
||||
<dict>
|
||||
<!-- App Sandbox must be enabled to distribute a MacCatalyst app through the Mac App Store. -->
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<!-- When App Sandbox is enabled, this value is required to open outgoing network connections. -->
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
40
TravelMateAdmin/Platforms/MacCatalyst/Info.plist
Normal file
40
TravelMateAdmin/Platforms/MacCatalyst/Info.plist
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!-- The Mac App Store requires you specify if the app uses encryption. -->
|
||||
<!-- Please consult https://developer.apple.com/documentation/bundleresources/information_property_list/itsappusesnonexemptencryption -->
|
||||
<!-- <key>ITSAppUsesNonExemptEncryption</key> -->
|
||||
<!-- Please indicate <true/> or <false/> here. -->
|
||||
|
||||
<!-- Specify the category for your app here. -->
|
||||
<!-- Please consult https://developer.apple.com/documentation/bundleresources/information_property_list/lsapplicationcategorytype -->
|
||||
<!-- <key>LSApplicationCategoryType</key> -->
|
||||
<!-- <string>public.app-category.YOUR-CATEGORY-HERE</string> -->
|
||||
<key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>2</integer>
|
||||
</array>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.lifestyle</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>XSAppIconAssets</key>
|
||||
<string>Assets.xcassets/appicon.appiconset</string>
|
||||
</dict>
|
||||
</plist>
|
||||
15
TravelMateAdmin/Platforms/MacCatalyst/Program.cs
Normal file
15
TravelMateAdmin/Platforms/MacCatalyst/Program.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using ObjCRuntime;
|
||||
using UIKit;
|
||||
|
||||
namespace TravelMateAdmin;
|
||||
|
||||
public class Program
|
||||
{
|
||||
// This is the main entry point of the application.
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// if you want to use a different Application Delegate class from "AppDelegate"
|
||||
// you can specify it here.
|
||||
UIApplication.Main(args, null, typeof(AppDelegate));
|
||||
}
|
||||
}
|
||||
8
TravelMateAdmin/Platforms/Windows/App.xaml
Normal file
8
TravelMateAdmin/Platforms/Windows/App.xaml
Normal file
@@ -0,0 +1,8 @@
|
||||
<maui:MauiWinUIApplication
|
||||
x:Class="TravelMateAdmin.WinUI.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:maui="using:Microsoft.Maui"
|
||||
xmlns:local="using:TravelMateAdmin.WinUI">
|
||||
|
||||
</maui:MauiWinUIApplication>
|
||||
24
TravelMateAdmin/Platforms/Windows/App.xaml.cs
Normal file
24
TravelMateAdmin/Platforms/Windows/App.xaml.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace TravelMateAdmin.WinUI;
|
||||
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
public partial class App : MauiWinUIApplication
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
||||
}
|
||||
|
||||
46
TravelMateAdmin/Platforms/Windows/Package.appxmanifest
Normal file
46
TravelMateAdmin/Platforms/Windows/Package.appxmanifest
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap rescap">
|
||||
|
||||
<Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="DF9B5AEA-A739-4C2A-8B2A-7275B002DFE5" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>$placeholder$</DisplayName>
|
||||
<PublisherDisplayName>User Name</PublisherDisplayName>
|
||||
<Logo>$placeholder$.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate" />
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="$placeholder$"
|
||||
Description="$placeholder$"
|
||||
Square150x150Logo="$placeholder$.png"
|
||||
Square44x44Logo="$placeholder$.png"
|
||||
BackgroundColor="transparent">
|
||||
<uap:DefaultTile Square71x71Logo="$placeholder$.png" Wide310x150Logo="$placeholder$.png" Square310x310Logo="$placeholder$.png" />
|
||||
<uap:SplashScreen Image="$placeholder$.png" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
|
||||
</Package>
|
||||
17
TravelMateAdmin/Platforms/Windows/app.manifest
Normal file
17
TravelMateAdmin/Platforms/Windows/app.manifest
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="TravelMateAdmin.WinUI.app"/>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<!-- The combination of below two tags have the following effect:
|
||||
1) Per-Monitor for >= Windows 10 Anniversary Update
|
||||
2) System < Windows 10 Anniversary Update
|
||||
-->
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
|
||||
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
9
TravelMateAdmin/Platforms/iOS/AppDelegate.cs
Normal file
9
TravelMateAdmin/Platforms/iOS/AppDelegate.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Foundation;
|
||||
|
||||
namespace TravelMateAdmin;
|
||||
|
||||
[Register("AppDelegate")]
|
||||
public class AppDelegate : MauiUIApplicationDelegate
|
||||
{
|
||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
||||
}
|
||||
32
TravelMateAdmin/Platforms/iOS/Info.plist
Normal file
32
TravelMateAdmin/Platforms/iOS/Info.plist
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>1</integer>
|
||||
<integer>2</integer>
|
||||
</array>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>XSAppIconAssets</key>
|
||||
<string>Assets.xcassets/appicon.appiconset</string>
|
||||
</dict>
|
||||
</plist>
|
||||
15
TravelMateAdmin/Platforms/iOS/Program.cs
Normal file
15
TravelMateAdmin/Platforms/iOS/Program.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using ObjCRuntime;
|
||||
using UIKit;
|
||||
|
||||
namespace TravelMateAdmin;
|
||||
|
||||
public class Program
|
||||
{
|
||||
// This is the main entry point of the application.
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// if you want to use a different Application Delegate class from "AppDelegate"
|
||||
// you can specify it here.
|
||||
UIApplication.Main(args, null, typeof(AppDelegate));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
This is the minimum required version of the Apple Privacy Manifest for .NET MAUI apps.
|
||||
The contents below are needed because of APIs that are used in the .NET framework and .NET MAUI SDK.
|
||||
|
||||
You are responsible for adding extra entries as needed for your application.
|
||||
|
||||
More information: https://aka.ms/maui-privacy-manifest
|
||||
-->
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>C617.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>35F9.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>E174.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<!--
|
||||
The entry below is only needed when you're using the Preferences API in your app.
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>CA92.1</string>
|
||||
</array>
|
||||
</dict> -->
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
8
TravelMateAdmin/Properties/launchSettings.json
Normal file
8
TravelMateAdmin/Properties/launchSettings.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Windows Machine": {
|
||||
"commandName": "Project",
|
||||
"nativeDebugging": false
|
||||
}
|
||||
}
|
||||
}
|
||||
4
TravelMateAdmin/Resources/AppIcon/appicon.svg
Normal file
4
TravelMateAdmin/Resources/AppIcon/appicon.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0" y="0" width="456" height="456" fill="#512BD4" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 231 B |
8
TravelMateAdmin/Resources/AppIcon/appiconfg.svg
Normal file
8
TravelMateAdmin/Resources/AppIcon/appiconfg.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<path d="m 105.50037,281.60863 c -2.70293,0 -5.00091,-0.90042 -6.893127,-2.70209 -1.892214,-1.84778 -2.837901,-4.04181 -2.837901,-6.58209 0,-2.58722 0.945687,-4.80389 2.837901,-6.65167 1.892217,-1.84778 4.190197,-2.77167 6.893127,-2.77167 2.74819,0 5.06798,0.92389 6.96019,2.77167 1.93749,1.84778 2.90581,4.06445 2.90581,6.65167 0,2.54028 -0.96832,4.73431 -2.90581,6.58209 -1.89221,1.80167 -4.212,2.70209 -6.96019,2.70209 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
<path d="M 213.56111,280.08446 H 195.99044 L 149.69953,207.0544 c -1.17121,-1.84778 -2.14037,-3.76515 -2.90581,-5.75126 h -0.40578 c 0.36051,2.12528 0.54076,6.67515 0.54076,13.6496 v 65.13172 h -15.54349 v -99.36009 h 18.71925 l 44.7374,71.29798 c 1.89222,2.95695 3.1087,4.98917 3.64945,6.09751 h 0.26996 c -0.45021,-2.6325 -0.67573,-7.09015 -0.67573,-13.37293 v -64.02256 h 15.47557 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
<path d="m 289.25134,280.08446 h -54.40052 v -99.36009 h 52.23835 v 13.99669 h -36.15411 v 28.13085 h 33.31621 v 13.9271 h -33.31621 v 29.37835 h 38.31628 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
<path d="M 366.56466,194.72106 H 338.7222 v 85.3634 h -16.08423 v -85.3634 h -27.77455 v -13.99669 h 71.70124 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
BIN
TravelMateAdmin/Resources/Fonts/OpenSans-Regular.ttf
Normal file
BIN
TravelMateAdmin/Resources/Fonts/OpenSans-Regular.ttf
Normal file
Binary file not shown.
BIN
TravelMateAdmin/Resources/Fonts/OpenSans-Semibold.ttf
Normal file
BIN
TravelMateAdmin/Resources/Fonts/OpenSans-Semibold.ttf
Normal file
Binary file not shown.
BIN
TravelMateAdmin/Resources/Images/dotnet_bot.png
Normal file
BIN
TravelMateAdmin/Resources/Images/dotnet_bot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
15
TravelMateAdmin/Resources/Raw/AboutAssets.txt
Normal file
15
TravelMateAdmin/Resources/Raw/AboutAssets.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
Any raw assets you want to be deployed with your application can be placed in
|
||||
this directory (and child directories). Deployment of the asset to your application
|
||||
is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
|
||||
|
||||
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
|
||||
These files will be deployed with your package and will be accessible using Essentials:
|
||||
|
||||
async Task LoadMauiAsset()
|
||||
{
|
||||
using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
|
||||
using var reader = new StreamReader(stream);
|
||||
|
||||
var contents = reader.ReadToEnd();
|
||||
}
|
||||
8
TravelMateAdmin/Resources/Splash/splash.svg
Normal file
8
TravelMateAdmin/Resources/Splash/splash.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<path d="m 105.50037,281.60863 c -2.70293,0 -5.00091,-0.90042 -6.893127,-2.70209 -1.892214,-1.84778 -2.837901,-4.04181 -2.837901,-6.58209 0,-2.58722 0.945687,-4.80389 2.837901,-6.65167 1.892217,-1.84778 4.190197,-2.77167 6.893127,-2.77167 2.74819,0 5.06798,0.92389 6.96019,2.77167 1.93749,1.84778 2.90581,4.06445 2.90581,6.65167 0,2.54028 -0.96832,4.73431 -2.90581,6.58209 -1.89221,1.80167 -4.212,2.70209 -6.96019,2.70209 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
<path d="M 213.56111,280.08446 H 195.99044 L 149.69953,207.0544 c -1.17121,-1.84778 -2.14037,-3.76515 -2.90581,-5.75126 h -0.40578 c 0.36051,2.12528 0.54076,6.67515 0.54076,13.6496 v 65.13172 h -15.54349 v -99.36009 h 18.71925 l 44.7374,71.29798 c 1.89222,2.95695 3.1087,4.98917 3.64945,6.09751 h 0.26996 c -0.45021,-2.6325 -0.67573,-7.09015 -0.67573,-13.37293 v -64.02256 h 15.47557 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
<path d="m 289.25134,280.08446 h -54.40052 v -99.36009 h 52.23835 v 13.99669 h -36.15411 v 28.13085 h 33.31621 v 13.9271 h -33.31621 v 29.37835 h 38.31628 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
<path d="M 366.56466,194.72106 H 338.7222 v 85.3634 h -16.08423 v -85.3634 h -27.77455 v -13.99669 h 71.70124 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
44
TravelMateAdmin/Resources/Styles/Colors.xaml
Normal file
44
TravelMateAdmin/Resources/Styles/Colors.xaml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
|
||||
|
||||
<!-- Note: For Android please see also Platforms\Android\Resources\values\colors.xml -->
|
||||
|
||||
<Color x:Key="Primary">#512BD4</Color>
|
||||
<Color x:Key="PrimaryDark">#ac99ea</Color>
|
||||
<Color x:Key="PrimaryDarkText">#242424</Color>
|
||||
<Color x:Key="Secondary">#DFD8F7</Color>
|
||||
<Color x:Key="SecondaryDarkText">#9880e5</Color>
|
||||
<Color x:Key="Tertiary">#2B0B98</Color>
|
||||
|
||||
<Color x:Key="White">White</Color>
|
||||
<Color x:Key="Black">Black</Color>
|
||||
<Color x:Key="Magenta">#D600AA</Color>
|
||||
<Color x:Key="MidnightBlue">#190649</Color>
|
||||
<Color x:Key="OffBlack">#1f1f1f</Color>
|
||||
|
||||
<Color x:Key="Gray100">#E1E1E1</Color>
|
||||
<Color x:Key="Gray200">#C8C8C8</Color>
|
||||
<Color x:Key="Gray300">#ACACAC</Color>
|
||||
<Color x:Key="Gray400">#919191</Color>
|
||||
<Color x:Key="Gray500">#6E6E6E</Color>
|
||||
<Color x:Key="Gray600">#404040</Color>
|
||||
<Color x:Key="Gray900">#212121</Color>
|
||||
<Color x:Key="Gray950">#141414</Color>
|
||||
|
||||
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}"/>
|
||||
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}"/>
|
||||
<SolidColorBrush x:Key="TertiaryBrush" Color="{StaticResource Tertiary}"/>
|
||||
<SolidColorBrush x:Key="WhiteBrush" Color="{StaticResource White}"/>
|
||||
<SolidColorBrush x:Key="BlackBrush" Color="{StaticResource Black}"/>
|
||||
|
||||
<SolidColorBrush x:Key="Gray100Brush" Color="{StaticResource Gray100}"/>
|
||||
<SolidColorBrush x:Key="Gray200Brush" Color="{StaticResource Gray200}"/>
|
||||
<SolidColorBrush x:Key="Gray300Brush" Color="{StaticResource Gray300}"/>
|
||||
<SolidColorBrush x:Key="Gray400Brush" Color="{StaticResource Gray400}"/>
|
||||
<SolidColorBrush x:Key="Gray500Brush" Color="{StaticResource Gray500}"/>
|
||||
<SolidColorBrush x:Key="Gray600Brush" Color="{StaticResource Gray600}"/>
|
||||
<SolidColorBrush x:Key="Gray900Brush" Color="{StaticResource Gray900}"/>
|
||||
<SolidColorBrush x:Key="Gray950Brush" Color="{StaticResource Gray950}"/>
|
||||
</ResourceDictionary>
|
||||
434
TravelMateAdmin/Resources/Styles/Styles.xaml
Normal file
434
TravelMateAdmin/Resources/Styles/Styles.xaml
Normal file
@@ -0,0 +1,434 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
|
||||
|
||||
<Style TargetType="ActivityIndicator">
|
||||
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="IndicatorView">
|
||||
<Setter Property="IndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}"/>
|
||||
<Setter Property="SelectedIndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray100}}"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Stroke" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
||||
<Setter Property="StrokeShape" Value="Rectangle"/>
|
||||
<Setter Property="StrokeThickness" Value="1"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="BoxView">
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource PrimaryDarkText}}" />
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource PrimaryDark}}" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="BorderWidth" Value="0"/>
|
||||
<Setter Property="CornerRadius" Value="8"/>
|
||||
<Setter Property="Padding" Value="14,10"/>
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="PointerOver" />
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="CheckBox">
|
||||
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="DatePicker">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Editor">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Entry">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="ImageButton">
|
||||
<Setter Property="Opacity" Value="1" />
|
||||
<Setter Property="BorderColor" Value="Transparent"/>
|
||||
<Setter Property="BorderWidth" Value="0"/>
|
||||
<Setter Property="CornerRadius" Value="0"/>
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="Opacity" Value="0.5" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="PointerOver" />
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Label" x:Key="Headline">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource MidnightBlue}, Dark={StaticResource White}}" />
|
||||
<Setter Property="FontSize" Value="32" />
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="HorizontalTextAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Label" x:Key="SubHeadline">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource MidnightBlue}, Dark={StaticResource White}}" />
|
||||
<Setter Property="FontSize" Value="24" />
|
||||
<Setter Property="HorizontalOptions" Value="Center" />
|
||||
<Setter Property="HorizontalTextAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Picker">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
||||
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="ProgressBar">
|
||||
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="RadioButton">
|
||||
<Setter Property="BackgroundColor" Value="Transparent"/>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="RefreshView">
|
||||
<Setter Property="RefreshColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="SearchBar">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
||||
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
|
||||
<Setter Property="CancelButtonColor" Value="{StaticResource Gray500}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="SearchHandler">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
||||
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Shadow">
|
||||
<Setter Property="Radius" Value="15" />
|
||||
<Setter Property="Opacity" Value="0.5" />
|
||||
<Setter Property="Brush" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource White}}" />
|
||||
<Setter Property="Offset" Value="10,10" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Slider">
|
||||
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
|
||||
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
|
||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="SwipeItem">
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Switch">
|
||||
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
<Setter Property="ThumbColor" Value="{StaticResource White}" />
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="On">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Secondary}, Dark={StaticResource Gray200}}" />
|
||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Off">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TimePicker">
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
||||
<Setter Property="BackgroundColor" Value="Transparent"/>
|
||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!--
|
||||
<Style TargetType="TitleBar">
|
||||
<Setter Property="MinimumHeightRequest" Value="32"/>
|
||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
||||
<VisualStateGroupList>
|
||||
<VisualStateGroup x:Name="TitleActiveStates">
|
||||
<VisualState x:Name="TitleBarTitleActive">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="ForegroundColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="TitleBarTitleInactive">
|
||||
<VisualState.Setters>
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
|
||||
<Setter Property="ForegroundColor" Value="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateGroupList>
|
||||
</Setter>
|
||||
</Style>
|
||||
-->
|
||||
|
||||
<Style TargetType="Page" ApplyToDerivedTypes="True">
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Shell" ApplyToDerivedTypes="True">
|
||||
<Setter Property="Shell.BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
|
||||
<Setter Property="Shell.ForegroundColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
|
||||
<Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
|
||||
<Setter Property="Shell.DisabledColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
|
||||
<Setter Property="Shell.UnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray200}}" />
|
||||
<Setter Property="Shell.NavBarHasShadow" Value="False" />
|
||||
<Setter Property="Shell.TabBarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
|
||||
<Setter Property="Shell.TabBarForegroundColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
|
||||
<Setter Property="Shell.TabBarTitleColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
|
||||
<Setter Property="Shell.TabBarUnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="NavigationPage">
|
||||
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
|
||||
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
|
||||
<Setter Property="IconColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TabbedPage">
|
||||
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray950}}" />
|
||||
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
|
||||
<Setter Property="UnselectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
|
||||
<Setter Property="SelectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
317
TravelMateAdmin/Services/DatabaseService.cs
Normal file
317
TravelMateAdmin/Services/DatabaseService.cs
Normal file
@@ -0,0 +1,317 @@
|
||||
using MySqlConnector;
|
||||
using TravelMateAdmin.Models;
|
||||
using TravelMateAdmin.Configuration;
|
||||
|
||||
namespace TravelMateAdmin.Services;
|
||||
|
||||
public class DatabaseService : IDatabaseService
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public DatabaseService()
|
||||
{
|
||||
// Utilise la configuration depuis AppSettings
|
||||
_connectionString = AppSettings.GetConnectionString();
|
||||
}
|
||||
|
||||
public DatabaseService(string connectionString)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
}
|
||||
|
||||
#region Connection
|
||||
|
||||
public async Task<bool> TestConnectionAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var connection = new MySqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Messages
|
||||
|
||||
public async Task<List<Message>> GetAllMessagesAsync()
|
||||
{
|
||||
var messages = new List<Message>();
|
||||
|
||||
try
|
||||
{
|
||||
using var connection = new MySqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
var query = "SELECT id, nom, prenom, email, message, done, created_at FROM messages ORDER BY created_at DESC";
|
||||
using var command = new MySqlCommand(query, connection);
|
||||
using var reader = await command.ExecuteReaderAsync();
|
||||
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
messages.Add(new Message
|
||||
{
|
||||
Id = reader.GetInt32("id"),
|
||||
Nom = reader.GetString("nom"),
|
||||
Prenom = reader.GetString("prenom"),
|
||||
Email = reader.GetString("email"),
|
||||
MessageText = reader.GetString("message"),
|
||||
Done = reader.GetBoolean("done"),
|
||||
CreatedAt = reader.GetDateTime("created_at")
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error getting messages: {ex.Message}");
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
public async Task<List<Message>> GetMessagesFilteredAsync(bool? isDone)
|
||||
{
|
||||
if (isDone == null)
|
||||
return await GetAllMessagesAsync();
|
||||
|
||||
var messages = new List<Message>();
|
||||
|
||||
try
|
||||
{
|
||||
using var connection = new MySqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
var query = "SELECT id, nom, prenom, email, message, done, created_at FROM messages WHERE done = @done ORDER BY created_at DESC";
|
||||
using var command = new MySqlCommand(query, connection);
|
||||
command.Parameters.AddWithValue("@done", isDone.Value);
|
||||
using var reader = await command.ExecuteReaderAsync();
|
||||
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
messages.Add(new Message
|
||||
{
|
||||
Id = reader.GetInt32("id"),
|
||||
Nom = reader.GetString("nom"),
|
||||
Prenom = reader.GetString("prenom"),
|
||||
Email = reader.GetString("email"),
|
||||
MessageText = reader.GetString("message"),
|
||||
Done = reader.GetBoolean("done"),
|
||||
CreatedAt = reader.GetDateTime("created_at")
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error getting filtered messages: {ex.Message}");
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
public async Task<int> GetMessagesPendingCountAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var connection = new MySqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
var query = "SELECT COUNT(*) FROM messages WHERE done = 0";
|
||||
using var command = new MySqlCommand(query, connection);
|
||||
var result = await command.ExecuteScalarAsync();
|
||||
return Convert.ToInt32(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error getting pending messages count: {ex.Message}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> GetMessagesDoneCountAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var connection = new MySqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
var query = "SELECT COUNT(*) FROM messages WHERE done = 1";
|
||||
using var command = new MySqlCommand(query, connection);
|
||||
var result = await command.ExecuteScalarAsync();
|
||||
return Convert.ToInt32(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error getting done messages count: {ex.Message}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateMessageStatusAsync(int id, bool done)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var connection = new MySqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
var query = "UPDATE messages SET done = @done WHERE id = @id";
|
||||
using var command = new MySqlCommand(query, connection);
|
||||
command.Parameters.AddWithValue("@done", done);
|
||||
command.Parameters.AddWithValue("@id", id);
|
||||
|
||||
var rowsAffected = await command.ExecuteNonQueryAsync();
|
||||
return rowsAffected > 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error updating message status: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Support Requests
|
||||
|
||||
public async Task<List<SupportRequest>> GetAllSupportRequestsAsync()
|
||||
{
|
||||
var requests = new List<SupportRequest>();
|
||||
|
||||
try
|
||||
{
|
||||
using var connection = new MySqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
var query = "SELECT id, nom, prenom, account_email, contact_email, message, done, created_at FROM support_requests ORDER BY created_at DESC";
|
||||
using var command = new MySqlCommand(query, connection);
|
||||
using var reader = await command.ExecuteReaderAsync();
|
||||
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
requests.Add(new SupportRequest
|
||||
{
|
||||
Id = reader.GetInt32("id"),
|
||||
Nom = reader.GetString("nom"),
|
||||
Prenom = reader.GetString("prenom"),
|
||||
AccountEmail = reader.GetString("account_email"),
|
||||
ContactEmail = reader.GetString("contact_email"),
|
||||
MessageText = reader.GetString("message"),
|
||||
Done = reader.GetBoolean("done"),
|
||||
CreatedAt = reader.GetDateTime("created_at")
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error getting support requests: {ex.Message}");
|
||||
}
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
public async Task<List<SupportRequest>> GetSupportRequestsFilteredAsync(bool? isDone)
|
||||
{
|
||||
if (isDone == null)
|
||||
return await GetAllSupportRequestsAsync();
|
||||
|
||||
var requests = new List<SupportRequest>();
|
||||
|
||||
try
|
||||
{
|
||||
using var connection = new MySqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
var query = "SELECT id, nom, prenom, account_email, contact_email, message, done, created_at FROM support_requests WHERE done = @done ORDER BY created_at DESC";
|
||||
using var command = new MySqlCommand(query, connection);
|
||||
command.Parameters.AddWithValue("@done", isDone.Value);
|
||||
using var reader = await command.ExecuteReaderAsync();
|
||||
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
requests.Add(new SupportRequest
|
||||
{
|
||||
Id = reader.GetInt32("id"),
|
||||
Nom = reader.GetString("nom"),
|
||||
Prenom = reader.GetString("prenom"),
|
||||
AccountEmail = reader.GetString("account_email"),
|
||||
ContactEmail = reader.GetString("contact_email"),
|
||||
MessageText = reader.GetString("message"),
|
||||
Done = reader.GetBoolean("done"),
|
||||
CreatedAt = reader.GetDateTime("created_at")
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error getting filtered support requests: {ex.Message}");
|
||||
}
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
public async Task<int> GetSupportRequestsPendingCountAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var connection = new MySqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
var query = "SELECT COUNT(*) FROM support_requests WHERE done = 0";
|
||||
using var command = new MySqlCommand(query, connection);
|
||||
var result = await command.ExecuteScalarAsync();
|
||||
return Convert.ToInt32(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error getting pending support requests count: {ex.Message}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> GetSupportRequestsDoneCountAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var connection = new MySqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
var query = "SELECT COUNT(*) FROM support_requests WHERE done = 1";
|
||||
using var command = new MySqlCommand(query, connection);
|
||||
var result = await command.ExecuteScalarAsync();
|
||||
return Convert.ToInt32(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error getting done support requests count: {ex.Message}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateSupportRequestStatusAsync(int id, bool done)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var connection = new MySqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
var query = "UPDATE support_requests SET done = @done WHERE id = @id";
|
||||
using var command = new MySqlCommand(query, connection);
|
||||
command.Parameters.AddWithValue("@done", done);
|
||||
command.Parameters.AddWithValue("@id", id);
|
||||
|
||||
var rowsAffected = await command.ExecuteNonQueryAsync();
|
||||
return rowsAffected > 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error updating support request status: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
23
TravelMateAdmin/Services/IDatabaseService.cs
Normal file
23
TravelMateAdmin/Services/IDatabaseService.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using TravelMateAdmin.Models;
|
||||
|
||||
namespace TravelMateAdmin.Services;
|
||||
|
||||
public interface IDatabaseService
|
||||
{
|
||||
// Messages
|
||||
Task<List<Message>> GetAllMessagesAsync();
|
||||
Task<List<Message>> GetMessagesFilteredAsync(bool? isDone);
|
||||
Task<int> GetMessagesPendingCountAsync();
|
||||
Task<int> GetMessagesDoneCountAsync();
|
||||
Task<bool> UpdateMessageStatusAsync(int id, bool done);
|
||||
|
||||
// Support Requests
|
||||
Task<List<SupportRequest>> GetAllSupportRequestsAsync();
|
||||
Task<List<SupportRequest>> GetSupportRequestsFilteredAsync(bool? isDone);
|
||||
Task<int> GetSupportRequestsPendingCountAsync();
|
||||
Task<int> GetSupportRequestsDoneCountAsync();
|
||||
Task<bool> UpdateSupportRequestStatusAsync(int id, bool done);
|
||||
|
||||
// Connection
|
||||
Task<bool> TestConnectionAsync();
|
||||
}
|
||||
66
TravelMateAdmin/TravelMateAdmin.csproj
Normal file
66
TravelMateAdmin/TravelMateAdmin.csproj
Normal file
@@ -0,0 +1,66 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net10.0-android;net10.0-ios;net10.0-maccatalyst</TargetFrameworks>
|
||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net10.0-windows10.0.19041.0</TargetFrameworks>
|
||||
|
||||
<!-- Note for MacCatalyst:
|
||||
The default runtime is maccatalyst-x64, except in Release config, in which case the default is maccatalyst-x64;maccatalyst-arm64.
|
||||
When specifying both architectures, use the plural <RuntimeIdentifiers> instead of the singular <RuntimeIdentifier>.
|
||||
The Mac App Store will NOT accept apps with ONLY maccatalyst-arm64 indicated;
|
||||
either BOTH runtimes must be indicated or ONLY macatalyst-x64. -->
|
||||
<!-- For example: <RuntimeIdentifiers>maccatalyst-x64;maccatalyst-arm64</RuntimeIdentifiers> -->
|
||||
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>TravelMateAdmin</RootNamespace>
|
||||
<UseMaui>true</UseMaui>
|
||||
<SingleProject>true</SingleProject>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<!-- Display name -->
|
||||
<ApplicationTitle>TravelMateAdmin</ApplicationTitle>
|
||||
|
||||
<!-- App Identifier -->
|
||||
<ApplicationId>com.companyname.travelmateadmin</ApplicationId>
|
||||
|
||||
<!-- Versions -->
|
||||
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>1</ApplicationVersion>
|
||||
|
||||
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
|
||||
<WindowsPackageType>None</WindowsPackageType>
|
||||
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
|
||||
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- App Icon -->
|
||||
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
|
||||
|
||||
<!-- Splash Screen -->
|
||||
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
|
||||
|
||||
<!-- Images -->
|
||||
<MauiImage Include="Resources\Images\*" />
|
||||
<MauiImage Update="Resources\Images\dotnet_bot.png" Resize="True" BaseSize="300,185" />
|
||||
|
||||
<!-- Custom Fonts -->
|
||||
<MauiFont Include="Resources\Fonts\*" />
|
||||
|
||||
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
|
||||
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.0" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
76
TravelMateAdmin/ViewModels/DashboardViewModel.cs
Normal file
76
TravelMateAdmin/ViewModels/DashboardViewModel.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using TravelMateAdmin.Services;
|
||||
|
||||
namespace TravelMateAdmin.ViewModels;
|
||||
|
||||
public partial class DashboardViewModel : ObservableObject
|
||||
{
|
||||
private readonly IDatabaseService _databaseService;
|
||||
|
||||
[ObservableProperty]
|
||||
private int messagesPending;
|
||||
|
||||
[ObservableProperty]
|
||||
private int messagesDone;
|
||||
|
||||
[ObservableProperty]
|
||||
private int supportRequestsPending;
|
||||
|
||||
[ObservableProperty]
|
||||
private int supportRequestsDone;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private string connectionStatus = "Non connecté";
|
||||
|
||||
public DashboardViewModel(IDatabaseService databaseService)
|
||||
{
|
||||
_databaseService = databaseService;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task LoadDashboardAsync()
|
||||
{
|
||||
IsLoading = true;
|
||||
|
||||
try
|
||||
{
|
||||
// Test connection
|
||||
var isConnected = await _databaseService.TestConnectionAsync();
|
||||
ConnectionStatus = isConnected ? "✓ Connecté" : "✗ Déconnecté";
|
||||
|
||||
if (isConnected)
|
||||
{
|
||||
// Load stats
|
||||
MessagesPending = await _databaseService.GetMessagesPendingCountAsync();
|
||||
MessagesDone = await _databaseService.GetMessagesDoneCountAsync();
|
||||
SupportRequestsPending = await _databaseService.GetSupportRequestsPendingCountAsync();
|
||||
SupportRequestsDone = await _databaseService.GetSupportRequestsDoneCountAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error loading dashboard: {ex.Message}");
|
||||
ConnectionStatus = "✗ Erreur de connexion";
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task NavigateToMessagesAsync()
|
||||
{
|
||||
await Shell.Current.GoToAsync("//MessagesPage");
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task NavigateToSupportAsync()
|
||||
{
|
||||
await Shell.Current.GoToAsync("//SupportPage");
|
||||
}
|
||||
}
|
||||
83
TravelMateAdmin/ViewModels/MessagesViewModel.cs
Normal file
83
TravelMateAdmin/ViewModels/MessagesViewModel.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System.Collections.ObjectModel;
|
||||
using TravelMateAdmin.Models;
|
||||
using TravelMateAdmin.Services;
|
||||
|
||||
namespace TravelMateAdmin.ViewModels;
|
||||
|
||||
public partial class MessagesViewModel : ObservableObject
|
||||
{
|
||||
private readonly IDatabaseService _databaseService;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<Message> messages = new();
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private string selectedFilter = "Tout";
|
||||
|
||||
public List<string> Filters { get; } = new() { "Tout", "À faire", "Fait" };
|
||||
|
||||
public MessagesViewModel(IDatabaseService databaseService)
|
||||
{
|
||||
_databaseService = databaseService;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task LoadMessagesAsync()
|
||||
{
|
||||
IsLoading = true;
|
||||
|
||||
try
|
||||
{
|
||||
bool? isDone = SelectedFilter switch
|
||||
{
|
||||
"À faire" => false,
|
||||
"Fait" => true,
|
||||
_ => null
|
||||
};
|
||||
|
||||
var messagesList = await _databaseService.GetMessagesFilteredAsync(isDone);
|
||||
Messages.Clear();
|
||||
foreach (var message in messagesList)
|
||||
{
|
||||
Messages.Add(message);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error loading messages: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task ToggleMessageStatusAsync(Message message)
|
||||
{
|
||||
if (message == null) return;
|
||||
|
||||
var success = await _databaseService.UpdateMessageStatusAsync(message.Id, !message.Done);
|
||||
if (success)
|
||||
{
|
||||
message.Done = !message.Done;
|
||||
OnPropertyChanged(nameof(Messages));
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task RefreshAsync()
|
||||
{
|
||||
await LoadMessagesAsync();
|
||||
}
|
||||
|
||||
partial void OnSelectedFilterChanged(string value)
|
||||
{
|
||||
_ = LoadMessagesAsync();
|
||||
}
|
||||
}
|
||||
83
TravelMateAdmin/ViewModels/SupportViewModel.cs
Normal file
83
TravelMateAdmin/ViewModels/SupportViewModel.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System.Collections.ObjectModel;
|
||||
using TravelMateAdmin.Models;
|
||||
using TravelMateAdmin.Services;
|
||||
|
||||
namespace TravelMateAdmin.ViewModels;
|
||||
|
||||
public partial class SupportViewModel : ObservableObject
|
||||
{
|
||||
private readonly IDatabaseService _databaseService;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<SupportRequest> supportRequests = new();
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private string selectedFilter = "Tout";
|
||||
|
||||
public List<string> Filters { get; } = new() { "Tout", "À faire", "Fait" };
|
||||
|
||||
public SupportViewModel(IDatabaseService databaseService)
|
||||
{
|
||||
_databaseService = databaseService;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task LoadSupportRequestsAsync()
|
||||
{
|
||||
IsLoading = true;
|
||||
|
||||
try
|
||||
{
|
||||
bool? isDone = SelectedFilter switch
|
||||
{
|
||||
"À faire" => false,
|
||||
"Fait" => true,
|
||||
_ => null
|
||||
};
|
||||
|
||||
var requestsList = await _databaseService.GetSupportRequestsFilteredAsync(isDone);
|
||||
SupportRequests.Clear();
|
||||
foreach (var request in requestsList)
|
||||
{
|
||||
SupportRequests.Add(request);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error loading support requests: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task ToggleSupportRequestStatusAsync(SupportRequest request)
|
||||
{
|
||||
if (request == null) return;
|
||||
|
||||
var success = await _databaseService.UpdateSupportRequestStatusAsync(request.Id, !request.Done);
|
||||
if (success)
|
||||
{
|
||||
request.Done = !request.Done;
|
||||
OnPropertyChanged(nameof(SupportRequests));
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task RefreshAsync()
|
||||
{
|
||||
await LoadSupportRequestsAsync();
|
||||
}
|
||||
|
||||
partial void OnSelectedFilterChanged(string value)
|
||||
{
|
||||
_ = LoadSupportRequestsAsync();
|
||||
}
|
||||
}
|
||||
165
TravelMateAdmin/Views/DashboardPage.xaml
Normal file
165
TravelMateAdmin/Views/DashboardPage.xaml
Normal file
@@ -0,0 +1,165 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:vm="clr-namespace:TravelMateAdmin.ViewModels"
|
||||
x:Class="TravelMateAdmin.Views.DashboardPage"
|
||||
x:DataType="vm:DashboardViewModel"
|
||||
Title="Tableau de Bord"
|
||||
BackgroundColor="{StaticResource Primary}">
|
||||
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<Color x:Key="Primary">#1a1a1a</Color>
|
||||
<Color x:Key="Secondary">#2d2d2d</Color>
|
||||
<Color x:Key="Accent">#5E50D9</Color>
|
||||
<Color x:Key="TextPrimary">#FFFFFF</Color>
|
||||
<Color x:Key="TextSecondary">#B0B0B0</Color>
|
||||
<Color x:Key="Success">#4CAF50</Color>
|
||||
<Color x:Key="Warning">#FFA726</Color>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
||||
<ScrollView>
|
||||
<VerticalStackLayout Padding="20" Spacing="20">
|
||||
|
||||
<!-- Header -->
|
||||
<Frame BackgroundColor="{StaticResource Secondary}"
|
||||
CornerRadius="10"
|
||||
Padding="20"
|
||||
HasShadow="True">
|
||||
<Grid RowDefinitions="Auto,Auto" ColumnDefinitions="*,Auto">
|
||||
<Label Text="TravelMate Admin"
|
||||
FontSize="32"
|
||||
FontAttributes="Bold"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
Grid.Row="0" Grid.Column="0"/>
|
||||
<Label Text="Panneau d'Administration"
|
||||
FontSize="16"
|
||||
TextColor="{StaticResource TextSecondary}"
|
||||
Grid.Row="1" Grid.Column="0"/>
|
||||
<Label Text="{Binding ConnectionStatus}"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource Success}"
|
||||
VerticalOptions="Center"
|
||||
Grid.Row="0" Grid.Column="1" Grid.RowSpan="2"/>
|
||||
</Grid>
|
||||
</Frame>
|
||||
|
||||
<!-- Loading Indicator -->
|
||||
<ActivityIndicator IsRunning="{Binding IsLoading}"
|
||||
IsVisible="{Binding IsLoading}"
|
||||
Color="{StaticResource Accent}"
|
||||
HeightRequest="50"/>
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<Grid ColumnDefinitions="*,*"
|
||||
RowDefinitions="Auto,Auto"
|
||||
ColumnSpacing="15"
|
||||
RowSpacing="15">
|
||||
|
||||
<!-- Messages Pending -->
|
||||
<Frame BackgroundColor="{StaticResource Secondary}"
|
||||
CornerRadius="10"
|
||||
Padding="20"
|
||||
HasShadow="True"
|
||||
Grid.Row="0" Grid.Column="0">
|
||||
<Frame.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding NavigateToMessagesCommand}"/>
|
||||
</Frame.GestureRecognizers>
|
||||
<VerticalStackLayout Spacing="10">
|
||||
<Label Text="Messages"
|
||||
FontSize="16"
|
||||
TextColor="{StaticResource TextSecondary}"/>
|
||||
<Label Text="{Binding MessagesPending}"
|
||||
FontSize="48"
|
||||
FontAttributes="Bold"
|
||||
TextColor="{StaticResource Warning}"/>
|
||||
<Label Text="En attente"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource TextSecondary}"/>
|
||||
</VerticalStackLayout>
|
||||
</Frame>
|
||||
|
||||
<!-- Messages Done -->
|
||||
<Frame BackgroundColor="{StaticResource Secondary}"
|
||||
CornerRadius="10"
|
||||
Padding="20"
|
||||
HasShadow="True"
|
||||
Grid.Row="0" Grid.Column="1">
|
||||
<Frame.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding NavigateToMessagesCommand}"/>
|
||||
</Frame.GestureRecognizers>
|
||||
<VerticalStackLayout Spacing="10">
|
||||
<Label Text="Messages"
|
||||
FontSize="16"
|
||||
TextColor="{StaticResource TextSecondary}"/>
|
||||
<Label Text="{Binding MessagesDone}"
|
||||
FontSize="48"
|
||||
FontAttributes="Bold"
|
||||
TextColor="{StaticResource Success}"/>
|
||||
<Label Text="Traités"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource TextSecondary}"/>
|
||||
</VerticalStackLayout>
|
||||
</Frame>
|
||||
|
||||
<!-- Support Pending -->
|
||||
<Frame BackgroundColor="{StaticResource Secondary}"
|
||||
CornerRadius="10"
|
||||
Padding="20"
|
||||
HasShadow="True"
|
||||
Grid.Row="1" Grid.Column="0">
|
||||
<Frame.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding NavigateToSupportCommand}"/>
|
||||
</Frame.GestureRecognizers>
|
||||
<VerticalStackLayout Spacing="10">
|
||||
<Label Text="Support"
|
||||
FontSize="16"
|
||||
TextColor="{StaticResource TextSecondary}"/>
|
||||
<Label Text="{Binding SupportRequestsPending}"
|
||||
FontSize="48"
|
||||
FontAttributes="Bold"
|
||||
TextColor="{StaticResource Warning}"/>
|
||||
<Label Text="En attente"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource TextSecondary}"/>
|
||||
</VerticalStackLayout>
|
||||
</Frame>
|
||||
|
||||
<!-- Support Done -->
|
||||
<Frame BackgroundColor="{StaticResource Secondary}"
|
||||
CornerRadius="10"
|
||||
Padding="20"
|
||||
HasShadow="True"
|
||||
Grid.Row="1" Grid.Column="1">
|
||||
<Frame.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding NavigateToSupportCommand}"/>
|
||||
</Frame.GestureRecognizers>
|
||||
<VerticalStackLayout Spacing="10">
|
||||
<Label Text="Support"
|
||||
FontSize="16"
|
||||
TextColor="{StaticResource TextSecondary}"/>
|
||||
<Label Text="{Binding SupportRequestsDone}"
|
||||
FontSize="48"
|
||||
FontAttributes="Bold"
|
||||
TextColor="{StaticResource Success}"/>
|
||||
<Label Text="Traités"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource TextSecondary}"/>
|
||||
</VerticalStackLayout>
|
||||
</Frame>
|
||||
</Grid>
|
||||
|
||||
<!-- Refresh Button -->
|
||||
<Button Text="Actualiser"
|
||||
Command="{Binding LoadDashboardCommand}"
|
||||
BackgroundColor="{StaticResource Accent}"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
CornerRadius="10"
|
||||
HeightRequest="50"
|
||||
FontSize="16"
|
||||
FontAttributes="Bold"/>
|
||||
|
||||
</VerticalStackLayout>
|
||||
</ScrollView>
|
||||
</ContentPage>
|
||||
21
TravelMateAdmin/Views/DashboardPage.xaml.cs
Normal file
21
TravelMateAdmin/Views/DashboardPage.xaml.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using TravelMateAdmin.ViewModels;
|
||||
|
||||
namespace TravelMateAdmin.Views;
|
||||
|
||||
public partial class DashboardPage : ContentPage
|
||||
{
|
||||
private readonly DashboardViewModel _viewModel;
|
||||
|
||||
public DashboardPage(DashboardViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = viewModel;
|
||||
BindingContext = _viewModel;
|
||||
}
|
||||
|
||||
protected override async void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
await _viewModel.LoadDashboardCommand.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
143
TravelMateAdmin/Views/MessagesPage.xaml
Normal file
143
TravelMateAdmin/Views/MessagesPage.xaml
Normal file
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:vm="clr-namespace:TravelMateAdmin.ViewModels"
|
||||
xmlns:models="clr-namespace:TravelMateAdmin.Models"
|
||||
xmlns:converters="clr-namespace:TravelMateAdmin.Converters"
|
||||
x:Class="TravelMateAdmin.Views.MessagesPage"
|
||||
x:DataType="vm:MessagesViewModel"
|
||||
Title="Messages"
|
||||
BackgroundColor="{StaticResource Primary}">
|
||||
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<Color x:Key="Primary">#1a1a1a</Color>
|
||||
<Color x:Key="Secondary">#2d2d2d</Color>
|
||||
<Color x:Key="Accent">#5E50D9</Color>
|
||||
<Color x:Key="TextPrimary">#FFFFFF</Color>
|
||||
<Color x:Key="TextSecondary">#B0B0B0</Color>
|
||||
<Color x:Key="Success">#4CAF50</Color>
|
||||
<Color x:Key="Warning">#FFA726</Color>
|
||||
<Color x:Key="CardBackground">#252525</Color>
|
||||
|
||||
<converters:BoolToStatusTextConverter x:Key="BoolToStatusTextConverter"/>
|
||||
<converters:BoolToColorConverter x:Key="BoolToColorConverter"/>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
||||
<Grid RowDefinitions="Auto,Auto,*" Padding="20" RowSpacing="15">
|
||||
|
||||
<!-- Header with Filter -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="*,Auto,Auto" ColumnSpacing="10">
|
||||
<Label Text="Messages"
|
||||
FontSize="28"
|
||||
FontAttributes="Bold"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
VerticalOptions="Center"
|
||||
Grid.Column="0"/>
|
||||
|
||||
<Picker ItemsSource="{Binding Filters}"
|
||||
SelectedItem="{Binding SelectedFilter}"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
BackgroundColor="{StaticResource Secondary}"
|
||||
WidthRequest="150"
|
||||
Grid.Column="1"/>
|
||||
|
||||
<Button Text="↻"
|
||||
Command="{Binding RefreshCommand}"
|
||||
BackgroundColor="{StaticResource Accent}"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
WidthRequest="50"
|
||||
HeightRequest="50"
|
||||
CornerRadius="25"
|
||||
FontSize="20"
|
||||
Grid.Column="2"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Loading Indicator -->
|
||||
<ActivityIndicator IsRunning="{Binding IsLoading}"
|
||||
IsVisible="{Binding IsLoading}"
|
||||
Color="{StaticResource Accent}"
|
||||
HeightRequest="50"
|
||||
Grid.Row="1"/>
|
||||
|
||||
<!-- Messages List -->
|
||||
<CollectionView ItemsSource="{Binding Messages}"
|
||||
Grid.Row="2"
|
||||
SelectionMode="None">
|
||||
<CollectionView.EmptyView>
|
||||
<VerticalStackLayout HorizontalOptions="Center"
|
||||
VerticalOptions="Center"
|
||||
Spacing="10">
|
||||
<Label Text="Aucun message"
|
||||
FontSize="20"
|
||||
TextColor="{StaticResource TextSecondary}"
|
||||
HorizontalOptions="Center"/>
|
||||
</VerticalStackLayout>
|
||||
</CollectionView.EmptyView>
|
||||
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:Message">
|
||||
<Frame BackgroundColor="{StaticResource CardBackground}"
|
||||
CornerRadius="10"
|
||||
Padding="15"
|
||||
Margin="0,5"
|
||||
HasShadow="True">
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto"
|
||||
ColumnDefinitions="*,Auto"
|
||||
RowSpacing="8">
|
||||
|
||||
<!-- Name and Date -->
|
||||
<Label Text="{Binding FullName}"
|
||||
FontSize="18"
|
||||
FontAttributes="Bold"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
Grid.Row="0" Grid.Column="0"/>
|
||||
<Label Text="{Binding CreatedAtFormatted}"
|
||||
FontSize="12"
|
||||
TextColor="{StaticResource TextSecondary}"
|
||||
Grid.Row="0" Grid.Column="1"/>
|
||||
|
||||
<!-- Email -->
|
||||
<Label Text="{Binding Email}"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource Accent}"
|
||||
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
|
||||
<!-- Message -->
|
||||
<Label Text="{Binding MessageText}"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource TextSecondary}"
|
||||
LineBreakMode="WordWrap"
|
||||
MaxLines="5"
|
||||
Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
|
||||
<!-- Separator -->
|
||||
<BoxView BackgroundColor="{StaticResource Secondary}"
|
||||
HeightRequest="1"
|
||||
Margin="0,8"
|
||||
Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
|
||||
<!-- Status and Action -->
|
||||
<Label Text="{Binding StatusText}"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource Warning}"
|
||||
VerticalOptions="Center"
|
||||
Grid.Row="4" Grid.Column="0"/>
|
||||
|
||||
<Button Text="{Binding Done, Converter={StaticResource BoolToStatusTextConverter}}"
|
||||
Command="{Binding Source={RelativeSource AncestorType={x:Type vm:MessagesViewModel}}, Path=ToggleMessageStatusCommand}"
|
||||
CommandParameter="{Binding .}"
|
||||
BackgroundColor="{Binding Done, Converter={StaticResource BoolToColorConverter}}"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
CornerRadius="8"
|
||||
FontSize="14"
|
||||
HeightRequest="40"
|
||||
Grid.Row="4" Grid.Column="1"/>
|
||||
</Grid>
|
||||
</Frame>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
21
TravelMateAdmin/Views/MessagesPage.xaml.cs
Normal file
21
TravelMateAdmin/Views/MessagesPage.xaml.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using TravelMateAdmin.ViewModels;
|
||||
|
||||
namespace TravelMateAdmin.Views;
|
||||
|
||||
public partial class MessagesPage : ContentPage
|
||||
{
|
||||
private readonly MessagesViewModel _viewModel;
|
||||
|
||||
public MessagesPage(MessagesViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = viewModel;
|
||||
BindingContext = _viewModel;
|
||||
}
|
||||
|
||||
protected override async void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
await _viewModel.LoadMessagesCommand.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
149
TravelMateAdmin/Views/SupportPage.xaml
Normal file
149
TravelMateAdmin/Views/SupportPage.xaml
Normal file
@@ -0,0 +1,149 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:vm="clr-namespace:TravelMateAdmin.ViewModels"
|
||||
xmlns:models="clr-namespace:TravelMateAdmin.Models"
|
||||
xmlns:converters="clr-namespace:TravelMateAdmin.Converters"
|
||||
x:Class="TravelMateAdmin.Views.SupportPage"
|
||||
x:DataType="vm:SupportViewModel"
|
||||
Title="Support"
|
||||
BackgroundColor="{StaticResource Primary}">
|
||||
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<Color x:Key="Primary">#1a1a1a</Color>
|
||||
<Color x:Key="Secondary">#2d2d2d</Color>
|
||||
<Color x:Key="Accent">#5E50D9</Color>
|
||||
<Color x:Key="TextPrimary">#FFFFFF</Color>
|
||||
<Color x:Key="TextSecondary">#B0B0B0</Color>
|
||||
<Color x:Key="Success">#4CAF50</Color>
|
||||
<Color x:Key="Warning">#FFA726</Color>
|
||||
<Color x:Key="CardBackground">#252525</Color>
|
||||
|
||||
<converters:BoolToStatusTextConverter x:Key="BoolToStatusTextConverter"/>
|
||||
<converters:BoolToColorConverter x:Key="BoolToColorConverter"/>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
||||
<Grid RowDefinitions="Auto,Auto,*" Padding="20" RowSpacing="15">
|
||||
|
||||
<!-- Header with Filter -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="*,Auto,Auto" ColumnSpacing="10">
|
||||
<Label Text="Demandes Support"
|
||||
FontSize="28"
|
||||
FontAttributes="Bold"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
VerticalOptions="Center"
|
||||
Grid.Column="0"/>
|
||||
|
||||
<Picker ItemsSource="{Binding Filters}"
|
||||
SelectedItem="{Binding SelectedFilter}"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
BackgroundColor="{StaticResource Secondary}"
|
||||
WidthRequest="150"
|
||||
Grid.Column="1"/>
|
||||
|
||||
<Button Text="↻"
|
||||
Command="{Binding RefreshCommand}"
|
||||
BackgroundColor="{StaticResource Accent}"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
WidthRequest="50"
|
||||
HeightRequest="50"
|
||||
CornerRadius="25"
|
||||
FontSize="20"
|
||||
Grid.Column="2"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Loading Indicator -->
|
||||
<ActivityIndicator IsRunning="{Binding IsLoading}"
|
||||
IsVisible="{Binding IsLoading}"
|
||||
Color="{StaticResource Accent}"
|
||||
HeightRequest="50"
|
||||
Grid.Row="1"/>
|
||||
|
||||
<!-- Support Requests List -->
|
||||
<CollectionView ItemsSource="{Binding SupportRequests}"
|
||||
Grid.Row="2"
|
||||
SelectionMode="None">
|
||||
<CollectionView.EmptyView>
|
||||
<VerticalStackLayout HorizontalOptions="Center"
|
||||
VerticalOptions="Center"
|
||||
Spacing="10">
|
||||
<Label Text="Aucune demande support"
|
||||
FontSize="20"
|
||||
TextColor="{StaticResource TextSecondary}"
|
||||
HorizontalOptions="Center"/>
|
||||
</VerticalStackLayout>
|
||||
</CollectionView.EmptyView>
|
||||
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:SupportRequest">
|
||||
<Frame BackgroundColor="{StaticResource CardBackground}"
|
||||
CornerRadius="10"
|
||||
Padding="15"
|
||||
Margin="0,5"
|
||||
HasShadow="True">
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto"
|
||||
ColumnDefinitions="*,Auto"
|
||||
RowSpacing="8">
|
||||
|
||||
<!-- Name and Date -->
|
||||
<Label Text="{Binding FullName}"
|
||||
FontSize="18"
|
||||
FontAttributes="Bold"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
Grid.Row="0" Grid.Column="0"/>
|
||||
<Label Text="{Binding CreatedAtFormatted}"
|
||||
FontSize="12"
|
||||
TextColor="{StaticResource TextSecondary}"
|
||||
Grid.Row="0" Grid.Column="1"/>
|
||||
|
||||
<!-- Account Email -->
|
||||
<Label Text="{Binding AccountEmail, StringFormat='Compte: {0}'}"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource Accent}"
|
||||
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
|
||||
<!-- Contact Email -->
|
||||
<Label Text="{Binding ContactEmail, StringFormat='Contact: {0}'}"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource Accent}"
|
||||
Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
|
||||
<!-- Message -->
|
||||
<Label Text="{Binding MessageText}"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource TextSecondary}"
|
||||
LineBreakMode="WordWrap"
|
||||
MaxLines="5"
|
||||
Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
|
||||
<!-- Separator -->
|
||||
<BoxView BackgroundColor="{StaticResource Secondary}"
|
||||
HeightRequest="1"
|
||||
Margin="0,8"
|
||||
Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
|
||||
<!-- Status and Action -->
|
||||
<Label Text="{Binding StatusText}"
|
||||
FontSize="14"
|
||||
TextColor="{StaticResource Warning}"
|
||||
VerticalOptions="Center"
|
||||
Grid.Row="5" Grid.Column="0"/>
|
||||
|
||||
<Button Text="{Binding Done, Converter={StaticResource BoolToStatusTextConverter}}"
|
||||
Command="{Binding Source={RelativeSource AncestorType={x:Type vm:SupportViewModel}}, Path=ToggleSupportRequestStatusCommand}"
|
||||
CommandParameter="{Binding .}"
|
||||
BackgroundColor="{Binding Done, Converter={StaticResource BoolToColorConverter}}"
|
||||
TextColor="{StaticResource TextPrimary}"
|
||||
CornerRadius="8"
|
||||
FontSize="14"
|
||||
HeightRequest="40"
|
||||
Grid.Row="5" Grid.Column="1"/>
|
||||
</Grid>
|
||||
</Frame>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
21
TravelMateAdmin/Views/SupportPage.xaml.cs
Normal file
21
TravelMateAdmin/Views/SupportPage.xaml.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using TravelMateAdmin.ViewModels;
|
||||
|
||||
namespace TravelMateAdmin.Views;
|
||||
|
||||
public partial class SupportPage : ContentPage
|
||||
{
|
||||
private readonly SupportViewModel _viewModel;
|
||||
|
||||
public SupportPage(SupportViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = viewModel;
|
||||
BindingContext = _viewModel;
|
||||
}
|
||||
|
||||
protected override async void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
await _viewModel.LoadSupportRequestsCommand.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
52
database_setup.sql
Normal file
52
database_setup.sql
Normal file
@@ -0,0 +1,52 @@
|
||||
-- Script SQL pour créer la base de données TravelMate Admin
|
||||
-- À exécuter dans MySQL/MariaDB
|
||||
|
||||
-- Créer la base de données
|
||||
CREATE DATABASE IF NOT EXISTS travelmateadmin CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
USE travelmateadmin;
|
||||
|
||||
-- Table des messages
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nom VARCHAR(100) NOT NULL,
|
||||
prenom VARCHAR(100) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
done BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_done (done),
|
||||
INDEX idx_created_at (created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table des demandes support
|
||||
CREATE TABLE IF NOT EXISTS support_requests (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nom VARCHAR(100) NOT NULL,
|
||||
prenom VARCHAR(100) NOT NULL,
|
||||
account_email VARCHAR(255) NOT NULL,
|
||||
contact_email VARCHAR(255) NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
done BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_done (done),
|
||||
INDEX idx_created_at (created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Données de test pour messages
|
||||
INSERT INTO messages (nom, prenom, email, message, done, created_at) VALUES
|
||||
('Dupont', 'Jean', 'jean.dupont@example.com', 'Je souhaite effacer toutes mes données personnelles conformément au RGPD.', FALSE, NOW() - INTERVAL 2 DAY),
|
||||
('Martin', 'Sophie', 'sophie.martin@example.com', 'Pouvez-vous supprimer mon compte et toutes les informations associées ?', FALSE, NOW() - INTERVAL 1 DAY),
|
||||
('Bernard', 'Pierre', 'pierre.bernard@example.com', 'Demande de suppression de données RGPD', TRUE, NOW() - INTERVAL 5 DAY),
|
||||
('Dubois', 'Marie', 'marie.dubois@example.com', 'Bonjour, je voudrais avoir des informations sur vos services.', FALSE, NOW() - INTERVAL 3 HOUR);
|
||||
|
||||
-- Données de test pour support_requests
|
||||
INSERT INTO support_requests (nom, prenom, account_email, contact_email, message, done, created_at) VALUES
|
||||
('Petit', 'Lucas', 'lucas.petit@example.com', 'lucas.contact@example.com', 'Je n''arrive pas à me connecter à mon compte depuis hier.', FALSE, NOW() - INTERVAL 1 DAY),
|
||||
('Roux', 'Emma', 'emma.roux@example.com', 'emma.pro@example.com', 'Mon mot de passe ne fonctionne plus, pouvez-vous m''aider ?', FALSE, NOW() - INTERVAL 6 HOUR),
|
||||
('Moreau', 'Thomas', 'thomas.moreau@example.com', 'thomas.m@example.com', 'Problème de synchronisation des données', TRUE, NOW() - INTERVAL 4 DAY),
|
||||
('Simon', 'Julie', 'julie.simon@example.com', 'julie.s@example.com', 'Question sur la facturation de mon abonnement', FALSE, NOW() - INTERVAL 2 HOUR);
|
||||
|
||||
-- Afficher un résumé
|
||||
SELECT 'Messages créés:' AS info, COUNT(*) AS count FROM messages
|
||||
UNION ALL
|
||||
SELECT 'Support créés:', COUNT(*) FROM support_requests;
|
||||
Reference in New Issue
Block a user