docs: add JSDoc comments to ContactComponent

This commit is contained in:
Chneemann 2024-11-12 04:43:17 +01:00
parent 7e32e16cdf
commit d8701f5cb9
5 changed files with 210 additions and 19 deletions

View file

@ -20,6 +20,12 @@ export class ContactDeleteComponent {
private router: Router
) {}
/**
* Deletes the current user and performs cleanup operations.
* This method deletes the user with the current user ID from the database,
* navigates to the contacts page, and closes any open dialog flags in the shared service.
* It also checks if the deleted contact was assigned to any tasks and removes them.
*/
deleteContact() {
this.firebaseService.deleteUser(this.currentUserId);
this.router.navigate(['contacts']);
@ -28,6 +34,13 @@ export class ContactDeleteComponent {
this.checkIfContactAnAssigned();
}
/**
* Checks if the deleted contact was assigned to any tasks and removes them.
* This method retrieves all tasks from the database, iterates over them,
* and checks if the current user ID is in the task's assigned array.
* If the ID is found, it is removed from the array and the modified task
* is updated in the database.
*/
checkIfContactAnAssigned() {
const tasks = this.firebaseService.getAllTasks();
@ -43,6 +56,10 @@ export class ContactDeleteComponent {
});
}
/**
* Closes the delete contact dialog by setting the appropriate flags in the shared service.
* If the edit contact dialog is not open, it also closes any open dialog flags in the shared service.
*/
cancelDeleteContact() {
this.sharedService.isDeleteContactDialogOpen = false;
if (!this.sharedService.isEditContactDialogOpen) {

View file

@ -6,24 +6,17 @@ import {
Output,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { ContactsComponent } from '../contacts.component';
import { Router } from '@angular/router';
import { SharedService } from '../../../services/shared.service';
import { ContactNavComponent } from '../contact-nav/contact-nav.component';
import { FirebaseService } from '../../../services/firebase.service';
import { LanguageService } from '../../../services/language.service';
import { TranslateModule } from '@ngx-translate/core';
import { ContactEditNewComponent } from '../contact-edit-new/contact-edit-new.component';
@Component({
selector: 'app-contact-detail',
standalone: true,
imports: [
CommonModule,
ContactsComponent,
ContactEditNewComponent,
ContactNavComponent,
TranslateModule,
],
imports: [CommonModule, TranslateModule, ContactNavComponent],
templateUrl: './contact-detail.component.html',
styleUrl: './contact-detail.component.scss',
})
@ -38,34 +31,61 @@ export class ContactDetailComponent {
private languageService: LanguageService
) {}
/**
* Closes the contact details view by resetting the current user id in the
* shared service and emitting the closeContactEmitter event.
*/
closeUserDetails() {
this.sharedService.currentUserId = '';
this.closeContactEmitter.emit();
}
/**
* Checks if a user with the given user id exists in the database.
* @param userId the id of the user
* @returns an array of user objects that match the given user id
*/
checkUserData(userId: string) {
return this.firebaseService
.getAllUsers()
.filter((user) => user.id === userId);
}
/**
* Toggles the mobile navigation bar on and off.
* @remarks This method is used by the contact details component to toggle
* the mobile navigation bar when the user clicks the three points icon.
*/
toggleNav() {
this.sharedService.isMobileNavbarOpen =
!this.sharedService.isMobileNavbarOpen;
}
/**
* Opens the edit contact dialog by setting the appropriate flags in the shared service.
* This method is used by the contact details component to open the edit contact dialog when the user clicks the edit button.
*/
openEditDialog() {
this.sharedService.isAnyDialogOpen = true;
this.sharedService.isEditContactDialogOpen = true;
this.sharedService.isMobileNavbarOpen = false;
}
/**
* Opens the delete contact dialog by setting the appropriate flags in the shared service.
* This method is used by the contact details component to open the delete contact dialog when the user clicks the delete button.
*/
deleteContact() {
this.sharedService.isAnyDialogOpen = true;
this.sharedService.isDeleteContactDialogOpen = true;
this.sharedService.isMobileNavbarOpen = false;
}
/**
* Converts a given timestamp to a human-readable date string.
* @param timestamp the timestamp to convert
* @returns a string in the format "DD. MMM. YYYY - HH:mm" in German or "MMM. DD, YYYY - hh:mm A" in English
*/
convertTimestamp(timestamp: number) {
const date = new Date(timestamp);
const monthsEN = [
@ -111,6 +131,11 @@ export class ContactDetailComponent {
}
}
/**
* Converts a given timestamp to a human-readable time string in English.
* @param timestamp the timestamp to convert
* @returns a string in the format "hh:mm:ss AM/PM"
*/
convertTimestampHourEN(timestamp: number) {
const date = new Date(timestamp * 1000);
let hour = date.getHours();
@ -124,6 +149,12 @@ export class ContactDetailComponent {
return `${hourWithNull}:${minute}:${second} ${period}`;
}
/**
* Converts a given timestamp to a human-readable time string in German.
*
* @param timestamp The timestamp to convert, in seconds.
* @returns A string in the format "HH:mm:ss Uhr".
*/
convertTimestampHourDE(timestamp: number) {
const date = new Date(timestamp * 1000);
let hour = date.getHours();
@ -134,6 +165,12 @@ export class ContactDetailComponent {
}
@HostListener('document:click', ['$event'])
/**
* Handles the opening of the contact edit, new contact, and delete contact
* dialogs when the respective buttons are clicked.
*
* @param event The MouseEvent that was triggered.
*/
checkOpenContactEdit(event: MouseEvent) {
const targetElement = event.target as HTMLElement;
@ -148,6 +185,14 @@ export class ContactDetailComponent {
}
}
/**
* Updates the dialog status flags in the shared service.
*
* @param anyOpen - Indicates if any dialog is open.
* @param editOpen - Indicates if the edit contact dialog is open.
* @param newOpen - Indicates if the new contact dialog is open.
* @param deleteOpen - Indicates if the delete contact dialog is open.
*/
private setDialogStatus(
anyOpen: boolean,
editOpen: boolean,

View file

@ -33,15 +33,32 @@ export class ContactEditNewComponent implements OnInit {
public sharedService: SharedService
) {}
/**
* Lifecycle hook that is called after data-bound properties of a directive are
* initialized.
* This method sets a random color for the user to be edited.
*/
ngOnInit() {
this.randomColor = this.sharedService.generateRandomColor();
}
/**
* This method is an event emitter that listens for changes to the user's initials.
* It is called by the contact form component and updates the userInitials
* variable with the new initials.
*
* @param emitter The new initials of the user.
*/
initialsEmitter(emitter: string) {
this.userInitials = emitter;
}
/**
* Updates the newColor variable with the newly selected color.
*
* @param newColor The new color to be set.
*/
updateColor(newColor: string) {
this.newColor = newColor;
}
ngOnInit() {
this.randomColor = this.sharedService.generateRandomColor();
}
}

View file

@ -58,6 +58,12 @@ export class ContactFormComponent implements OnInit, OnChanges {
lastLogin: 0,
};
/**
* OnInit lifecycle hook.
*
* If the currentUserId input property is empty, it sets the color and lastLogin
* properties of the userData object.
*/
ngOnInit() {
if (!this.currentUserId) {
this.userData = {
@ -68,17 +74,33 @@ export class ContactFormComponent implements OnInit, OnChanges {
}
}
/**
* Lifecycle hook that is called whenever the input properties of the component change.
*
* If the currentUserId input property has changed, it calls the updateContactData method.
* @param changes an object containing the changed input properties
*/
ngOnChanges(changes: SimpleChanges) {
if (changes['currentUserId']) {
this.updateContactData();
}
}
/**
* Updates the form data by calling helper methods to update the initials and user data.
*/
updateFormData() {
this.updateInitials();
this.updateUserData();
}
/**
* Updates the initials property of the userData object by extracting the first letter
* of the firstName and lastName properties of the contactData object. If the
* currentUserId input property is empty, it sets the initials property of the
* userData object, otherwise it sets the initials property of the contactData object.
* Finally, it emits an event containing the initials.
*/
updateInitials() {
const initials = this.contactData
? this.contactData.firstName.slice(0, 1).toUpperCase() +
@ -98,6 +120,12 @@ export class ContactFormComponent implements OnInit, OnChanges {
this.initialsEmitter.emit(initials);
}
/**
* Updates the userData or contactData object by copying the properties from the
* other object and capitalizing the first letter of the firstName and lastName
* properties. If the currentUserId input property is empty, it updates the userData
* object. Otherwise, it updates the contactData object.
*/
updateUserData() {
if (!this.currentUserId) {
this.userData = {
@ -116,10 +144,23 @@ export class ContactFormComponent implements OnInit, OnChanges {
}
}
/**
* Returns a string with the first letter capitalized and the rest of the letters
* in lower case.
*
* @param {string} name - The string to modify.
* @return {string} The modified string.
*/
capitalizeFirstLetter(name: string) {
return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
}
/**
* Validates if the given email address matches the standard email format.
*
* @param {string} emailValue - The email address to validate.
* @return {boolean} Returns true if the email address is in a valid format, otherwise false.
*/
checkIfUserEmailIsValid(emailValue: string) {
const emailRegex = /^[\w.%+-]+@[\w.-]+\.[a-zA-Z]{2,}$/;
if (emailRegex.test(emailValue)) {
@ -129,12 +170,25 @@ export class ContactFormComponent implements OnInit, OnChanges {
}
}
/**
* Returns an array of users that have the same email address as the given argument.
* This is used to check for duplicate email addresses when adding or editing a contact.
* @param {string} mail - The email address to check.
* @return {User[]} An array of users with the same email address.
*/
existEmailOnServer(mail: string) {
return this.firebaseService
.getAllUsers()
.filter((user) => user.email === mail);
}
/**
* Updates the contactData object with user details retrieved from the Firebase service.
* It fetches the first name, last name, email, phone number, and initials of the user
* associated with the currentUserId from the Firebase database and assigns these values to the
* respective properties of the contactData object. The values are expected to be arrays and are
* joined into strings using a comma separator.
*/
private updateContactData() {
this.contactData.firstName = this.firebaseService
.getUserDetails(this.currentUserId, 'firstName')
@ -153,6 +207,14 @@ export class ContactFormComponent implements OnInit, OnChanges {
.join(', ');
}
/**
* Submits the form when the user clicks the submit button. If the form is valid,
* it either updates the existing contact if currentUserId is set, or adds a new
* contact if currentUserId is empty. When the operation is completed, it closes
* the contact dialog.
*
* @param ngForm - The angular form object.
*/
onSubmit(ngForm: NgForm) {
if (ngForm.submitted && ngForm.form.valid) {
if (this.currentUserId) {
@ -178,11 +240,19 @@ export class ContactFormComponent implements OnInit, OnChanges {
}
}
/**
* Closes the delete contact dialog and the main dialog overlay.
*/
deleteContact() {
this.sharedService.isDeleteContactDialogOpen = false;
this.sharedService.isAnyDialogOpen = false;
}
/**
* Closes the contact dialog by updating the shared service flags
* to indicate that no dialog, edit contact dialog, or new contact dialog
* is currently open.
*/
closeDialog() {
this.sharedService.isAnyDialogOpen = false;
this.sharedService.isEditContactDialogOpen = false;

View file

@ -10,7 +10,7 @@ import { TranslateModule } from '@ngx-translate/core';
@Component({
selector: 'app-contacts',
standalone: true,
imports: [CommonModule, RouterLink, ContactDetailComponent, TranslateModule],
imports: [CommonModule, ContactDetailComponent, TranslateModule],
templateUrl: './contacts.component.html',
styleUrl: './contacts.component.scss',
})
@ -26,16 +26,22 @@ export class ContactsComponent {
public sharedService: SharedService
) {}
/**
* Trigger onResize when the component is initialized
*/
ngOnInit(): void {
this.onResize();
}
showUserId(userId: string = '') {
this.sharedService.currentUserId = userId;
this.onResize();
}
@HostListener('window:resize', ['$event'])
/**
* Toggles the showAllUsers variable based on the window width and the
* currentUserId of the shared service.
*
* If the window width is less than or equal to 1150px and the currentUserId
* is not empty, showAllUsers is set to false. Otherwise, showAllUsers is set
* to true.
*/
onResize() {
if (window.innerWidth <= 1150 && this.sharedService.currentUserId != '') {
this.showAllUsers = false;
@ -44,22 +50,52 @@ export class ContactsComponent {
}
}
/**
* 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.
* @param userId - the id of the user to be set as the current user id
*/
showUserId(userId: string = '') {
this.sharedService.currentUserId = userId;
this.onResize();
}
/**
* Triggers the resize function to adjust UI elements based on the current state.
*/
closeContactEmitter() {
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.
* @param sortLetter - the letter to filter the users by
* @returns An array of users with the given sort letter
*/
sortUsersByFirstLetter(sortLetter: string) {
return this.loadAllUserWithoutGuest().filter(
(user) => user.initials.substring(0, 1) === sortLetter
);
}
/**
* Returns an array of unique first letters from the sorted array of users.
* The users array is first sorted by the first letter of the user's first name,
* and then the first letter of each user's first name is extracted and
* converted to uppercase. The resulting array is then deduplicated with a
* Set, and the unique letters are returned in an array.
* @returns An array of unique first letters
*/
sortFirstLetter() {
let filterteArray = this.loadAllUserWithoutGuest().sort((a, b) =>
a.firstName.localeCompare(b.firstName)
@ -70,6 +106,12 @@ export class ContactsComponent {
return usersFirstLetter;
}
/**
* Opens the new contact dialog.
* This function sets the isAnyDialogOpen and isNewContactDialogOpen
* properties of the shared service to true, which will open the new contact
* dialog.
*/
openNewContactDialog() {
this.sharedService.isAnyDialogOpen = true;
this.sharedService.isNewContactDialogOpen = true;