Commit 327da6e1 authored by Almouhannad's avatar Almouhannad

(F) Add phones for doctors

parent 10de6317
......@@ -21,6 +21,8 @@ import { EmployeeComponent } from './components/receptionist/employee/employee.c
import { DoctorDashboardComponent } from './components/doctor/doctor-dashboard/doctor-dashboard.component';
import { HistoryComponent } from './components/doctor/history/history.component';
import { CreateVisitComponent } from './components/doctor/create-visit/create-visit.component';
import { DoctorPhonesComponent } from './components/doctor/doctor-phones/doctor-phones.component';
import { CreateDoctorPhoneComponent } from './components/doctor/create-doctor-phone/create-doctor-phone.component';
const routes: Routes = [
{
......@@ -100,6 +102,14 @@ const routes: Routes = [
path: 'visits/create/:id',
component: CreateVisitComponent
},
{
path: 'phones',
component: DoctorPhonesComponent
},
{
path: 'phones/create',
component: CreateDoctorPhoneComponent
},
]
},
......
......@@ -58,6 +58,9 @@ import { VisitsService } from './services/visits/visits.service';
import { ArabicDatePipe } from './pipes/arabic-date.pipe';
import { MedicinesService } from './services/medicines/medicines.service';
import { SearchForMedicineComponent } from './components/doctor/search-for-medicine/search-for-medicine.component';
import { DoctorPhoneComponent } from './components/doctor/doctor-phone/doctor-phone.component';
import { DoctorPhonesComponent } from './components/doctor/doctor-phones/doctor-phones.component';
import { CreateDoctorPhoneComponent } from './components/doctor/create-doctor-phone/create-doctor-phone.component';
@NgModule({
......@@ -136,6 +139,9 @@ import { SearchForMedicineComponent } from './components/doctor/search-for-medic
PatientIsComingNotificationComponent,
ArabicDatePipe,
SearchForMedicineComponent,
DoctorPhoneComponent,
DoctorPhonesComponent,
CreateDoctorPhoneComponent,
],
// identifies the root component that Angular should
......
export class DoctorPhone {
public name: string;
public phone: string;
constructor(name: string = '', phone: string = ''){
this.name = name;
this.phone = phone;
}
}
\ No newline at end of file
/* #region Form card*/
.custom-form {
width: 60%;
margin: auto;
padding: 1em;
border: 1px solid var(--accent-color);
border-radius: 3%;
}
/* #endregion */
/* #region Title*/
.custom-form .custom-form-title h3 {
width: 50%;
margin: auto;
padding: 0.5em;
border: 1px solid var(--accent-color);
border-radius: 10em;
}
/* #endregion */
/* #region Server error message*/
.custom-form .custom-server-error-message .btn{
width: 100%;
font-size: 1.2em;
font-weight: 700;
cursor: auto;
}
/* #endregion */
/* #region Buttons*/
.custom-buttons .btn {
font-weight: 700;
width: 50%;
margin: auto;
font-size: 1.2em;
}
.custom-buttons .btn i {
font-weight: 900;
font-size: 1.2em;
margin-right: 0.5em;
}
.custom-buttons .btn-outline-primary {
color: white;
background-color: var(--heading-color);
border-color: var(--heading-color);
}
.custom-buttons .btn-outline-primary:hover {
background-color: white;
color: var(--heading-color);
box-shadow: 0 0 0 0.1em var(--heading-color);
}
/* #endregion */
/* #region Back-button*/
.custom-back-button {
margin-bottom: 1em;
}
.custom-back-button a{
width: 50%;
}
.custom-back-button a .btn{
width: 50%;
background-color: var(--accent-color);
color: white;
border-color: var(--accent-color);
font-weight: 700;
}
.custom-back-button a button:hover{
background-color: white;
border-color: var(--accent-color);
color:var(--accent-color);
}
.custom-back-button a .btn i{
margin-right: 0.5em;
}
/* #endregion */
/* #region Field*/
.custom-field {
width: 50%;
margin: auto;
color: var(--heading-color);
}
.custom-field .custom-label {
font-weight: 800;
margin-bottom: 0.3em;
}
.custom-field .custom-label span{
margin-right: 0.1em;
}
.custom-field .custom-input {
border: 1px solid var(--heading-color);
color: var(--heading-color);
margin-bottom: 0.3em;
}
.custom-field .custom-input:focus {
box-shadow: 0 0 0 0.1em var(--heading-color);
}
.custom-field .custom-error-message {
font-weight: 700;
}
.custom-form-buttons {
margin-top: 2em;
}
/* #endregion */
\ No newline at end of file
<div class="cutom-child" dir="rtl">
<section class="section">
<div dir="rtl" class="mb-5 custom-form">
<!-- #region Back button-->
<div class="container text-center mb-3">
<div class="custom-back-button">
<a [routerLink]="['..']" appScrollToTop>
<button class="btn btn-outline-primary">
عودة<i class="bi bi-arrow-left"></i>
</button>
</a>
</div>
</div>
<!-- #endregion -->
<!-- #region Title-->
<div class="text-center custom-form-title mb-4">
<h3 style="font-weight: 800;">إضافة رقم هاتف</h3>
</div>
<!-- #endregion -->
<!-- #region Server-side errors -->
<div *ngIf="isFailure" class="mb-3 d-grid gap-3 custom-server-error-message">
<button type="button" class="btn btn-danger">خطأ: {{errorMessage}}</button>
</div>
<!-- #endregion -->
<!-- #region Form-->
<form #form="ngForm" (ngSubmit)="onSubmit()" class="text-center custom-form-container" autocomplete="off">
<!-- #region Name field-->
<div class="form-group mb-3 custom-field">
<label for="firstName" class="col-form-label custom-label">
الاسم
<span class="text-danger">*</span>
</label>
<input type="text" class="form-control text-center custom-input" placeholder="ادخل الاسم" dir="rtl"
[(ngModel)]="formModel.name" name="firstName" #name="ngModel" required maxlength="50">
<div *ngIf="(name.touched || name.dirty) && (name.errors)" class="custom-error-message">
<p class="text-danger">
{{
name.errors['required'] ? 'هذا الحقل مطلوب'
: ''
}}
</p>
</div>
</div>
<!-- #endregion -->
<!-- #region Phone field-->
<div class="form-group mb-3 custom-field">
<label for="phone" class="col-form-label custom-label">
رقم الهاتف
<span class="text-danger">*</span>
</label>
<input type="text" class="form-control text-center custom-input" placeholder="ادخل رقم الهاتف"
dir="ltr" [(ngModel)]="formModel.phone" name="phone" #phone="ngModel" required maxlength="50">
<div *ngIf="(phone.touched || phone.dirty) && (phone.errors)" class="custom-error-message">
<p class="text-danger">
{{
phone.errors['required'] ? 'هذا الحقل مطلوب'
: ''
}}
</p>
</div>
</div>
<!-- #endregion -->
<!-- #region Buttons-->
<div class="d-grid gap-3 mb-5 custom-buttons custom-form-buttons">
<button type="submit" class="btn btn-outline-primary"
[disabled]="form.invalid">
حفظ
<i class="bi bi-save"></i>
</button>
</div>
<!-- #endregion -->
</form>
<!-- #endregion -->
</div>
</section>
</div>
\ No newline at end of file
import { Component, OnInit, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { DoctorPhone } from '../../../classes/doctor/phones/doctor-phone';
import { DoctorsService } from '../../../services/doctors/doctors.service';
import { AuthenticationService } from '../../../services/authentication/authentication.service';
import { ToastrService } from 'ngx-toastr';
import { ViewportScroller } from '@angular/common';
import { ConstantMessages } from '../../../constants/messages';
import { Router } from '@angular/router';
@Component({
selector: 'app-create-doctor-phone',
templateUrl: './create-doctor-phone.component.html',
styleUrl: './create-doctor-phone.component.css'
})
export class CreateDoctorPhoneComponent implements OnInit{
constructor(private doctorsService: DoctorsService,
private authenticationService: AuthenticationService,
private toastrService: ToastrService,
private viewportScroller: ViewportScroller,
private router: Router
) {}
userId: number = 0;
ngOnInit(): void {
this.setUserId();
}
setUserId(): void {
this.userId = this.authenticationService.getUserData()!.id;
}
// #region server-side errors variables
isFailure: boolean = false;
errorMessage: string = '';
// #endregion
// #region Submit form
@ViewChild("form") form: NgForm;
formModel: DoctorPhone = new DoctorPhone();
onSubmit(): void {
this.isFailure = false;
this.errorMessage = '';
this.doctorsService.addPhoneByUserId(this.userId, this.formModel)
.subscribe(result => {
if (result.status === false) {
this.isFailure = true;
this.errorMessage = result.errorMessage!;
this.viewportScroller.scrollToPosition([0,0]);
}
else {
this.toastrService.success(ConstantMessages.SUCCESS_ADD);
this.router.navigateByUrl('doctor/phones');
}
})
}
// #endregion
}
/* #region custom*/
.custom-user-data {
color: var(--heading-color);
font-weight: 700;
}
.custom-user-full-name h3 {
font-weight: 800;
padding-bottom: 0.5em;
}
.custom-edit-button button:hover {
font-weight: 900;
background-color: inherit;
border-color: var(--heading-color);
color: var(--heading-color);
}
.custom-edit-button button {
font-weight: 900;
border-color: var(--heading-color);
background-color: var(--heading-color);
color: white;
}
/* #endregion */
/* #region collection item */
.collection-item {
background-color: var(--background-color);
text-align: center;
border: 1px solid var(--accent-color);
border-radius: 3%;
padding: 80px 20px;
padding-left: 20px;
padding-right: 20px;
padding-bottom: 40px;
transition: all ease-in-out 0.3s;
height: 100%;
}
.collection-item .icon {
margin: 0 auto;
width: 64px;
height: 64px;
background: var(--heading-color);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
transition: 0.3s;
transform-style: preserve-3d;
}
.collection-item .icon i {
color: var(--contrast-color);
font-size: 28px;
transition: ease-in-out 0.3s;
}
.collection-item .icon::before {
position: absolute;
content: "";
left: -8px;
top: -8px;
height: 100%;
width: 100%;
background: color-mix(in srgb, var(--accent-color), transparent 80%);
border-radius: 5px;
transition: all 0.3s ease-out 0s;
transform: translateZ(-1px);
}
.collection-item:hover {
box-shadow: 2px 2px 2px var(--accent-color)
}
/* #endregion */
\ No newline at end of file
<div class="collection-item">
<!-- #region icon -->
<div class="icon">
<i class="fas fa-phone"></i>
</div>
<!-- #endregion -->
<!-- #region Name-->
<div class="mb-3" class="custom-user-full-name">
<h3>{{phone.name}}</h3>
<h3>{{phone.phone}}</h3>
</div>
<!-- #endregion -->
<!-- #region buttons-->
<a class="d-grid gap-3 custom-edit-button" appScrollToTop>
<button class="btn btn-outline-secondary">
تعديل <i class="bi bi-pencil-fill"></i>
</button>
</a>
<!-- #endregion -->
</div>
\ No newline at end of file
import { Component, Input } from '@angular/core';
import { DoctorPhone } from '../../../classes/doctor/phones/doctor-phone';
@Component({
selector: 'app-doctor-phone',
templateUrl: './doctor-phone.component.html',
styleUrl: './doctor-phone.component.css'
})
export class DoctorPhoneComponent {
@Input("phone") phone: DoctorPhone = new DoctorPhone();
}
/* #region custom*/
.custom-create-button button:hover {
font-weight: 900;
background-color: inherit;
border-color: var(--heading-color);
color: var(--heading-color);
}
.custom-create-button button {
font-weight: 900;
background-color: var(--heading-color);
border-color: var(--heading-color);
color: white;
}
/* #endregion */
\ No newline at end of file
<div class="custom-child" dir="rtl" style="cursor: auto;">
<section class="section">
<!-- #region Title -->
<div class="container text-center mb-3 custom-title">
<h2>الهواتف المسجلة في حسابك</h2>
</div>
<!-- #endregion -->
<!-- #region buttons-->
<div class="text-center custom-create-button">
<a [routerLink]="['create']" appScrollToTop><button class="btn btn-lg btn-outline-success mb-5" style="width: 35%;">إضافة هاتف +</button></a>
</div>
<!-- #endregion -->
<!-- #region container-->
<div class="container">
<div class="row gy-5 ">
<div *ngFor="let phone of phones" class="col-lg-4 col-md-6">
<app-doctor-phone [phone]="phone"></app-doctor-phone>
</div>
</div>
</div>
<!-- #endregion -->
</section>
</div>
\ No newline at end of file
import { Component, OnInit } from '@angular/core';
import { Phone } from '../../../classes/doctor/doctor';
import { DoctorsService } from '../../../services/doctors/doctors.service';
import { AuthenticationService } from '../../../services/authentication/authentication.service';
import { ToastrService } from 'ngx-toastr';
import { ConstantMessages } from '../../../constants/messages';
@Component({
selector: 'app-doctor-phones',
templateUrl: './doctor-phones.component.html',
styleUrl: './doctor-phones.component.css'
})
export class DoctorPhonesComponent implements OnInit{
constructor(private doctorsService: DoctorsService,
private authenticationService: AuthenticationService,
private toastrService: ToastrService) {}
userId: number = 0;
ngOnInit(): void {
this.setUserId();
this.setPhones();
}
setUserId(): void {
this.userId = this.authenticationService.getUserData()!.id;
}
setPhones(): void {
this.doctorsService.getPhoneByUserId(this.userId)
.subscribe(result => {
if (result.status === false) {
this.toastrService.error(ConstantMessages.ERROR);
}
else {
this.phones = result.phones!;
}
})
}
phones: Phone[] = [new Phone("المنزل", "0943646733")];
}
......@@ -76,6 +76,7 @@
(click)="showDropdown = !showDropdown">خيارات <i
class="bi bi-chevron-down toggle-dropdown"></i></button>
<ul [ngClass]="{'show': showDropdown}">
<li (click)="showDropdown=false;"><a [routerLink]="'doctor/phones'">الهواتف</a></li>
<li (click)="showDropdown=false; openPopUp(doctorAskForSerialNumberCommand);"><a>تسجيل زيارة</a></li>
<li (click)="onLogout();"><a>تسجيل الخروج</a></li>
</ul>
......
......@@ -3,6 +3,9 @@ import { Injectable } from '@angular/core';
import * as config from '../../../../config';
import { catchError, map, Observable, of } from 'rxjs';
import { Doctor } from '../../classes/doctor/doctor';
import { AuthenticationService } from '../authentication/authentication.service';
import { DoctorPhone } from '../../classes/doctor/phones/doctor-phone';
import { HttpError } from '@microsoft/signalr';
@Injectable({
providedIn: 'root'
......@@ -64,4 +67,37 @@ export class DoctorsService {
})
);
}
getPhoneByUserId(userId: number)
: Observable<{status: boolean, errorMessage: string | null, phones: DoctorPhone[] | null}> {
return this.http.get<{phones: DoctorPhone[]}>(`${this.DOCTORS_ENDPOINT}/Phones/${userId}`)
.pipe(
map((response: {phones: DoctorPhone[]}) => {
return {status: true, errorMessage: null, phones: response.phones}
}),
catchError ((error: HttpErrorResponse) => {
console.error(error.error.detail);
return of({status: false, errorMessage: error.error.detail, phones: null});
})
)
}
addPhoneByUserId(userId: number, doctorPhone: DoctorPhone)
: Observable<{status: boolean, errorMessage: string | null}> {
var body = {
doctorUserId: userId,
name: doctorPhone.name,
phone: doctorPhone.phone
};
return this.http.post(`${this.DOCTORS_ENDPOINT}/phones`, body)
.pipe(
map(_ => {
return {status: true, errorMessage: null};
}),
catchError((error: HttpErrorResponse) => {
return of ({status: false, errorMessage: error.error.detail});
})
)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment