changement de la logique des messages
This commit is contained in:
@@ -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()],
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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`);
|
||||
}
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user