feat: migrate ContactsComponent & ContactDetailComponent to Django Rest

This commit is contained in:
Chneemann 2025-03-30 09:46:38 +02:00
parent 7b85ad5493
commit e995696882
9 changed files with 129 additions and 59 deletions

View file

@ -9,45 +9,45 @@
</div> </div>
<div class="btn-back"> <div class="btn-back">
<img <img
[ngClass]="{ 'd-none': !currentUserId }" [ngClass]="{ 'd-none': !selectedUserId }"
(click)="closeUserDetails()" (click)="closeUserDetails()"
src="./../../../../assets/img/arrow-left.svg" src="./../../../../assets/img/arrow-left.svg"
/> />
</div> </div>
</div> </div>
@if (currentUserId) { @for (user of checkUserData(currentUserId); track user) @if (selectedUser && selectedUserId) {
{
<div <div
class="contact-details" class="contact-details"
[ngClass]="{ [ngClass]="{
'animation-coming-in': currentUserId 'animation-coming-in': selectedUserId
}" }"
> >
<div class="content"> <div class="content">
<div <div
class="circle" class="circle"
[ngStyle]="{ [ngStyle]="{
'background-color': user.color 'background-color': selectedUser.color
}" }"
> >
@if(user.status) { @if(selectedUser.isOnline) {
<img src="./../../../assets/img/online.svg" alt="" /> <img src="./../../../assets/img/online.svg" alt="" />
} @else { } @else {
<img src="./../../../assets/img/offline.svg" alt="" /> <img src="./../../../assets/img/offline.svg" alt="" />
} }
<div class="initials"> <div class="initials">
{{ user.initials }} {{ selectedUser.initials }}
</div> </div>
</div> </div>
<div class="word-wrap"> <div class="word-wrap">
<div class="name"> <div class="name">
{{ user.firstName }} {{ selectedUser.firstName }}
{{ user.lastName }} {{ selectedUser.lastName }}
@if (user.id === firebaseService.getCurrentUserId()) { @if (currentUser && selectedUser.id === currentUser.id) {
{{ "contacts.you" | translate }} {{ "contacts.you" | translate }}
} }
</div> </div>
@if(user.uId === "" || user.id === firebaseService.getCurrentUserId()) { @if(selectedUser.isContactOnly || currentUser && selectedUser.id ===
currentUser.id) {
<div class="btns"> <div class="btns">
<div class="btn btn-edit"> <div class="btn btn-edit">
<img src="./../../../../assets/img/contact/edit.svg" alt="" /> <img src="./../../../../assets/img/contact/edit.svg" alt="" />
@ -55,7 +55,8 @@
{{ "contacts.btnEdit0" | translate }} {{ "contacts.btnEdit0" | translate }}
</p> </p>
</div> </div>
@if (user.id !== firebaseService.getCurrentUserId()) { @if (selectedUser.isContactOnly || currentUser && selectedUser.id !==
currentUser.id) {
<div class="btn btn-delete"> <div class="btn btn-delete">
<img src="./../../../../assets/img/contact/delete.svg" alt="" /> <img src="./../../../../assets/img/contact/delete.svg" alt="" />
<p (click)="deleteContact()"> <p (click)="deleteContact()">
@ -74,21 +75,21 @@
<div class="headline">{{ "contacts.contactInfo" | translate }}</div> <div class="headline">{{ "contacts.contactInfo" | translate }}</div>
<div class="info"> <div class="info">
<p>{{ "contacts.contactEmail" | translate }}</p> <p>{{ "contacts.contactEmail" | translate }}</p>
<a [href]="'mail:' + user.email"> <a [href]="'mail:' + selectedUser.email">
{{ user.email }} {{ selectedUser.email }}
</a> </a>
<p>{{ "contacts.contactPhone" | translate }}</p> <p>{{ "contacts.contactPhone" | translate }}</p>
@if(user.phone === '') { @if(selectedUser.phone === '') {
<span>{{ "contacts.contactPhoneTxT" | translate }}</span> } @else { <span>{{ "contacts.contactPhoneTxT" | translate }}</span> } @else {
<a [href]="'tel:' + user.phone"> <a [href]="'tel:' + selectedUser.phone">
<span>{{ user.phone }}</span> <span>{{ selectedUser.phone }}</span>
</a> </a>
} @if(user.uId !== "") { } @if(selectedUser.uId !== "") {
<p>{{ "contacts.contactLastOnline" | translate }}</p> <p>{{ "contacts.contactLastOnline" | translate }}</p>
@if(user.status) { @if(selectedUser.isOnline) {
<span>{{ "contacts.contactLastOnlineTxt" | translate }}</span> <span>{{ "contacts.contactLastOnlineTxt" | translate }}</span>
} @else { } @else {
<span>{{ convertTimestamp(user.lastLogin) }}</span> <span>{{ convertTimestamp(selectedUser.lastLogin) }}</span>
} } } }
</div> </div>
</div> </div>
@ -98,5 +99,5 @@
[deleteContact]="deleteContact" [deleteContact]="deleteContact"
[openEditDialog]="openEditDialog" [openEditDialog]="openEditDialog"
></app-contact-nav> ></app-contact-nav>
}} }
</section> </section>

View file

@ -4,6 +4,7 @@ import {
HostListener, HostListener,
Input, Input,
Output, Output,
SimpleChanges,
} from '@angular/core'; } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
@ -12,6 +13,9 @@ import { ContactNavComponent } from '../contact-nav/contact-nav.component';
import { FirebaseService } from '../../../services/firebase.service'; import { FirebaseService } from '../../../services/firebase.service';
import { LanguageService } from '../../../services/language.service'; import { LanguageService } from '../../../services/language.service';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { UserService } from '../../../services/user.service';
import { finalize } from 'rxjs';
import { User } from '../../../interfaces/user.interface';
@Component({ @Component({
selector: 'app-contact-detail', selector: 'app-contact-detail',
@ -21,34 +25,59 @@ import { TranslateModule } from '@ngx-translate/core';
styleUrl: './contact-detail.component.scss', styleUrl: './contact-detail.component.scss',
}) })
export class ContactDetailComponent { export class ContactDetailComponent {
@Input() currentUserId: string | undefined; @Input() selectedUserId: string | undefined;
@Input() currentUser: User | null = null;
@Output() closeContactEmitter = new EventEmitter<boolean>(); @Output() closeContactEmitter = new EventEmitter<boolean>();
isLoading: boolean = false;
selectedUser: User | null = null;
constructor( constructor(
private router: Router, private router: Router,
public sharedService: SharedService, public sharedService: SharedService,
public firebaseService: FirebaseService, public firebaseService: FirebaseService,
private userService: UserService,
private languageService: LanguageService private languageService: LanguageService
) {} ) {}
ngOnChanges(changes: SimpleChanges) {
if (
changes['selectedUserId'] !== undefined &&
changes['selectedUserId'].currentValue !== ''
) {
this.loadUser();
} else {
this.selectedUser = null;
}
}
/** /**
* Closes the contact details view by resetting the current user id in the * Closes the contact details view by resetting the current user id in the
* shared service and emitting the closeContactEmitter event. * shared service and emitting the closeContactEmitter event.
*/ */
closeUserDetails() { closeUserDetails() {
this.sharedService.currentUserId = '';
this.closeContactEmitter.emit(); this.closeContactEmitter.emit();
} }
/** loadUser(): void {
* Checks if a user with the given user id exists in the database. this.isLoading = true;
* @param userId the id of the user
* @returns an array of user objects that match the given user id if (!this.selectedUserId) {
*/ this.isLoading = false;
checkUserData(userId: string) { return;
return this.firebaseService }
.getAllUsers()
.filter((user) => user.id === userId); this.userService
.getUserById(this.selectedUserId)
.pipe(finalize(() => (this.isLoading = false)))
.subscribe({
next: (response) => {
this.selectedUser = response;
},
error: (err) => {
console.error('Error loading the tasks:', err);
},
});
} }
/** /**

View file

@ -54,7 +54,8 @@ export class ContactFormComponent implements OnInit, OnChanges {
phone: '', phone: '',
initials: '', initials: '',
color: '', color: '',
status: false, isContactOnly: true,
isOnline: false,
lastLogin: 0, lastLogin: 0,
}; };

View file

@ -2,7 +2,7 @@
<div <div
class="left-frame" class="left-frame"
[ngClass]="{ [ngClass]="{
'd-none': !showAllUsers && sharedService.currentUserId != undefined 'd-none': !showAllUsers && selectedUserId != undefined
}" }"
> >
<button class="btn-new" type="submit" (click)="openNewContactDialog()"> <button class="btn-new" type="submit" (click)="openNewContactDialog()">
@ -24,7 +24,7 @@
class="contact" class="contact"
(click)="showUserId(user.id)" (click)="showUserId(user.id)"
[ngClass]="{ [ngClass]="{
'contact-active': sharedService.currentUserId === user.id 'contact-active': selectedUserId === user.id
}" }"
> >
<div <div
@ -33,7 +33,7 @@
'background-color': user.color 'background-color': user.color
}" }"
> >
@if(user.status) { @if(user.isOnline) {
<img src="./../../../assets/img/online.svg" alt="" /> <img src="./../../../assets/img/online.svg" alt="" />
} @else { } @else {
<img src="./../../../assets/img/offline.svg" alt="" /> <img src="./../../../assets/img/offline.svg" alt="" />
@ -47,11 +47,12 @@
<p> <p>
{{ user.firstName }} {{ user.firstName }}
</p> </p>
<span>,&nbsp;</span> @if (user.lastName ) {
<p class="last-name"> <p class="last-name">
<span>,</span>
{{ user.lastName }} {{ user.lastName }}
</p> </p>
@if (user.id === firebaseService.getCurrentUserId()) { } @if (currentUser && user.id === currentUser.id ) {
<p>&nbsp;{{ "contacts.you" | translate }}</p> <p>&nbsp;{{ "contacts.you" | translate }}</p>
} }
</div> </div>
@ -66,9 +67,10 @@
<div class="right-frame"> <div class="right-frame">
<app-contact-detail <app-contact-detail
[ngClass]="{ [ngClass]="{
'd-none': !showAllUsers && sharedService.currentUserId == undefined 'd-none': !showAllUsers && selectedUserId == undefined
}" }"
[currentUserId]="sharedService.currentUserId" [selectedUserId]="selectedUserId"
[currentUser]="currentUser"
(closeContactEmitter)="closeContactEmitter()" (closeContactEmitter)="closeContactEmitter()"
></app-contact-detail> ></app-contact-detail>
</div> </div>

View file

@ -6,6 +6,9 @@ import { ContactDetailComponent } from './contact-detail/contact-detail.componen
import { SharedService } from '../../services/shared.service'; import { SharedService } from '../../services/shared.service';
import { FirebaseService } from '../../services/firebase.service'; import { FirebaseService } from '../../services/firebase.service';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { ApiService } from '../../services/api.service';
import { UserService } from '../../services/user.service';
import { finalize } from 'rxjs';
@Component({ @Component({
selector: 'app-contacts', selector: 'app-contacts',
@ -16,13 +19,16 @@ import { TranslateModule } from '@ngx-translate/core';
}) })
export class ContactsComponent { export class ContactsComponent {
allUsers: User[] = []; allUsers: User[] = [];
currentUser: User | null = null;
selectedUserId: string | undefined;
usersFirstLetter: string[] = []; usersFirstLetter: string[] = [];
usersByFirstLetter: { [key: string]: string[] } = {}; usersByFirstLetter: { [key: string]: string[] } = {};
showAllUsers: boolean = false; showAllUsers: boolean = false;
isLoading: boolean = false;
constructor( constructor(
public firebaseService: FirebaseService, public firebaseService: FirebaseService,
private route: ActivatedRoute, private userService: UserService,
public sharedService: SharedService public sharedService: SharedService
) {} ) {}
@ -31,6 +37,8 @@ export class ContactsComponent {
*/ */
ngOnInit(): void { ngOnInit(): void {
this.onResize(); this.onResize();
this.loadAllUsers();
this.loadCurrentUser();
} }
@HostListener('window:resize', ['$event']) @HostListener('window:resize', ['$event'])
@ -43,20 +51,42 @@ export class ContactsComponent {
* to true. * to true.
*/ */
onResize() { onResize() {
if (window.innerWidth <= 1150 && this.sharedService.currentUserId != '') { if (window.innerWidth <= 1150 && this.selectedUserId != undefined) {
this.showAllUsers = false; this.showAllUsers = false;
} else { } else {
this.showAllUsers = true; this.showAllUsers = true;
} }
} }
loadAllUsers(): void {
this.isLoading = true;
this.userService
.getUsers()
.pipe(finalize(() => (this.isLoading = false)))
.subscribe({
next: (response) => {
this.allUsers = response;
},
error: (err) => {
console.error('Error loading the tasks:', err);
},
});
}
loadCurrentUser(): void {
this.userService.getCurrentUser().subscribe((userData) => {
this.currentUser = userData;
});
}
/** /**
* Updates the shared service current user id and triggers the resize function. * Updates the shared service current user id and triggers the resize function.
* If the parameter is not given, it resets the current user id to an empty string. * If the parameter is not given, it resets the current user id to an empty string.
* @param userId - the id of the user to be set as the current user id * @param userId - the id of the user to be set as the current user id
*/ */
showUserId(userId: string = '') { showUserId(userId: string = '') {
this.sharedService.currentUserId = userId; this.selectedUserId = userId;
this.onResize(); this.onResize();
} }
@ -64,26 +94,17 @@ export class ContactsComponent {
* Triggers the resize function to adjust UI elements based on the current state. * Triggers the resize function to adjust UI elements based on the current state.
*/ */
closeContactEmitter() { closeContactEmitter() {
this.selectedUserId = undefined;
this.onResize(); this.onResize();
} }
/**
* Returns an array of users without the guest user.
* @returns An array of users
*/
loadAllUserWithoutGuest(): User[] {
return this.firebaseService
.getAllUsers()
.filter((user) => user.initials !== 'G');
}
/** /**
* Sorts the users array by the first letter of the user's initials, and filters it by the given sort letter. * Sorts the users array by the first letter of the user's initials, and filters it by the given sort letter.
* @param sortLetter - the letter to filter the users by * @param sortLetter - the letter to filter the users by
* @returns An array of users with the given sort letter * @returns An array of users with the given sort letter
*/ */
sortUsersByFirstLetter(sortLetter: string) { sortUsersByFirstLetter(sortLetter: string) {
return this.loadAllUserWithoutGuest().filter( return this.allUsers.filter(
(user) => user.initials.substring(0, 1) === sortLetter (user) => user.initials.substring(0, 1) === sortLetter
); );
} }
@ -97,7 +118,7 @@ export class ContactsComponent {
* @returns An array of unique first letters * @returns An array of unique first letters
*/ */
sortFirstLetter() { sortFirstLetter() {
let filterteArray = this.loadAllUserWithoutGuest().sort((a, b) => let filterteArray = this.allUsers.sort((a, b) =>
a.firstName.localeCompare(b.firstName) a.firstName.localeCompare(b.firstName)
); );
let usersFirstLetter = Array.from( let usersFirstLetter = Array.from(

View file

@ -7,7 +7,8 @@ export interface User {
phone: string; phone: string;
initials: string; initials: string;
color: string; color: string;
status: boolean; isOnline: boolean;
isContactOnly: boolean;
lastLogin: number; lastLogin: number;
} }

View file

@ -60,6 +60,10 @@ export class ApiService {
// ------------- USERS ------------- // // ------------- USERS ------------- //
getUsers(): Observable<User[]> {
return this.request<User[]>('GET', `/api/users/`);
}
getUserById(userId: string): Observable<User> { getUserById(userId: string): Observable<User> {
return this.request<User>('GET', `/api/users/${userId}/`); return this.request<User>('GET', `/api/users/${userId}/`);
} }

View file

@ -117,7 +117,8 @@ export class LoginService {
? registerData.lastName.charAt(0).toUpperCase() + ? registerData.lastName.charAt(0).toUpperCase() +
registerData.lastName.slice(1) registerData.lastName.slice(1)
: '', : '',
status: true, isContactOnly: false,
isOnline: true,
phone: '', phone: '',
initials: registerData.name initials: registerData.name
? registerData.firstName.slice(0, 1).toUpperCase() + ? registerData.firstName.slice(0, 1).toUpperCase() +
@ -164,7 +165,8 @@ export class LoginService {
email: user.email || 'no mail', email: user.email || 'no mail',
firstName: firstName.charAt(0).toUpperCase() + firstName.slice(1), firstName: firstName.charAt(0).toUpperCase() + firstName.slice(1),
lastName: lastName.charAt(0).toUpperCase() + lastName.slice(1), lastName: lastName.charAt(0).toUpperCase() + lastName.slice(1),
status: true, isContactOnly: false,
isOnline: true,
phone: '', phone: '',
initials: firstName.slice(0, 1) + lastName.slice(0, 1), initials: firstName.slice(0, 1) + lastName.slice(0, 1),
color: this.sharedService.generateRandomColor(), color: this.sharedService.generateRandomColor(),
@ -192,7 +194,8 @@ export class LoginService {
email: user.email, email: user.email,
firstName: user.firstName || '', firstName: user.firstName || '',
lastName: user.lastName || '', lastName: user.lastName || '',
status: true, isContactOnly: false,
isOnline: true,
phone: '', phone: '',
initials: user.initials, initials: user.initials,
color: user.color, color: user.color,

View file

@ -63,4 +63,12 @@ export class UserService {
}) })
); );
} }
getUsers(): Observable<User[]> {
return this.apiService.getUsers();
}
getUserById(userId: string): Observable<User> {
return this.apiService.getUserById(userId);
}
} }