mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: mise en place de la messagerie [#17]
This commit is contained in:
340
Front-End/docs/api-messagerie-technique.md
Normal file
340
Front-End/docs/api-messagerie-technique.md
Normal file
@ -0,0 +1,340 @@
|
||||
# API Messagerie Instantanée - Guide Développeur
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Cette documentation technique présente l'implémentation du système de messagerie instantanée, incluant les APIs WebSocket et REST, l'architecture des composants React et les fonctions utilitaires.
|
||||
|
||||
## API WebSocket
|
||||
|
||||
### Connexion
|
||||
|
||||
**URL de connexion :**
|
||||
|
||||
```javascript
|
||||
// Développement
|
||||
ws://localhost:8000/ws/chat/{userId}/
|
||||
|
||||
// Production
|
||||
wss://[domaine]/ws/chat/{userId}/
|
||||
```
|
||||
|
||||
### Messages WebSocket
|
||||
|
||||
#### Messages entrants (serveur → client)
|
||||
|
||||
```javascript
|
||||
// Liste des conversations
|
||||
{
|
||||
"type": "conversations_list",
|
||||
"conversations": [...]
|
||||
}
|
||||
|
||||
// Nouveau message reçu
|
||||
{
|
||||
"type": "new_message",
|
||||
"message": {
|
||||
"id": 123,
|
||||
"conversation_id": 456,
|
||||
"sender_id": 789,
|
||||
"content": "Contenu du message",
|
||||
"timestamp": "2024-01-01T12:00:00Z"
|
||||
}
|
||||
}
|
||||
|
||||
// Utilisateur en train d'écrire
|
||||
{
|
||||
"type": "typing_start",
|
||||
"conversation_id": 456,
|
||||
"user_id": 789
|
||||
}
|
||||
|
||||
// Utilisateur a arrêté d'écrire
|
||||
{
|
||||
"type": "typing_stop",
|
||||
"conversation_id": 456,
|
||||
"user_id": 789
|
||||
}
|
||||
```
|
||||
|
||||
#### Messages sortants (client → serveur)
|
||||
|
||||
```javascript
|
||||
// Envoyer un message
|
||||
{
|
||||
"type": "chat_message",
|
||||
"conversation_id": 456,
|
||||
"message": "Contenu du message"
|
||||
}
|
||||
|
||||
// Signaler début de frappe
|
||||
{
|
||||
"type": "typing_start",
|
||||
"conversation_id": 456
|
||||
}
|
||||
|
||||
// Signaler fin de frappe
|
||||
{
|
||||
"type": "typing_stop",
|
||||
"conversation_id": 456
|
||||
}
|
||||
|
||||
// Marquer comme lu
|
||||
{
|
||||
"type": "mark_as_read",
|
||||
"conversation_id": 456
|
||||
}
|
||||
|
||||
// Rejoindre une conversation
|
||||
{
|
||||
"type": "join_conversation",
|
||||
"conversation_id": 456
|
||||
}
|
||||
```
|
||||
|
||||
## API REST
|
||||
|
||||
### Endpoints disponibles
|
||||
|
||||
```javascript
|
||||
// Récupérer les conversations
|
||||
GET /api/messagerie/conversations/{userId}/
|
||||
Response: Array<Conversation>
|
||||
|
||||
// Récupérer les messages d'une conversation
|
||||
GET /api/messagerie/messages/{conversationId}/
|
||||
Response: Array<Message>
|
||||
|
||||
// Rechercher des destinataires
|
||||
GET /api/messagerie/search/{establishmentId}/?q={query}
|
||||
Response: Array<User>
|
||||
|
||||
// Créer une conversation
|
||||
POST /api/messagerie/conversations/create/
|
||||
Body: { "participants": [userId1, userId2] }
|
||||
Response: Conversation
|
||||
|
||||
// Envoyer un email (séparé de la messagerie instantanée)
|
||||
POST /api/email/send/
|
||||
Body: { "recipients": [...], "subject": "...", "content": "..." }
|
||||
```
|
||||
|
||||
## Composants React
|
||||
|
||||
### InstantChat
|
||||
|
||||
**Props :**
|
||||
|
||||
```javascript
|
||||
{
|
||||
userProfileId: number, // ID de l'utilisateur connecté
|
||||
establishmentId: number // ID de l'établissement
|
||||
}
|
||||
```
|
||||
|
||||
**États principaux :**
|
||||
|
||||
- `conversations` : Liste des conversations
|
||||
- `selectedConversation` : Conversation active
|
||||
- `messages` : Messages de la conversation active
|
||||
- `searchQuery` : Terme de recherche
|
||||
- `searchResults` : Résultats de recherche de contacts
|
||||
|
||||
### useWebSocket Hook
|
||||
|
||||
**Paramètres :**
|
||||
|
||||
```javascript
|
||||
useWebSocket(
|
||||
userProfileId, // ID utilisateur
|
||||
onMessage, // Callback pour messages reçus
|
||||
onConnectionChange // Callback changement de connexion
|
||||
);
|
||||
```
|
||||
|
||||
**Valeurs retournées :**
|
||||
|
||||
```javascript
|
||||
{
|
||||
isConnected: boolean,
|
||||
connectionStatus: string,
|
||||
sendChatMessage: (conversationId, content) => boolean,
|
||||
sendTypingStart: (conversationId) => void,
|
||||
sendTypingStop: (conversationId) => void,
|
||||
markAsRead: (conversationId) => void,
|
||||
joinConversation: (conversationId) => void,
|
||||
reconnect: () => void
|
||||
}
|
||||
```
|
||||
|
||||
## Actions Redux/State
|
||||
|
||||
### messagerieAction.js
|
||||
|
||||
```javascript
|
||||
// Récupérer les conversations
|
||||
fetchConversations(userId): Promise<Array<Conversation>>
|
||||
|
||||
// Récupérer les messages
|
||||
fetchMessages(conversationId): Promise<Array<Message>>
|
||||
|
||||
// Rechercher des destinataires
|
||||
searchMessagerieRecipients(establishmentId, query): Promise<Array<User>>
|
||||
|
||||
// Créer une conversation
|
||||
createConversation(participants): Promise<Conversation>
|
||||
```
|
||||
|
||||
### emailAction.js
|
||||
|
||||
```javascript
|
||||
// Envoyer un email
|
||||
sendEmail(recipients, subject, content, csrfToken): Promise<Response>
|
||||
|
||||
// Rechercher des destinataires email
|
||||
searchEmailRecipients(establishmentId, query): Promise<Array<User>>
|
||||
```
|
||||
|
||||
## Modèles de Données
|
||||
|
||||
### Conversation
|
||||
|
||||
```javascript
|
||||
{
|
||||
conversation_id: number,
|
||||
participants: Array<User>,
|
||||
last_message: Message,
|
||||
created_at: string,
|
||||
updated_at: string
|
||||
}
|
||||
```
|
||||
|
||||
### Message
|
||||
|
||||
```javascript
|
||||
{
|
||||
id: number,
|
||||
conversation_id: number,
|
||||
sender_id: number,
|
||||
content: string,
|
||||
timestamp: string,
|
||||
is_read: boolean
|
||||
}
|
||||
```
|
||||
|
||||
### User
|
||||
|
||||
```javascript
|
||||
{
|
||||
id: number,
|
||||
first_name: string,
|
||||
last_name: string,
|
||||
email: string,
|
||||
role: string
|
||||
}
|
||||
```
|
||||
|
||||
## Gestion des Erreurs
|
||||
|
||||
### WebSocket
|
||||
|
||||
```javascript
|
||||
// Reconnexion automatique
|
||||
const reconnectWebSocket = () => {
|
||||
setConnectionStatus('reconnecting');
|
||||
// Logique de reconnexion avec backoff exponentiel
|
||||
};
|
||||
|
||||
// Gestion des erreurs de connexion
|
||||
wsRef.current.onerror = (error) => {
|
||||
logger.error('Erreur WebSocket:', error);
|
||||
setIsConnected(false);
|
||||
};
|
||||
```
|
||||
|
||||
### API REST
|
||||
|
||||
```javascript
|
||||
// Wrapper avec gestion d'erreur
|
||||
const apiCall = async (url, options) => {
|
||||
try {
|
||||
const response = await fetch(url, options);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Erreur ${response.status}`);
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
logger.error('Erreur API:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Configuration des Tests
|
||||
|
||||
### Jest Setup
|
||||
|
||||
```javascript
|
||||
// jest.setup.js
|
||||
global.WebSocket = class MockWebSocket {
|
||||
// Mock complet du WebSocket pour les tests
|
||||
};
|
||||
|
||||
global.fetch = jest.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve([]),
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
### Tests des Composants
|
||||
|
||||
```javascript
|
||||
// Exemple de test
|
||||
test('renders InstantChat component', async () => {
|
||||
await act(async () => {
|
||||
render(<InstantChat userProfileId={1} establishmentId={123} />);
|
||||
});
|
||||
|
||||
expect(screen.getByText('Messages')).toBeInTheDocument();
|
||||
});
|
||||
```
|
||||
|
||||
## Intégration Backend
|
||||
|
||||
### Consumer Django
|
||||
|
||||
```python
|
||||
# consumers.py
|
||||
class ChatConsumer(AsyncWebsocketConsumer):
|
||||
async def connect(self):
|
||||
# Logique de connexion
|
||||
|
||||
async def chat_message(self, event):
|
||||
# Traitement des messages
|
||||
```
|
||||
|
||||
### URLs Configuration
|
||||
|
||||
```python
|
||||
# routing.py
|
||||
websocket_urlpatterns = [
|
||||
re_path(r'ws/chat/(?P<user_id>\w+)/$', ChatConsumer.as_asgi()),
|
||||
]
|
||||
```
|
||||
|
||||
## Optimisations
|
||||
|
||||
### Performance
|
||||
|
||||
- Pagination des messages anciens (load on scroll)
|
||||
- Debounce pour la recherche de contacts (300ms)
|
||||
- Memoization des composants avec React.memo
|
||||
- Lazy loading des conversations
|
||||
|
||||
### UX
|
||||
|
||||
- Reconnexion automatique avec feedback visuel
|
||||
- Sauvegarde locale des messages en cours de frappe
|
||||
- Indicateurs de livraison des messages
|
||||
- Scrolling automatique vers les nouveaux messages
|
||||
Reference in New Issue
Block a user