Commit c7831f2c authored by hasan khaddour's avatar hasan khaddour

add crud for the ain domains

parent f7030244
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
} }
], ],
"styles": [ "styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"@angular/material/prebuilt-themes/azure-blue.css", "@angular/material/prebuilt-themes/azure-blue.css",
"src/styles.css", "src/styles.css",
"src/assets/css/app-light.css", "src/assets/css/app-light.css",
...@@ -51,6 +52,8 @@ ...@@ -51,6 +52,8 @@
"./node_modules/bootstrap/dist/css/bootstrap.min.css" "./node_modules/bootstrap/dist/css/bootstrap.min.css"
], ],
"scripts": [ "scripts": [
"node_modules/@popperjs/core/dist/umd/popper.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js",
"./node_modules/jquery-sparkline/jquery.sparkline.min.js", "./node_modules/jquery-sparkline/jquery.sparkline.min.js",
"./node_modules/@popperjs/core/dist/umd/popper.min.js", "./node_modules/@popperjs/core/dist/umd/popper.min.js",
"node_modules/feather-icons/dist/feather.min.js" "node_modules/feather-icons/dist/feather.min.js"
......
This diff is collapsed.
...@@ -7,6 +7,7 @@ import { AuthGuard } from './core/guards/auth.guard'; ...@@ -7,6 +7,7 @@ import { AuthGuard } from './core/guards/auth.guard';
import { CustomerListComponent } from './customers/pages/customer-list/customer-list.component'; import { CustomerListComponent } from './customers/pages/customer-list/customer-list.component';
import { PageNotfoundComponent } from './pages/page-notfound/page-notfound.component'; import { PageNotfoundComponent } from './pages/page-notfound/page-notfound.component';
import { ProjectFAQComponent } from './pages/project-faq/project-faq.component'; import { ProjectFAQComponent } from './pages/project-faq/project-faq.component';
import { PsmStartComponent } from './pages/psm-start/psm-start.component';
export const routes: Routes = [ export const routes: Routes = [
...@@ -27,6 +28,11 @@ export const routes: Routes = [ ...@@ -27,6 +28,11 @@ export const routes: Routes = [
path: 'Project-FAQ', path: 'Project-FAQ',
component: ProjectFAQComponent, component: ProjectFAQComponent,
},
{
path: 'Help',
component: PsmStartComponent,
}, },
{ {
path: '', path: '',
...@@ -40,6 +46,7 @@ export const routes: Routes = [ ...@@ -40,6 +46,7 @@ export const routes: Routes = [
, { , {
path: 'projects', path: 'projects',
loadChildren: () => import('./projects/projects.module').then(m => m.ProjectsModule) loadChildren: () => import('./projects/projects.module').then(m => m.ProjectsModule)
} }
, { , {
path: 'employees', path: 'employees',
......
...@@ -29,6 +29,8 @@ import { LoadingInterceptor } from './core/interceptors/loading.interceptor'; ...@@ -29,6 +29,8 @@ import { LoadingInterceptor } from './core/interceptors/loading.interceptor';
import { ProjectsModule } from './projects/projects.module'; import { ProjectsModule } from './projects/projects.module';
import { ProjectRoutingModule } from './projects/project-routing.module'; import { ProjectRoutingModule } from './projects/project-routing.module';
import { ProjectFAQComponent } from './pages/project-faq/project-faq.component'; import { ProjectFAQComponent } from './pages/project-faq/project-faq.component';
import { PsmStartComponent } from './pages/psm-start/psm-start.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
@NgModule({ @NgModule({
declarations: [ declarations: [
...@@ -37,6 +39,7 @@ import { ProjectFAQComponent } from './pages/project-faq/project-faq.component'; ...@@ -37,6 +39,7 @@ import { ProjectFAQComponent } from './pages/project-faq/project-faq.component';
LoginComponent, LoginComponent,
PageNotfoundComponent, PageNotfoundComponent,
ProjectFAQComponent, ProjectFAQComponent,
PsmStartComponent,
], ],
imports: [ imports: [
...@@ -57,7 +60,8 @@ import { ProjectFAQComponent } from './pages/project-faq/project-faq.component'; ...@@ -57,7 +60,8 @@ import { ProjectFAQComponent } from './pages/project-faq/project-faq.component';
preventDuplicates: true, preventDuplicates: true,
progressBar: true, // Prevent duplicate toasts progressBar: true, // Prevent duplicate toasts
}), }),
HttpClientModule HttpClientModule,
NgbModule
], ],
providers: [ providers: [
......
export class UpdateCustomerRequest{
customerId: number
customerName : string
address : {
city : string ,
streetNumber : number ,
streetName : string
}
email :string
}
\ No newline at end of file
...@@ -21,8 +21,10 @@ ...@@ -21,8 +21,10 @@
</div> </div>
<div class="row mb-4"> <div class="row mb-4">
<button class="col-4 offset-1 m-4 btn btn-danger" (click)="onDelete(customer.id)">إزالة</button> <button class="col-3 offset-1 m-4 btn btn-danger" (click)="openModal('delete')">إزالة</button>
<button class="col-4 m-4 btn btn-info" (click)="addContact(customer.id)">إضافة معلومة اتصال</button> <button class="col-3 offset-1 m-4 btn btn-primary" (click)="openModal('edit')">تعديل</button>
<button class="col-3 m-4 btn btn-primary" (click)="addContact(customer.id)">إضافة معلومة اتصال</button>
</div> </div>
...@@ -30,4 +32,59 @@ ...@@ -30,4 +32,59 @@
</div> <!-- /.card --> </div> <!-- /.card -->
</div> <!-- /.col-12 --> </div> <!-- /.col-12 -->
</div> <!-- .row --> </div> <!-- .row -->
<div class="modal fade" id="customerModal" tabindex="-1" aria-labelledby="modalLabel" aria-hidden="true">
\ No newline at end of file <div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<h5 class="modal-title" id="modalLabel">{{ modalTitle }}</h5>
</div>
<div class="modal-body">
<!-- Edit Form -->
<div *ngIf="modalMode === 'edit'">
<form (ngSubmit)="saveCustomer()">
<div class="row">
<div class="mb-3 col-5 offset-1">
<label for="stepName" class="form-label">نوع الكلفة</label>
<input type="text" name="stepName" id="stepName" class="form-control" [(ngModel)]="selectedCustomer.customerName" required>
</div>
<div class="mb-3 col-5">
<label for="expectedSpendingDate" class="form-label">تاريخ الانفاق المتوقع</label>
<input type="date" id="expectedSpendingDate" class="form-control" [(ngModel)]="selectedCustomer.email" name="expectedSpendingDate" required>
</div>
<div class="mb-3 col-4 offset-1">
<label for="local" class="form-label">الشراء المحلي</label>
<input id="local" class="form-control" [(ngModel)]="selectedCustomer.address.city" name="local" required>
</div>
<div class="mb-3 col-4 ">
<label for="completion" class="form-label">الشراء الخارجي </label>
<input id="completion" class="form-control" [(ngModel)]="selectedCustomer.address.streetName" name="completion" required>
</div>
<div class="mb-3 col-2">
<label for="duration" class="form-label">نوغ القطع</label>
<input type="number" id="duration" class="form-control select " [(ngModel)]="selectedCustomer.address.streetNumber" name="duration" required>
</div>
</div>
<div class="row">
</div>
<button type="submit" class="btn btn-success">حفظ</button>
</form>
</div>
<!-- Delete Confirmation -->
<div *ngIf="modalMode === 'delete'">
<p>هل أنت متأكد من أنك تريد حذف عنصر {{ selectedCustomer.customerName }} ؟</p>
<button type="button" class="btn m-4 btn-danger" (click)="delete()">Delete</button>
<button type="button" class="btn m-4 btn-secondary" data-bs-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
...@@ -3,6 +3,9 @@ import { Customer } from '../../models/customer'; ...@@ -3,6 +3,9 @@ import { Customer } from '../../models/customer';
import { CustomerService } from '../../services/customer.service'; import { CustomerService } from '../../services/customer.service';
import { ActivatedRoute, Router, RouteReuseStrategy } from '@angular/router'; import { ActivatedRoute, Router, RouteReuseStrategy } from '@angular/router';
import { ToastrService } from 'ngx-toastr'; import { ToastrService } from 'ngx-toastr';
import { Modal } from 'bootstrap';
import { UpdateCustomerComponent } from '../update-customer/update-customer.component';
import { UpdateCustomerRequest } from '../../models/requests/updateCustomerRequest';
@Component({ @Component({
selector: 'customer-details', selector: 'customer-details',
...@@ -11,9 +14,11 @@ import { ToastrService } from 'ngx-toastr'; ...@@ -11,9 +14,11 @@ import { ToastrService } from 'ngx-toastr';
}) })
export class CustomerDetailsComponent implements OnInit { export class CustomerDetailsComponent implements OnInit {
modalMode: 'edit' | 'delete' = 'edit';
modalTitle: string = '';
customer: Customer | undefined; customer: Customer ;
selectedCustomer :Customer ;
constructor( constructor(
private router : Router, private router : Router,
private route: ActivatedRoute, private route: ActivatedRoute,
...@@ -23,11 +28,13 @@ export class CustomerDetailsComponent implements OnInit { ...@@ -23,11 +28,13 @@ export class CustomerDetailsComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
const id = Number(this.route.snapshot.paramMap.get('id')); const id = Number(this.route.snapshot.paramMap.get('id'));
this.customerService.getCustomerById(id).subscribe({ this.customerService.getCustomerById(id).subscribe({
next :(data) => { next :(data) => {
this.customer = data; this.customer = data;
this.selectedCustomer=this.customer;
}, },
error : (err)=>{ console.log(err)} error : (err)=>{ console.log(err)}
...@@ -37,14 +44,78 @@ export class CustomerDetailsComponent implements OnInit { ...@@ -37,14 +44,78 @@ export class CustomerDetailsComponent implements OnInit {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
onDelete(id: number) {
this.customerService.deleteCustomer(id).subscribe({ openModal(mode: 'edit' | 'delete'): void {
next : (data)=> { this.modalMode = mode;
this.toastr.success('تم حذف الجهة بنجاح');
this.router.navigate(['/customers']); if (mode === 'edit') {
}, this.modalTitle = 'تعديل جهة طارحة ';
error: (err)=>this.toastr.error('لقد حدث خطاء ما') } else if (mode === 'delete') {
}); this.modalTitle = 'حذف جهة طارحة';
}
const modalElement = document.getElementById('customerModal');
if (modalElement) {
new Modal(modalElement).show(); // Open the modal
}
} }
saveCustomer(): void {
let request : UpdateCustomerRequest ={
...this.selectedCustomer,
customerId: this.selectedCustomer.id
}
this.customerService.updateCustomer(this.selectedCustomer.id,request).subscribe({
next :()=>{
this.customer.address=this.selectedCustomer.address ;
this.customer.customerName=this.selectedCustomer.customerName;
this.customer.email=this.selectedCustomer.email
this.closeModal();
}
,
error:(err)=>{
this.toastr.error("لقد حدث خطاء ما ")
this.closeModal();
}
})
}
delete(): void {
this.customerService.deleteCustomer(this.customer.id).subscribe({
next :()=>{
this.router.navigate(['/customers'])
this.closeModal();
}
,
error:(err)=>{
this.toastr.error("لقد حدث خطاء ما ")
this.closeModal();
}
}
);
}
closeModal(): void {
const modalElement = document.getElementById('customerModal');
if (modalElement) {
new Modal(modalElement).hide(); // Close the modal
}
}
} }
\ No newline at end of file
...@@ -16,15 +16,15 @@ export class UpdateCustomerComponent { ...@@ -16,15 +16,15 @@ export class UpdateCustomerComponent {
} }
onSubmit(customer: Customer) { onSubmit(customer: Customer) {
this.customerService // this.customerService
.updateCustomer(customer.id,customer) // .updateCustomer(customer.id,customer)
.subscribe({ // .subscribe({
next: (res)=>{ // next: (res)=>{
console.log(res) // console.log(res)
}, // },
error: (error)=> console.log(error) // error: (error)=> console.log(error)
} // }
); // );
} }
......
...@@ -5,6 +5,7 @@ import { ConfigurationService } from '../../core/services/configuration/configur ...@@ -5,6 +5,7 @@ import { ConfigurationService } from '../../core/services/configuration/configur
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Result } from '../../core/models/result'; import { Result } from '../../core/models/result';
import { CreateCustomerRequest } from '../models/createCustomerRequest'; import { CreateCustomerRequest } from '../models/createCustomerRequest';
import { UpdateCustomerRequest } from '../models/requests/updateCustomerRequest';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
...@@ -28,9 +29,9 @@ export class CustomerService { ...@@ -28,9 +29,9 @@ export class CustomerService {
return this.http.post<Customer>(this.config.getServerUrl()+ "/Customers",customer); return this.http.post<Customer>(this.config.getServerUrl()+ "/Customers",customer);
} }
public updateCustomer(id :number ,customer :Customer):Observable<void>{ public updateCustomer(id :number ,request :UpdateCustomerRequest):Observable<void>{
return this.http.put<void>(`${this.config.getServerUrl()}/Customers/${id}` ,customer); return this.http.put<void>(`${this.config.getServerUrl()}/Customers/${id}` ,request);
} }
public deleteCustomer(customerId: number): Observable<void> { public deleteCustomer(customerId: number): Observable<void> {
......
.hero .btn-get-started {
color: var(--contrast-color);
background: var(--accent-color);
font-family: var(--heading-font);
font-weight: 400;
font-size: 15px;
letter-spacing: 1px;
display: inline-block;
padding: 10px 28px;
border-radius: 50px;
transition: 0.5s;
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.1);
}
.hero .btn-get-started:hover {
color: var(--contrast-color);
background: color-mix(in srgb, var(--accent-color), transparent 15%);
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.1);
}
.hero .btn-watch-video {
font-size: 16px;
transition: 0.5s;
margin-left: 25px;
color: var(--default-color);
font-weight: 500;
}
.hero .btn-watch-video i {
color: var(--accent-color);
font-size: 32px;
transition: 0.3s;
line-height: 0;
margin-right: 8px;
}
.hero .btn-watch-video:hover {
color: var(--accent-color);
}
.hero .btn-watch-video:hover i {
color: color-mix(in srgb, var(--accent-color), transparent 15%);
}
.hero .animated {
margin-bottom: 60px;
animation: up-down 2s ease-in-out infinite alternate-reverse both;
}
@media (min-width: 992px) {
.hero .animated {
max-width: 45%;
}
}
@media (max-width: 991px) {
.hero .animated {
max-width: 60%;
}
}
@media (max-width: 575px) {
.hero .animated {
max-width: 80%;
}
}
@media (max-width: 640px) {
.hero h1 {
font-size: 28px;
line-height: 36px;
}
.hero p {
font-size: 18px;
line-height: 24px;
margin-bottom: 30px;
}
.hero .btn-get-started,
.hero .btn-watch-video {
font-size: 13px;
}
}
@keyframes up-down {
0% {
transform: translateY(10px);
}
100% {
transform: translateY(-10px);
}
}
\ No newline at end of file
<div class="container d-flex flex-column justify-content-center align-items-center text-center position-relative aos-init aos-animate" data-aos="zoom-out">
<img height="400px" src="assets/images/home/hero-img.png" class=" animated" alt="">
<h3>مرحبا بك <span>في موقعنا</span></h3>
<p class="text-important text-italic">هل تحتاج إلى مساعدة ؟ </p>
<div class="d-flex">
<a href="#about" class="btn-get-started mr-4 scrollto">انطلق الآن</a>
<a class="glightbox mr-4 btn-watch-video d-flex align-items-center"><i class="bi bi-play-circle"></i><span>طريقة الاستخدام</span></a>
</div>
</div>
\ No newline at end of file
import { Component } from '@angular/core';
@Component({
selector: 'psm-start',
templateUrl: './psm-start.component.html',
styleUrl: './psm-start.component.css'
})
export class PsmStartComponent {
}
<div class="card shadow mb-4 col-8 offset-2">
<div class="card-header py-3">
<div class="row align-items-center">
<div class="col-auto">
<a href="profile-posts.html" class="avatar avatar-md">
<img src="./assets/images/users/4.jpg" alt="..." class="avatar-img rounded-circle">
</a>
</div>
<div class="col ml-n2">
<strong class="mb-1">{{item.costType}}</strong><span class=" ml-1"></span>
<p class="small text-muted mb-1">{{item.description}}</p>
</div>
<div class="col-auto">
</div>
</div>
</div>
<div class="card-body ">
<div class="row align-items-center">
<div class="col-8 ">
<div class="small mb-2 d-flex">
<span class="text-muted flex-fill">الشراء المحلي {{item.localPurchase}}</span>
<span class="text-muted">تاريخ الصرف المتوقع {{item.expectedSpendingDate | date}}</span>
</div>
</div>
<div class="col-8 ">
<div class="small mb-2 d-flex">
<span class="text-muted flex-fill">الشراء الخارجي {{item.externalPurchase.ammount}} {{item.externalPurchase.currency}}</span>
</div>
<div class="col-auto">
<button type="button" (click)="onEdit()" class="btn m-2 btn-sm btn-secondary">تعديل المعلومات</button>
<button type="button" (click)="onDelete()"class="btn m-2 btn-sm btn-danger">إزالة</button>
</div>
</div>
</div>
</div> <!-- / .card-body -->
</div>
\ No newline at end of file
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { FinancialSpending } from '../../models/responses/FinancialSpending';
@Component({
selector: 'financial-item',
templateUrl: './financial-item.component.html',
styleUrl: './financial-item.component.css'
})
export class FinancialItemComponent {
@Input() item :FinancialSpending
@Output() edit = new EventEmitter<void>();
@Output() delete = new EventEmitter<void>();
onEdit() {
this.edit.emit();
}
onDelete() {
this.delete.emit();
}
}
<p>add-financial-spend-modal works!</p> <div class="modal-header">
<button type="button" class="btn-close" (click)="onClose()" ></button>
<h5 class="modal-title text-center">إضافة عنصر جديد </h5>
</div>
<div class="modal-body">
<form (ngSubmit)="onSubmit()" #projectForm="ngForm">
<div class="row">
<div class="mb-3 col-3 offset-1">
<label for="stepName" class="form-label">نوع الكلفة</label>
<input type="text" name="stepName" id="stepName" class="form-control" [(ngModel)]="request.costType" required>
</div>
<div class="mb-3 col-3">
<label for="start" class="form-label">تاريخ الانفاق المتوقع</label>
<input type="date" id="start" class="form-control" [(ngModel)]="request.expectedSpendingDate" name="start" required>
</div>
<div class="mb-3 col-3">
<label for="worker" class="form-label">الكلفة بالليرة السورية</label>
<input id="worker" class="form-control" [(ngModel)]="request.localPurchase" name="worker" required>
</div>
</div>
<div class="row">
<div class="mb-3 col-8 offset-1" >
<label for="decription" class="form-label">البيان</label>
<textarea col="3" name="worker" id="decription" class="form-control" [(ngModel)]="request.description" required>
</textarea>
</div>
</div>
<div class="row">
<div class="mb-3 col-3 offset-1">
<label for="completion" class="form-label">الشراء الخارجي </label>
<input id="completion" class="form-control" [(ngModel)]="request.externalPurchase.ammount" name="completion" required>
</div>
<div class="mb-3 col-3">
<label for="duration" class="form-label">نوغ القطع</label>
<select id="duration" class="form-control select " [(ngModel)]="request.externalPurchase.currency" name="duration" required>
<option value="USA">USA</option>
<option value="EUR">EUR</option>
</select>
</div>
</div>
<div class="row ">
<button type="submit" class=" col-3 btn btn-primary">إضافة</button>
<button class="btn btn-seondary col-3" (click)="onClose()" >إغلاق</button>
</div>
</form>
</div>
\ No newline at end of file
import { Component } from '@angular/core'; import { Component, Input } from '@angular/core';
import { FinancialSpending } from '../../../models/responses/FinancialSpending';
import { CreateFinancialSpendItemRequest } from '../../../models/requests/financial-reuqests/CreateFinancialSpendItemRequest';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { ToastrService } from 'ngx-toastr';
import { ProjectService } from '../../../services/project.service';
import { FinancialSpendingService } from '../../../services/financial-spending.service';
@Component({ @Component({
selector: 'add-financial-spend-modal', selector: 'add-financial-spend-modal',
...@@ -6,5 +12,42 @@ import { Component } from '@angular/core'; ...@@ -6,5 +12,42 @@ import { Component } from '@angular/core';
styleUrl: './add-financial-spend-modal.component.css' styleUrl: './add-financial-spend-modal.component.css'
}) })
export class AddFinancialSpendModalComponent { export class AddFinancialSpendModalComponent {
item = new FinancialSpending()
@Input() projectId : number
request :CreateFinancialSpendItemRequest
constructor(private toastr :ToastrService, public activeModal: NgbActiveModal,private financialService :FinancialSpendingService) {}
ngOnInit(): void {
this.request ={
projectId: this.projectId ,
localPurchase: 0,
expectedSpendingDate :new Date(),
externalPurchase :{
ammount :0 ,
currency :""
},
costType:"" ,
description:""
};
}
onSubmit(): void {
// Emit the project data or handle it as needed
console.log('Project data submitted:', this.request);
this.financialService.addSpendItem(this.request).subscribe({
next: (data)=>{
this.activeModal.close(data); // Close modal and pass data
},
error: (err )=> this.toastr.error("لقد حدث خطاء ما")
})
}
onClose():void {
this.activeModal.close();
}
} }
.popup-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.popup-content {
background: white;
padding: 20px;
border-radius: 8px;
width: 300px;
}
.popup-actions {
margin-top: 20px;
display: flex;
justify-content: space-between;
}
\ No newline at end of file
<h1 mat-dialog-title>Add Step</h1> <div class="modal-header">
<div mat-dialog-content> <button type="button" class="btn-close" (click)="onClose()" ></button>
<form [formGroup]="stepForm"> <h5 class="modal-title text-center">إضافة مرحلة جديدة</h5>
<mat-form-field> </div>
<mat-label>Name</mat-label> <div class="modal-body">
<input matInput formControlName="name"> <form (ngSubmit)="onSubmit()" #projectForm="ngForm">
<mat-error *ngIf="stepForm.get('name')!.hasError('required')">Name is required</mat-error> <div class="row">
</mat-form-field>
<mat-form-field> <div class="mb-3 col-3 offset-1">
<mat-label>Description</mat-label> <label for="stepName" class="form-label">اسم المرحلة</label>
<textarea matInput formControlName="description"></textarea> <input type="text" name="stepName" id="stepName" class="form-control" [(ngModel)]="request.stepInfo.stepName" required>
<mat-error *ngIf="stepForm.get('description')!.hasError('required')">Description is required</mat-error> </div>
</mat-form-field>
<div class="mb-3 col-3">
<label for="start" class="form-label">تاريخ البدء</label>
<input type="date" id="start" class="form-control" [(ngModel)]="request.stepInfo.startDate" name="start" required>
</div>
<mat-form-field> <div class="mb-3 col-3">
<mat-label>Weight</mat-label> <label for="worker" class="form-label">عدد العمال المطلوب</label>
<input matInput type="number" formControlName="weight"> <input id="worker" class="form-control" [(ngModel)]="request.stepInfo.NumberOfWorker" name="worker" required>
<mat-error *ngIf="stepForm.get('weight')!.hasError('required')">Weight is required</mat-error> </div>
<mat-error *ngIf="stepForm.get('weight')!.hasError('min') || stepForm.get('weight')!.hasError('max')">
Weight must be between 1 and 100 </div>
</mat-error> <div class="row">
</mat-form-field> <div class="mb-3 col-8 offset-1" >
</form> <label for="decription" class="form-label">الوصف</label>
</div> <textarea col="3" name="worker" id="decription" class="form-control" [(ngModel)]="request.stepInfo.description" required>
<div mat-dialog-actions> </textarea>
<button mat-button (click)="onCancel()">Cancel</button> </div>
<button mat-button color="primary" (click)="onSubmit()" [disabled]="stepForm.invalid">Add Step</button> </div>
<div class="row">
<div class="mb-3 col-3 offset-1">
<label for="completion" class="form-label">نسبة الانجاز</label>
<input id="completion" class="form-control" [(ngModel)]="request.currentCompletionRatio" name="completion" required>
</div>
<div class="mb-3 col-3">
<label for="duration" class="form-label">المدة</label>
<input id="duration" class="form-control" [(ngModel)]="request.stepInfo.duration" name="duration" required>
</div>
<div class="mb-3 col-3">
<label for="weight" class="form-label">الثقل</label>
<input id="weight" name="weight" class="form-control" [(ngModel)]="request.weight" required>
</div>
</div>
<div class="row ">
<button type="submit" class="btn btn-primary">إضافة</button>
<button class="btn btn-seondary" (click)="onClose()" >إغلاق</button>
</div>
</form>
</div> </div>
import { Component, Inject } from '@angular/core'; import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { Step } from '../../../models/responses/Step';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { StepService } from '../../../services/step.service';
import { AddProjectStepRequest } from '../../../models/requests/project-requests/AddProjectStepRequest';
import { ProjectService } from '../../../services/project.service';
import { ToastrService } from 'ngx-toastr';
@Component({ @Component({
selector: 'add-step-modal', selector: 'add-step-modal',
templateUrl: './add-step-modal.component.html', templateUrl: './add-step-modal.component.html',
styleUrl: './add-step-modal.component.css' styleUrl: './add-step-modal.component.css'
}) })
export class AddStepModalComponent { export class AddStepModalComponent implements OnInit {
stepForm: FormGroup; step :Step = new Step()
@Input() projectId : number
request :AddProjectStepRequest
constructor(private toastr :ToastrService, public activeModal: NgbActiveModal,private projectService :ProjectService) {}
constructor( ngOnInit(): void {
private fb: FormBuilder, this.request ={
public dialogRef: MatDialogRef<AddStepModalComponent>, stepInfo: {
@Inject(MAT_DIALOG_DATA) public data: any startDate:new Date (),
) { description :'',
this.stepForm = this.fb.group({ NumberOfWorker :0,
name: ['', Validators.required], stepName:'',
description: ['', Validators.required], duration:0
weight: [0, [Validators.required, Validators.min(1), Validators.max(100)]] },
}); currentCompletionRatio:0,
weight:0,
projectId: this.projectId
};
} }
onSubmit(): void {
// Emit the project data or handle it as needed
console.log('Project data submitted:', this.request);
this.projectService.addStepToProject(this.request).subscribe({
next: (data)=>{
this.step= {
id : data ,
stepInfo: this.request.stepInfo ,
weight: this.request.weight ,
currentCompletionRatio: this.request.currentCompletionRatio,
projectId: this.projectId
}
this.activeModal.close(this.step); // Close modal and pass data
},
error: (err )=> this.toastr.error("لقد حدث خطاء ما")
onSubmit() { })
if (this.stepForm.valid) {
this.dialogRef.close(this.stepForm.value);
}
} }
onCancel(): void { onClose():void {
this.dialogRef.close(); this.activeModal.close();
} }
} }
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<strong class="card-title my-0">{{project.projectInfo.name}} </strong> <strong class="card-title my-0">{{project.projectInfo.name}} </strong>
<p class="small">{{project.projectInfo.description}}</p> <p class="small">{{project.projectInfo.description}}</p>
<p class="small">ينفذ من قبل {{project.executer.name}}</p> <p class="small">ينفذ من قبل {{project.executer.name}}</p>
<p class="small">الطور {{project.currentState }}</p> <p class="small">الطور {{project.currentState }}</p>
<p class="small text-muted mb-0"> <span class="badge badge-light text-muted"> رمز المشروع {{project.projectInfo.code}} </span>, <span class="badge badge-light text-muted"> تاريخ البدء {{project.projectInfo.startDate | date}} </span></p> <p class="small text-muted mb-0"> <span class="badge badge-light text-muted"> رمز المشروع {{project.projectInfo.code}} </span>, <span class="badge badge-light text-muted"> تاريخ البدء {{project.projectInfo.startDate | date}} </span></p>
......
export class CreateFinancialSpendItemRequest {
projectId: number;
externalPurchase: {
ammount: number;
currency: string;
};
localPurchase: number;
costType: string;
description: string;
expectedSpendingDate: Date;
}
export class GetFinancialSpendItemByIdRequest {
projectId: number;
id: number;
}
export class GetFinancialSpendItemByProjecRequest{
projectId :number
pageNumber :number |null
pageSize : number | null
}
export class RemoveFinancialSpendItemRequest {
projectId: number;
id: number;
}
export class UpdateFinancialSpendItemRequest {
projectId: number;
id: number;
externalPurchase: {
ammount: number;
currency: string;
};
localPurchase: number;
costType: string;
description: string;
expectedSpendingDate: Date;
}
export class FinancialSpending { export class FinancialSpending {
id: number; id: number;
expectedSpendingDate: number; expectedSpendingDate: Date;
costType: number; costType: string;
description: string; description: string;
localPurchase: number; localPurchase: number;
externalPurchase: { externalPurchase: {
......
...@@ -4,5 +4,6 @@ export interface StepInfo { ...@@ -4,5 +4,6 @@ export interface StepInfo {
description: string; description: string;
startDate: Date; startDate: Date;
duration: number; duration: number;
NumberOfWorker : number
} }
<section *ngIf="spends" class="row">
<div class="row justify-content-center">
<div class="col-12">
<div class="row align-items-center my-4">
<div class="col">
<h2 class="h3 mb-0 page-title"> قائمة خطة الانفاق </h2>
</div>
<div class="col-auto">
<button type="button" (click)="openAddModal()" class="btn btn-primary"><span class="fe fe-file-plus fe-12 mr-2"></span>إضافة عنصر </button>
</div>
</div>
<hr>
<financial-item class=" offset-2"
*ngFor="let item of spends"
[item]="item"
(edit)="openModal('edit', item)"
(delete)="openModal('delete', item)"
>
</financial-item>
<div *ngIf="spends.length==0">
للأسف هذا المشروع لايحوي على خطة انفاق
</div>
</div>
</div>
</section>
<div class="modal fade" id="projectModal" tabindex="-1" aria-labelledby="modalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<h5 class="modal-title" id="modalLabel">{{ modalTitle }}</h5>
</div>
<div class="modal-body">
<!-- Edit Form -->
<div *ngIf="modalMode === 'edit'">
<form (ngSubmit)="saveProject()">
<div class="row">
<div class="mb-3 col-5 offset-1">
<label for="stepName" class="form-label">نوع الكلفة</label>
<input type="text" name="stepName" id="stepName" class="form-control" [(ngModel)]="selectedItem.costType" required>
</div>
<div class="mb-3 col-5">
<label for="expectedSpendingDate" class="form-label">تاريخ الانفاق المتوقع</label>
<input type="date" id="expectedSpendingDate" class="form-control" [(ngModel)]="selectedItem.expectedSpendingDate" name="expectedSpendingDate" required>
</div>
<div class="mb-3 col-4 offset-1">
<label for="local" class="form-label">الشراء المحلي</label>
<input id="local" class="form-control" [(ngModel)]="selectedItem.localPurchase" name="local" required>
</div>
<div class="mb-3 col-4 ">
<label for="completion" class="form-label">الشراء الخارجي </label>
<input id="completion" class="form-control" [(ngModel)]="selectedItem.externalPurchase.ammount" name="completion" required>
</div>
<div class="mb-3 col-2">
<label for="duration" class="form-label">نوغ القطع</label>
<select id="duration" class="form-control select " [(ngModel)]="selectedItem.externalPurchase.currency" name="duration" required>
<option value="USA">USA</option>
<option value="EUR">EUR</option>
</select>
</div>
</div>
<div class="row">
<div class="mb-3 col-10 offset-1 " >
<label for="decription" class="form-label">البيان</label>
<textarea col="3" name="worker" id="decription" class="form-control" [(ngModel)]="selectedItem.description" required>
</textarea>
</div>
</div>
<div class="row">
</div>
<button type="submit" class="btn btn-success">حفظ</button>
</form>
</div>
<!-- Delete Confirmation -->
<div *ngIf="modalMode === 'delete'">
<p>هل أنت متأكد من أنك تريد حذف عنصر {{ selectedItem.costType }}?</p>
<button type="button" class="btn m-4 btn-danger" (click)="deleteProject()">Delete</button>
<button type="button" class="btn m-4 btn-secondary" data-bs-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
import { Component } from '@angular/core';
import { FinancialSpending } from '../../models/responses/FinancialSpending';
import { FinancialSpendingService } from '../../services/financial-spending.service';
import { ActivatedRoute, Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ToastrService } from 'ngx-toastr';
import { AddStepModalComponent } from '../../components/modals/add-step-modal/add-step-modal.component';
import { GetFinancialSpendItemByIdRequest } from '../../models/requests/financial-reuqests/GetFinancialSpendItemByIdRequest';
import { GetFinancialSpendItemByProjecRequest } from '../../models/requests/financial-reuqests/GetFinancialSpendItemByProjectRequest';
import { AddFinancialSpendModalComponent } from '../../components/modals/add-financial-spend-modal/add-financial-spend-modal.component';
import { UpdateFinancialSpendItemRequest } from '../../models/requests/financial-reuqests/UpdateFinancialSpendItemRequest';
import { RemoveFinancialSpendItemRequest } from '../../models/requests/financial-reuqests/RemoveFinancialSpendItemRequest';
import { Modal } from 'bootstrap';
@Component({
selector: 'financial-spending',
templateUrl: './financial-spending.component.html',
styleUrl: './financial-spending.component.css'
})
export class FinancialSpendingComponent {
spends :FinancialSpending[]
selectedItem : FinancialSpending;
projectId = Number(this.route.snapshot.paramMap.get('id'));
modalMode: 'edit' | 'delete' = 'edit';
modalTitle: string = '';
constructor(
private financialService :FinancialSpendingService,
private toastr : ToastrService,
private route: ActivatedRoute,
public router :Router,
private modalService: NgbModal
) {
}
ngOnInit(): void {
this.loadSpends();
this.selectedItem ={
id:-1 ,
costType:'',
expectedSpendingDate: new Date (),
localPurchase:0,
externalPurchase: {
currency:"",
ammount:0
},
description:""
}
}
loadSpends(): void{
let request : GetFinancialSpendItemByProjecRequest ={
projectId : this.projectId ,
pageNumber: null ,
pageSize: null
}
this.financialService.getSpendByProject(request).subscribe({
next: (data)=> {
this.spends= data
this.toastr.success("تم تحميل خطة الانفاق بنجاح");
}
,
error:(err)=>{
console.log(err)
this.toastr.error("لقد حدث خطاء ما")
}
})
}
openModal(mode: 'edit' | 'delete', item: FinancialSpending): void {
this.modalMode = mode;
this.selectedItem = { ...item }; // Clone project to prevent direct mutation
console.log(this.selectedItem)
if (mode === 'edit') {
this.modalTitle = 'تعديل عنصر ';
} else if (mode === 'delete') {
this.modalTitle = 'حذف عنصر';
}
const modalElement = document.getElementById('projectModal');
if (modalElement) {
new Modal(modalElement).show(); // Open the modal
}
}
saveProject(): void {
let request : UpdateFinancialSpendItemRequest ={
...this.selectedItem,
projectId: this.projectId
}
this.financialService.updateSpendItem(request).subscribe({
next :()=>{
const index = this.spends.findIndex(p => p.id === this.selectedItem.id);
if (index !== -1) {
this.spends[index] = this.selectedItem;
}
this.closeModal();
}
,
error:(err)=>{
this.toastr.error("لقد حدث خطاء ما ")
this.closeModal();
}
})
}
deleteProject(): void {
let request : RemoveFinancialSpendItemRequest= {
projectId: this.projectId ,
id: this.selectedItem.id
}
this.financialService.delete(request).subscribe({
next :()=>{
this.spends = this.spends.filter(p => p.id !== this.selectedItem.id);
this.toastr.success("تم الحذف بنجاح")
this.closeModal();
}
,
error:(err)=>{
this.toastr.error("لقد حدث خطاء ما ")
this.closeModal();
}
}
);
}
closeModal(): void {
const modalElement = document.getElementById('projectModal');
if (modalElement) {
new Modal(modalElement).hide(); // Close the modal
}
}
openAddModal(): void {
const modalRef = this.modalService.open(AddFinancialSpendModalComponent, { size: 'lg' });
modalRef.componentInstance.projectId = this.projectId;
modalRef.result.then((result) => {
if (result) {
// Add the new project to the list
this.spends.push(result);
console.log('Project added:', result);
}
}, (reason) => {
// Handle modal dismiss
console.log('Modal dismissed with reason:', reason);
});
}
}
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-6 col-lg-4"> <div class="col-md-6 col-lg-4" [routerLink]="['/projects/spending/',project.id]">
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<div class="card-body file-list"> <div class="card-body file-list">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
......
...@@ -6,10 +6,12 @@ ...@@ -6,10 +6,12 @@
<h2 class="h3 mb-0 page-title"> قائمة مراحل المشروع </h2> <h2 class="h3 mb-0 page-title"> قائمة مراحل المشروع </h2>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<button type="button" mat-raised-button color="primary" (click)="addStep()"class="btn btn-primary"><span class="fe fe-file-plus fe-12 mr-2"></span>إضافة مرحلة </button> <button type="button" (click)="openAddModal()" class="btn btn-primary"><span class="fe fe-file-plus fe-12 mr-2"></span>إضافة مرحلة </button>
</div> </div>
</div> </div>
<hr> <hr>
<step-row-item class=" offset-2" *ngFor="let step of steps" [step]="step"></step-row-item> <step-row-item class=" offset-2" *ngFor="let step of steps" [step]="step"></step-row-item>
<div *ngIf="steps.length==0"> <div *ngIf="steps.length==0">
......
import { Component } from '@angular/core'; import { Component, NgModuleRef } from '@angular/core';
import { Step } from '../../models/responses/Step'; import { Step } from '../../models/responses/Step';
import { ProjectService } from '../../services/project.service'; import { ProjectService } from '../../services/project.service';
import { ToastrService } from 'ngx-toastr'; import { ToastrService } from 'ngx-toastr';
import { ActivatedRoute, Route, Router } from '@angular/router'; import { ActivatedRoute, Route, Router } from '@angular/router';
import { StepService } from '../../services/step.service'; import { StepService } from '../../services/step.service';
import { ModalService } from '../../../core/services/modals/modal.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { AddStepModalComponent } from '../../components/modals/add-step-modal/add-step-modal.component'; import { AddStepModalComponent } from '../../components/modals/add-step-modal/add-step-modal.component';
@Component({ @Component({
selector: 'step-list', selector: 'step-list',
templateUrl: './step-list.component.html', templateUrl: './step-list.component.html',
...@@ -14,13 +13,15 @@ import { AddStepModalComponent } from '../../components/modals/add-step-modal/ad ...@@ -14,13 +13,15 @@ import { AddStepModalComponent } from '../../components/modals/add-step-modal/ad
}) })
export class StepListComponent { export class StepListComponent {
steps : Step[] steps : Step[]
projectId = Number(this.route.snapshot.paramMap.get('id')); projectId = Number(this.route.snapshot.paramMap.get('id'));
constructor( constructor(
private stepService :StepService, private stepService :StepService,
private toastr : ToastrService, private toastr : ToastrService,
private route: ActivatedRoute, private route: ActivatedRoute,
public router :Router, public router :Router,
private modalService: ModalService private modalService: NgbModal
) { ) {
} }
...@@ -46,12 +47,19 @@ export class StepListComponent { ...@@ -46,12 +47,19 @@ export class StepListComponent {
}) })
} }
addStep() { openAddModal(): void {
this.modalService.openModal({},AddStepModalComponent).then(result => { const modalRef = this.modalService.open(AddStepModalComponent, { size: 'lg' });
modalRef.componentInstance.projectId = this.projectId;
modalRef.result.then((result) => {
if (result) { if (result) {
// Logic to handle the step after it's been added, such as updating the project steps // Add the new project to the list
console.log('New Step:', result); this.steps.push(result);
console.log('Project added:', result);
} }
}, (reason) => {
// Handle modal dismiss
console.log('Modal dismissed with reason:', reason);
}); });
} }
} }
...@@ -5,6 +5,7 @@ import { ProjectDetailsComponent } from './pages/project-details/project-details ...@@ -5,6 +5,7 @@ import { ProjectDetailsComponent } from './pages/project-details/project-details
import { ProjectCreateComponent } from './pages/project-create/project-create.component'; import { ProjectCreateComponent } from './pages/project-create/project-create.component';
import { StepListComponent } from './pages/step-list/step-list.component'; import { StepListComponent } from './pages/step-list/step-list.component';
import { ParticipantsListComponent } from './pages/participants-list/participants-list.component'; import { ParticipantsListComponent } from './pages/participants-list/participants-list.component';
import { FinancialSpendingComponent } from './pages/financial-spending/financial-spending.component';
const routes: Routes = [ const routes: Routes = [
...@@ -12,7 +13,8 @@ const routes: Routes = [ ...@@ -12,7 +13,8 @@ const routes: Routes = [
{ path: 'detail/:id', component: ProjectDetailsComponent }, { path: 'detail/:id', component: ProjectDetailsComponent },
{ path: 'create', component: ProjectCreateComponent }, { path: 'create', component: ProjectCreateComponent },
{ path: 'steps/:id', component: StepListComponent }, { path: 'steps/:id', component: StepListComponent },
{ path: 'participants/:id', component: ParticipantsListComponent } { path: 'participants/:id', component: ParticipantsListComponent },
{ path: 'spending/:id', component: FinancialSpendingComponent }
......
...@@ -28,6 +28,8 @@ import { RouterModule } from '@angular/router'; ...@@ -28,6 +28,8 @@ import { RouterModule } from '@angular/router';
import { AddStepModalComponent } from './components/modals/add-step-modal/add-step-modal.component'; import { AddStepModalComponent } from './components/modals/add-step-modal/add-step-modal.component';
import { AddFinancialSpendModalComponent } from './components/modals/add-financial-spend-modal/add-financial-spend-modal.component'; import { AddFinancialSpendModalComponent } from './components/modals/add-financial-spend-modal/add-financial-spend-modal.component';
import { AddAttachmentModalComponent } from './components/modals/add-attachment-modal/add-attachment-modal.component'; import { AddAttachmentModalComponent } from './components/modals/add-attachment-modal/add-attachment-modal.component';
import { FinancialSpendingComponent } from './pages/financial-spending/financial-spending.component';
import { FinancialItemComponent } from './components/financial-item/financial-item.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
...@@ -46,7 +48,9 @@ import { AddAttachmentModalComponent } from './components/modals/add-attachment- ...@@ -46,7 +48,9 @@ import { AddAttachmentModalComponent } from './components/modals/add-attachment-
InfoControllComponent, InfoControllComponent,
AddStepModalComponent, AddStepModalComponent,
AddFinancialSpendModalComponent, AddFinancialSpendModalComponent,
AddAttachmentModalComponent AddAttachmentModalComponent,
FinancialSpendingComponent,
FinancialItemComponent
], ],
providers: [ providers: [
ProjectService, ProjectService,
......
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ConfigurationService } from '../../core/services/configuration/configuration.service';
import { FinancialSpending } from '../models/responses/FinancialSpending';
import { Observable } from 'rxjs';
import { CreateFinancialSpendItemRequest } from '../models/requests/financial-reuqests/CreateFinancialSpendItemRequest';
import { GetFinancialSpendItemByProjecRequest } from '../models/requests/financial-reuqests/GetFinancialSpendItemByProjectRequest';
import { RemoveFinancialSpendItemRequest } from '../models/requests/financial-reuqests/RemoveFinancialSpendItemRequest';
import { UpdateFinancialSpendItemRequest } from '../models/requests/financial-reuqests/UpdateFinancialSpendItemRequest';
import { GetFinancialSpendItemByIdRequest } from '../models/requests/financial-reuqests/GetFinancialSpendItemByIdRequest';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class FinancialSpendingService { export class FinancialSpendingService {
constructor() { } constructor(private http : HttpClient , private config : ConfigurationService) { }
public getSpendById(request : GetFinancialSpendItemByIdRequest ):Observable<FinancialSpending>{
return this.http.get<FinancialSpending>(`${this.config.getServerUrl()}/FinancialSpends/?id=${request.id}&projectId=${request.projectId}`);
}
public addSpendItem(request : CreateFinancialSpendItemRequest ):Observable<FinancialSpending>{
return this.http.post<FinancialSpending>(this.config.getServerUrl()+ "/FinancialSpends/",request);
}
public getSpendByProject(request : GetFinancialSpendItemByProjecRequest ):Observable<FinancialSpending[]>{
let pagination = this.getPagination(request.pageSize,request.pageNumber)
return this.http.get<FinancialSpending[]>(`${this.config.getServerUrl()}/FinancialSpends/ByProject/?projectId=${request.projectId}${pagination}`);
}
public delete(request : RemoveFinancialSpendItemRequest ):Observable<any>{
return this.http.delete(`${this.config.getServerUrl()}/FinancialSpends/ByProject/${request.id}?id=${request.id}&projectId=${request.projectId}`);
}
public updateSpendItem(request : UpdateFinancialSpendItemRequest ):Observable<FinancialSpending>{
return this.http.put<FinancialSpending>(this.config.getServerUrl()+ "/FinancialSpends/",request);
}
//#region pagination convert
private getPagination( pageSize:number | null , pageNumber : number |null ){
if(pageNumber == null || pageSize == null){
return "";
}
else {
return `&pageSize=${pageSize}&PageNumber=${pageNumber}`;
}
}
//#endregion pagination convert
} }
...@@ -95,7 +95,7 @@ export class ProjectService { ...@@ -95,7 +95,7 @@ export class ProjectService {
// //
public addStepToProject(request : AddProjectStepRequest ):Observable<number>{ public addStepToProject(request : AddProjectStepRequest ):Observable<number>{
return this.http.post<number>(this.config.getServerUrl()+ "/Projects/AddProjetStep",request); return this.http.post<number>(this.config.getServerUrl()+ "/Projects/AddProjectStep",request);
} }
//#endregion planning managment //#endregion planning managment
......
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