changement de la logique des messages

This commit is contained in:
gokhoal
2026-06-08 21:31:41 +02:00
parent bff995151f
commit 1cc9688d00
15 changed files with 260 additions and 149 deletions
+3 -1
View File
@@ -3,7 +3,9 @@ import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideIonicAngular } from '@ionic/angular/standalone';
import {provideHttpClient} from "@angular/common/http";
export const appConfig: ApplicationConfig = {
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideIonicAngular({})]
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideIonicAngular({}), provideHttpClient()],
};
+1 -1
View File
@@ -16,7 +16,7 @@ export const routes: Routes = [
},*/
{
path:'messages',
path: 'messages/:discussionId',
loadComponent: () => import('./pages/messages/messages-main/messages-main.component').then(x => x.MessagesMain)
},
{
-41
View File
@@ -1,41 +0,0 @@
import { Injectable } from '@angular/core';
import {tap} from "rxjs";
@Injectable({
providedIn: 'root'
})
export class LoginService {
/*
login(credentials: { name: string; password: string }) {
return this.http.post<LoginResponse>(`${this.apiUrl}/login`, credentials).pipe(
tap(response => this.setSession(response.token))
);
}
*/
/*
refreshToken(): Observable<RefreshResponse> {
this.isRefreshing = true;
return this.http.post<RefreshResponse>(`${this.apiUrl}/refresh`, {})
.pipe(
tap(response => {
this.setSession(response.token);
}),
finalize(() => {
this.isRefreshing = false;
})
);
}
*/
/*
logout(){
return localStorage.removeItem('token');
this.currentUser.set(null);
this.router.navigate(['/login']);
}
*/
}
@@ -20,7 +20,7 @@
<ion-input type="password" placeholder="Password..."></ion-input>
</ion-item>
<ion-button expand="block" class="btn">
<ion-button expand="block" class="btn" (click)="submitForm()">
Se connecter
</ion-button>
@@ -1,21 +1,17 @@
import {Component, inject} from '@angular/core';
import { Component, inject } from '@angular/core';
import {
IonButton,
IonCard,
IonCardContent,
IonCardHeader,
IonCardTitle, IonContent, IonInput, IonItem, NavController,
IonButton, IonContent, IonInput, IonItem, NavController,
} from '@ionic/angular/standalone';
import {CommonModule} from "@angular/common";
import {FormBuilder, ReactiveFormsModule, Validators} from "@angular/forms";
import {Router} from "@angular/router";
import {LoginService} from "../../login.service";
import { CommonModule } from "@angular/common";
import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
import { Router } from "@angular/router";
import { LoginService } from "../../services/api/login.service";
@Component({
selector: 'login-form',
templateUrl: 'login-form.component.html',
styleUrls: ['login-form.component.css'],
imports: [IonButton, CommonModule, ReactiveFormsModule, IonItem, IonInput, IonContent,],
imports: [IonButton, CommonModule, ReactiveFormsModule, IonItem, IonInput, IonContent],
})
export class LoginFormComponent {
@@ -37,11 +33,6 @@ export class LoginFormComponent {
async submitForm(): Promise<void> {
if (this.loginForm.valid) {
await this.navCtrl.navigateRoot(['main/messages']);
this.isLoading = true;
const request = {
@@ -49,31 +40,29 @@ export class LoginFormComponent {
password: this.loginForm.value.password!
};
/*this.authService.login(request).subscribe({
next: () => {
this.loginService.login(request).subscribe({
next: (response) => {
this.isLoading = false;
this.notification.success('Succès', 'Connexion réussie !');
this.router.navigate(['/main/discussions']);
// Le discussionId vient de la réponse de l'API
this.navCtrl.navigateRoot(['main/messages', response.discussionId]);
},
error: (err) => {
this.isLoading = false;
// Gestion des erreurs (inchangée)
if (err.status === 401) {
this.notification.error('Erreur', 'Identifiant ou mot de passe incorrect.');
console.error('Identifiant ou mot de passe incorrect.');
} else {
this.notification.error('Erreur', 'Impossible de contacter le serveur.');
console.error('Impossible de contacter le serveur.');
}
}
});
} else {
// Affiche les erreurs de validation visuelles
Object.values(this.loginForm.controls).forEach(control => {
if (control.invalid) {
control.markAsDirty();
control.updateValueAndValidity({ onlySelf: true });
}
});*/
});
}
}
}
@@ -0,0 +1,52 @@
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap');
.discussions-list {
display: flex;
flex-direction: column;
gap: 10px;
width: 100%;
}
.discussion-btn {
display: flex;
align-items: center;
gap: 14px;
width: 100%;
padding: 12px 16px;
background: rgba(255, 255, 255, 0.88);
border: none;
border-radius: 50px;
box-shadow: 0 2px 10px rgba(180, 80, 80, 0.10);
cursor: pointer;
transition: transform 0.15s, box-shadow 0.15s;
img {
opacity: 0.7;
flex-shrink: 0;
}
&:active {
transform: scale(0.97);
box-shadow: 0 1px 5px rgba(180, 80, 80, 0.08);
}
}
.discussion-info {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.username {
font-family: 'Nunito', sans-serif;
font-size: 15px;
font-weight: 700;
color: #b05050;
}
.members {
font-family: 'Nunito', sans-serif;
font-size: 12px;
font-weight: 600;
color: #c98080;
}
@@ -1,4 +1,22 @@
<button class="users-btn">
<img width="50" height="50" src="https://img.icons8.com/ios/50/user-male-circle--v1.png" alt="user"/>
<span class="username">INFO NOM : </span>
</button>
<div class="discussions-list">
<button
class="discussion-btn"
*ngFor="let disc of discussions"
(click)="openDiscussion(disc.id)">
<img
width="36" height="36"
[src]="disc.isGroup
? 'https://img.icons8.com/ios/50/conference-call--v1.png'
: 'https://img.icons8.com/ios/50/user-male-circle--v1.png'"
alt="avatar"/>
<div class="discussion-info">
<span class="username">{{ disc.name }}</span>
<span class="members" *ngIf="disc.isGroup">
{{ disc.membersCount }} membres
</span>
</div>
</button>
</div>
@@ -1,11 +1,34 @@
import { Component } from '@angular/core';
import { Component, inject } from '@angular/core';
import { Router } from "@angular/router";
import { CommonModule } from "@angular/common";
export interface Discussion {
id: number;
name: string;
isGroup: boolean;
membersCount?: number;
}
@Component({
selector: 'app-menu-users',
imports: [],
imports: [CommonModule],
templateUrl: './menu-users.component.html',
styleUrl: './menu-users.component.css'
})
export class MenuUsersComponent {
}
private router = inject(Router);
discussions: Discussion[] = [
{ id: 1, name: 'Um-Bro', isGroup: false },
{ id: 2, name: 'Doggeybag', isGroup: false },
{ id: 3, name: '', isGroup: false },
{ id: 4, name: 'Abel Paradigm', isGroup: false },
{ id: 5, name: 'Um-Brothers', isGroup: true, membersCount: 7 },
{ id: 6, name: 'Hoodie G', isGroup: false },
];
openDiscussion(discussionId: number) {
this.router.navigate(['/main/messages', discussionId]);
}
}
@@ -17,7 +17,7 @@
</div>
<div class="bottombar">
<app-messages-send/>
<app-messages-send [discussionId]="currentdiscussionId" />
</div>
</div>
@@ -1,19 +1,22 @@
import { Component } from '@angular/core';
import {MessagesMenu} from "../messages-menu/messages-menu.component";
import {MessagesInfoUser} from "../messages-infouser/messages-infouser.component";
import {MessagesSend} from "../messages-send/messages-send.component";
import {Router} from '@angular/router';
import { Component, inject, OnInit } from '@angular/core';
import { MessagesMenu } from "../messages-menu/messages-menu.component";
import { MessagesInfoUser } from "../messages-infouser/messages-infouser.component";
import { MessagesSend } from "../messages-send/messages-send.component";
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-messages-main',
imports: [
MessagesMenu,
MessagesInfoUser,
MessagesSend
],
imports: [MessagesMenu, MessagesInfoUser, MessagesSend],
templateUrl: './messages-main.component.html',
styleUrl: './messages-main.component.css'
})
export class MessagesMain {
export class MessagesMain implements OnInit {
}
private route = inject(ActivatedRoute);
currentdiscussionId!: string;
ngOnInit() {
this.currentdiscussionId = this.route.snapshot.paramMap.get('discussionId')!;
}
}
@@ -1,27 +1,38 @@
import { Component } from '@angular/core';
import {FormControl, FormsModule, ReactiveFormsModule} from "@angular/forms";
import { Component, inject, Input } from '@angular/core';
import { FormControl, FormsModule, ReactiveFormsModule } from "@angular/forms";
import { ChatService } from "../../../services/api/chat.service";
@Component({
selector: 'app-messages-send',
imports: [
FormsModule,
ReactiveFormsModule
],
templateUrl:'./messages-send.component.html',
imports: [FormsModule, ReactiveFormsModule],
templateUrl: './messages-send.component.html',
styleUrl: './messages-send.component.css'
})
export class MessagesSend {
sendMessage = new FormControl();
onSubmit() {
private chatService = inject(ChatService);
@Input() discussionId!: string; // passé par le composant parent
sendMessage = new FormControl();
isSending = false;
async onSubmit() {
const message = this.sendMessage.value;
if (!message || message.trim() === '') return;
if (this.isSending) return; // évite le double envoi
console.log('Message envoyé :', message);
this.isSending = true;
// Logique d'envoi
this.sendMessage.reset();
try {
await this.chatService.sendMessage(this.discussionId, message.trim());
this.sendMessage.reset();
} catch (error) {
console.error('Erreur lors de l\'envoi :', error);
// Afficher une notification d'erreur ici
} finally {
this.isSending = false;
}
}
}
+12 -20
View File
@@ -1,38 +1,30 @@
// chat.service.ts
import * as signalR from '@microsoft/signalr';
import {Injectable} from "@angular/core";
import { Injectable } from '@angular/core';
import { HubConnection, HubConnectionBuilder, HubConnectionState } from '@microsoft/signalr';
@Injectable({ providedIn: 'root' })
export class ChatService {
private hub: signalR.HubConnection;
private hub: HubConnection;
constructor() {
this.hub = new signalR.HubConnectionBuilder()
this.hub = new HubConnectionBuilder()
.withUrl('https://localhost:5001/hubs/chat')
.withAutomaticReconnect() // reconnexion auto si coupure réseau
.withAutomaticReconnect()
.build();
}
async connect() {
await this.hub.start();
if (this.hub.state === HubConnectionState.Disconnected) {
await this.hub.start();
}
}
async joinConversation(conversationId: string) {
await this.hub.invoke('JoinConversation', conversationId);
async sendMessage(discussionId: string, content: string) {
await this.connect(); // s'assure que la connexion est active
await this.hub.invoke('SendMessage', discussionId, content);
}
async sendMessage(conversationId: string, content: string) {
await this.hub.invoke('SendMessage', conversationId, content);
}
// Écouter les messages entrants
onMessage(callback: (msg: any) => void) {
onMessage(callback: (message: any) => void) {
this.hub.on('ReceiveMessage', callback);
}
// Écouter l'indicateur de frappe
onTyping(callback: (userId: string) => void) {
this.hub.on('UserTyping', callback);
}
}
@@ -0,0 +1,15 @@
import {Observable} from "rxjs";
import {Discussion} from "../../pages/menu/menu-users/menu-users.component";
import {HttpClient} from "@angular/common/http";
import {inject, Injectable} from "@angular/core";
@Injectable({ providedIn: 'root' })
export class discussionsService {
private http = inject(HttpClient);
private apiUrl = 'https://localhost:5001/API';
getDiscussions(): Observable<Discussion[]> {
return this.http.get<Discussion[]>(`${this.apiUrl}/discussions`);
}
}
+42
View File
@@ -0,0 +1,42 @@
import { Injectable, inject } from '@angular/core';
import { HttpClient } from "@angular/common/http";
import { Observable, tap, finalize } from "rxjs";
export interface LoginRequest {
name: string;
password: string;
}
export interface LoginResponse {
token: string;
discussionId: string;
}
@Injectable({
providedIn: 'root'
})
export class LoginService {
private http = inject(HttpClient);
private apiUrl = 'https://localhost:5001/API';
private isRefreshing = false;
login(credentials: LoginRequest): Observable<LoginResponse> {
return this.http.post<LoginResponse>(`${this.apiUrl}/auth/login`, credentials).pipe(
tap(response => localStorage.setItem('token', response.token))
);
}
refreshToken(): Observable<{ token: string }> {
this.isRefreshing = true;
return this.http.post<{ token: string }>(`${this.apiUrl}/auth/refresh`, {}).pipe(
tap(response => localStorage.setItem('token', response.token)),
finalize(() => { this.isRefreshing = false; })
);
}
logout() {
localStorage.removeItem('token');
}
}