Commit a5828466 authored by hasan khaddour's avatar hasan khaddour

adddd the project and cutomer modules

parent a72a7c1b
......@@ -13,6 +13,13 @@
}
},
"root": "",
"i18n": {
"sourceLocale": "en",
"locales": {
"fr": "src/locale/messages.fr.xlf",
"es": "src/locale/messages.es.xlf"
}
},
"sourceRoot": "src",
"prefix": "",
"architect": {
......
......@@ -19,12 +19,17 @@
"@angular/platform-browser-dynamic": "^18.0.0",
"@angular/router": "^18.0.0",
"@fortawesome/fontawesome-free": "^6.6.0",
"@ngx-translate/core": "^15.0.0",
"@ngx-translate/http-loader": "^8.0.0",
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.3",
"feather-icons": "^4.29.2",
"i": "^0.3.7",
"jquery": "^3.7.1",
"jquery-sparkline": "^2.4.0",
"material": "^0.9.15",
"ngx-pagination": "^6.0.3",
"ngx-toastr": "^19.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
......@@ -3516,6 +3521,33 @@
"webpack": "^5.54.0"
}
},
"node_modules/@ngx-translate/core": {
"version": "15.0.0",
"resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-15.0.0.tgz",
"integrity": "sha512-Am5uiuR0bOOxyoercDnAA3rJVizo4RRqJHo8N3RqJ+XfzVP/I845yEnMADykOHvM6HkVm4SZSnJBOiz0Anx5BA==",
"engines": {
"node": "^16.13.0 || >=18.10.0"
},
"peerDependencies": {
"@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0",
"rxjs": "^6.5.5 || ^7.4.0"
}
},
"node_modules/@ngx-translate/http-loader": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-8.0.0.tgz",
"integrity": "sha512-SFMsdUcmHF5OdZkL1CHEoSAwbP5EbAOPTLLboOCRRoOg21P4GJx+51jxGdJeGve6LSKLf4Pay7BkTwmE6vxYlg==",
"engines": {
"node": "^16.13.0 || >=18.10.0"
},
"peerDependencies": {
"@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0",
"@ngx-translate/core": ">=15.0.0",
"rxjs": "^6.5.5 || ^7.4.0"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
......@@ -7760,6 +7792,14 @@
"node": ">=10.18"
}
},
"node_modules/i": {
"version": "0.3.7",
"resolved": "https://registry.npmjs.org/i/-/i-0.3.7.tgz",
"integrity": "sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q==",
"engines": {
"node": ">=0.4"
}
},
"node_modules/i18nsupport-lib": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/i18nsupport-lib/-/i18nsupport-lib-1.0.0.tgz",
......@@ -9877,6 +9917,31 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"node_modules/ngx-pagination": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/ngx-pagination/-/ngx-pagination-6.0.3.tgz",
"integrity": "sha512-lONjTQ7hFPh1SyhwDrRd5ZwM4NMGQ7bNR6vLrs6mrU0Z8Q1zCcWbf/pvyp4DOlGyd9uyZxRy2wUsSZLeIPjbAw==",
"dependencies": {
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/common": ">=13.0.0",
"@angular/core": ">=13.0.0"
}
},
"node_modules/ngx-toastr": {
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-19.0.0.tgz",
"integrity": "sha512-6pTnktwwWD+kx342wuMOWB4+bkyX9221pAgGz3SHOJH0/MI9erLucS8PeeJDFwbUYyh75nQ6AzVtolgHxi52dQ==",
"dependencies": {
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/common": ">=16.0.0-0",
"@angular/core": ">=16.0.0-0",
"@angular/platform-browser": ">=16.0.0-0"
}
},
"node_modules/nice-napi": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",
......
......@@ -4,8 +4,9 @@ import { LoginComponent } from './pages/login/login.component';
import { HomeComponent } from './pages/home/home.component';
import { LayoutComponent } from './shared/sharedLayout/layout/layout.component';
import { AuthGuard } from './core/guards/auth.guard';
import { CustomerListComponent } from './customers/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 { ProjectFAQComponent } from './pages/project-faq/project-faq.component';
export const routes: Routes = [
......@@ -22,6 +23,10 @@ export const routes: Routes = [
path: 'home',
component: HomeComponent
},
{
path: 'projectfaq',
component: ProjectFAQComponent
},
{
path: '',
component:HomeComponent ,
......@@ -29,9 +34,13 @@ export const routes: Routes = [
} ,
{
path: 'customers',
component: CustomerListComponent
loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
}
, {
path: 'projects',
loadChildren: () => import('./projects/projects.module').then(m => m.ProjectsModule)
}
]
}
......
<router-outlet />
<loading-spinner hidden></loading-spinner>
<router-outlet />
\ No newline at end of file
import { AfterViewInit, Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'app-root',
......@@ -6,5 +7,10 @@ import { AfterViewInit, Component } from '@angular/core';
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'PSManagement';
title ="PSManagement";
constructor() {
}
}
......@@ -5,7 +5,7 @@ import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginComponent } from './pages/login/login.component';
import { FormsModule } from '@angular/forms';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http';
import { ConfigurationService } from './core/services/configuration/configuration.service';
import { CoreModule } from './core/core.module';
import { HomeComponent } from './pages/home/home.component';
......@@ -18,31 +18,59 @@ import { CustomersModule } from './customers/customers.module';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { PageNotfoundComponent } from './pages/page-notfound/page-notfound.component';
import { LOCALE_ID } from '@angular/core';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { JwtInterceptor } from './core/interceptors/jwt.interceptor';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ToastrModule } from 'ngx-toastr';
import { NgxPaginationModule } from 'ngx-pagination';
import { CustomerRoutingModule } from './customers/customer-routing.module';
import { LoadingInterceptor } from './core/interceptors/loading.interceptor';
import { ProjectsModule } from './projects/projects.module';
import { ProjectRoutingModule } from './projects/project-routing.module';
import { ProjectFAQComponent } from './pages/project-faq/project-faq.component';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
LoginComponent,
PageNotfoundComponent,
ProjectFAQComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
CustomerRoutingModule,
ProjectRoutingModule,
FormsModule,
ProjectsModule,
CoreModule,
CustomersModule,
SharedModule,
NgxPaginationModule,
BrowserAnimationsModule, // Required for toast animations
ToastrModule.forRoot({
positionClass: 'toast-top-full-width', // Position the toast
timeOut: 3000, // Toast timeout
preventDuplicates: true,
progressBar: true, // Prevent duplicate toasts
}),
HttpClientModule
],
providers: [
provideAnimationsAsync(),
{ provide: LOCALE_ID, useValue: 'en' }
{ provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: LoadingInterceptor, multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule { }
// export function HttpLoaderFactory(http: HttpClient) {
// return new TranslateHttpLoader(http);
// }
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
......@@ -11,15 +11,13 @@ export class AuthGuard implements CanActivate {
next : ActivatedRouteSnapshot,
state: RouterStateSnapshot, ) {
//this.router.navigate(["/login"])
return true;
// if (this.auth.isAuthenticated()) {
// return true ;
// } else {
// this.router.navigate(["/login"])
// return false;
// }
if (this.auth.isAuthenticated()) {
return true ;
} else {
this.router.navigate(["/login"])
return false;
}
}
}
// src/app/services/jwt-interceptor.service.ts
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthenticationService } from '../services/authentication/authentication.service';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private authService : AuthenticationService ,) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = this.authService.getToken();
if (token) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
return next.handle(request);
}
}
// src/app/interceptors/loading.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { LoadingService } from '../services/loading/loading-service.service';
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
constructor(private loadingService: LoadingService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.loadingService.show();
return next.handle(req).pipe(
finalize(() => this.loadingService.hide())
);
}
}
export interface Result <T>{
isSuccess :boolean
isFailed :boolean
value :any
value :T
errors : string[]
reasons: string[]
valueOrDefault:any
successes: any[]
validationErrors :{
identifier: any,
errorMessage: string,
errorCode: string,
severity:number
}[]
}
\ No newline at end of file
export interface User {
id: string;
name: string;
userName: string
firstName :string
lastName :string,
roles :string[]
email: string;
avatarUrl: string;
}
\ No newline at end of file
import { TestBed } from '@angular/core/testing';
import { AuthenticationService } from './authentication.service';
describe('AuthenticationService', () => {
let service: AuthenticationService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AuthenticationService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
......@@ -3,7 +3,7 @@ import { HttpClient } from '@angular/common/http';
import { LoginRequest } from '../../models/authentication/loginRequest';
import { RegisterRequest } from '../../models/authentication/registerRequest';
import { AuthenticationResponse } from '../../models/authentication/authenticationResponse';
import { Observable } from 'rxjs';
import { catchError, Observable, throwError } from 'rxjs';
import { ConfigurationService } from '../configuration/configuration.service';
import { DataStorageService } from '../dataStorage/data-storage.service';
......@@ -28,7 +28,12 @@ export class AuthenticationService {
return this.http
.post<AuthenticationResponse>(
this.config.getServerUrl()+ "/Authentication/register",registerRequest)
this.config.getServerUrl()+ "/Authentication/register",registerRequest)
.pipe(
catchError(error => {
return throwError(() => error.error);
})
);
}
isAuthenticated():Boolean{
......@@ -39,4 +44,7 @@ export class AuthenticationService {
}
}
getToken(){
return this.dataStorage.getItem("token");
}
}
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
@Injectable({
providedIn: 'root'
})
export class LoadingService {
private loadingSubject = new BehaviorSubject<boolean>(false);
isLoading$ = this.loadingSubject.asObservable();
show() {
this.loadingSubject.next(true);
}
hide() {
this.loadingSubject.next(false);
}
}
<div class="card shadow mb-4">
<div class="card-body text-center">
<div class="avatar avatar-lg mt-4">
<a href="">
<img src="/assets/images/users/4.jpg" alt="..." class="avatar-img rounded-circle">
</a>
</div>
<div class="card-text my-2">
<strong class="card-title my-0">{{customer.customerName}} </strong>
<p class="small text-muted mb-0">{{customer.email}}</p>
<p class="small"><span class="badge badge-light text-muted">{{customer.address.city}} , {{customer.address.streetName}}</span></p>
</div>
</div> <!-- ./card-text -->
<div class="card-footer">
<div class="row align-items-center justify-content-between">
<div class="col-auto">
<small>
<span class=" mr-1"></span> </small>
</div>
<div class="col-auto">
<div class="file-action">
</div>
</div>
</div>
</div> <!-- /.card-footer -->
</div>
import { Component, Input } from '@angular/core';
import { Customer } from '../../models/customer';
@Component({
selector: 'customer-item',
templateUrl: './customer-item.component.html',
styleUrl: './customer-item.component.css'
})
export class CustomerItemComponent {
@Input() customer : Customer ;
constructor (){}
}
import { Component, Input } from '@angular/core';
import { Customer } from '../models/customer';
import { CustomerService } from '../services/customer.service';
@Component({
selector: 'customer-details',
templateUrl: './customer-details.component.html',
styleUrl: './customer-details.component.css'
})
export class CustomerDetailsComponent {
@Input() customer :Customer ;
name :string= ""
constructor(private customerServive :CustomerService){
}
handleInput(){
this.customer.customerName= this.name;
}
onDelete(customer: Customer) {
this.customerServive
.deleteCustomer(customer.id+10)
.subscribe(
{
next: (res)=>console.log(res),
error:(err)=>{
CustomerService.customers=CustomerService.customers.filter(o => o.id==customer.id);
console.log(CustomerService.customers)
}
}
);
}
}
<br>
<!-- <strong>Do you have a new customer
</strong>
<button class="btn btn-primary" (click)="toggle()">
Create
</button> -->
<br>
<div *ngIf="isCreate" (click)="toggle()">
dsfdf dsfsf dsf dfdsf sddf dfdf d
</div>
<strong class="text-muted"> you have a {{customers.length}} customers</strong>
<ol class="customers alternating-colors">
<li *ngFor="let cust of customers"
[class.selected]="cust === selectedCustomer"
(click)="onSelect(cust)">
<span class="badge">#</span> <strong>{{cust.customerName}}</strong>
</li>
</ol>
<customer-details [customer]="selectedCustomer"></customer-details>
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CustomerListComponent } from './pages/customer-list/customer-list.component';
import { UpdateCustomerComponent } from './pages/update-customer/update-customer.component';
import { CustomerDetailsComponent } from './pages/customer-details/customer-details.component';
import { CustomerCreateComponent } from './pages/customer-create/customer-create.component';
const routes: Routes = [
{ path: '', component: CustomerListComponent },
{ path: 'edit/:id', component: UpdateCustomerComponent },
{ path: 'create', component: CustomerCreateComponent },
{ path: 'detail/:id', component: CustomerDetailsComponent },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class CustomerRoutingModule { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CustomerListComponent } from './customer-list/customer-list.component';
import { CustomerListComponent } from './pages/customer-list/customer-list.component';
import { CustomerService } from './services/customer.service';
import { FormsModule, NgModel } from '@angular/forms';
import { CustomerDetailsComponent } from './customer-details/customer-details.component';
import { UpdateCustomerComponent } from './update-customer/update-customer.component';
import { CustomerDetailsComponent } from './pages/customer-details/customer-details.component';
import { UpdateCustomerComponent } from './pages/update-customer/update-customer.component';
import { CustomerRoutingModule } from './customer-routing.module';
import { SharedModule } from "../shared/shared.module";
import { CustomerItemComponent } from './components/customer-item/customer-item.component';
import { CustomerCreateComponent } from './pages/customer-create/customer-create.component';
......@@ -12,15 +16,17 @@ import { UpdateCustomerComponent } from './update-customer/update-customer.compo
declarations: [
CustomerListComponent,
CustomerDetailsComponent,
UpdateCustomerComponent
UpdateCustomerComponent,
CustomerItemComponent,
CustomerCreateComponent
],
imports: [
CommonModule,
FormsModule
],
FormsModule,
SharedModule
],
providers:[CustomerService],
exports:[
CustomerListComponent,
CustomerDetailsComponent]
CustomerRoutingModule]
})
export class CustomersModule { }
export interface CreateCustomerRequest{
customerName : string ,
email : string ,
address : {
city : string ,
streetName : string ,
streetNumber:number
}
}
\ No newline at end of file
......@@ -5,8 +5,7 @@ export interface Customer{
address :{
city : string ,
streetNumber : number ,
streetName : string ,
zipCode : number
streetName : string
}
contactInfo :{
contactValue :string,
......
<section class="section contact">
<div class="row gy-4">
<div class="col-xl-6 col offset-3">
<div class="card p-4">
<form class="php-email-form">
<div class="row gy-4">
<div class="col-12">
<input type="text" [(ngModel)]="request.customerName"
name="name" class="form-control" placeholder="Your Name" required>
</div>
<div class="col-6 ">
<input type="email" [(ngModel)]="request.email"
class="form-control" name="email" placeholder="Your Email" required>
</div>
<div class="col-6">
<input type="text" [(ngModel)]="request.address.streetName"
class="form-control" name="subject" placeholder="street Name" required>
</div>
<div class="col-6">
<input type="number" [(ngModel)]="request.address.streetNumber"
class="form-control" name="subject" placeholder="street Number" required>
</div>
<div class="col-6">
<input type="text" [(ngModel)]="request.address.city"
class="form-control" name="subject" placeholder="city " required>
</div>
<div class="col-md-12 text-center">
<button class="btn btn-primary" (click)="submit(request)">إضافة</button>
</div>
</div>
</form>
</div>
</div>
</div>
</section>
import { Component } from '@angular/core';
import { CreateCustomerRequest } from '../../models/createCustomerRequest';
import { CustomerService } from '../../services/customer.service';
import { ToastrService } from 'ngx-toastr';
import { Router } from '@angular/router';
@Component({
selector: 'customer-create',
templateUrl: './customer-create.component.html',
styleUrl: './customer-create.component.css'
})
export class CustomerCreateComponent {
request : CreateCustomerRequest ={
customerName :"",
email:"",
address :{
city:"",
streetName:"",
streetNumber:0
}
}
constructor(
private customerService :CustomerService,
private toastr : ToastrService,
private router : Router
){}
submit(request : CreateCustomerRequest){
this.customerService.createCustomer(request)
.subscribe({
next : (res)=>{
if(res.isSuccess){
this.toastr.success("تمت إضافة الجهة بنجاح");
this.router.navigate(['customers/detail', res.value.id]);
}else {
this.toastr.error(res.validationErrors[0].errorMessage);
}
}
,
error : (err)=>this.toastr.error("An error Occured")
});
}
}
<div *ngIf="customer" class="card col-6 offset-3 mb-3" style="border-radius: .5rem;">
<div *ngIf="customer" class="card col-6 offset-1 mb-3" style="border-radius: .5rem;">
<div class="row g-0">
<div class="col-md-4 gradient-custom text-center text-black"
style="border-top-left-radius: .5rem; border-bottom-left-radius: .5rem;">
......@@ -14,7 +14,7 @@
<div class="col-6 mb-3">
<h6>Address</h6>
<p class="text-muted">{{customer.address.city}} - {{customer.address.streetName}}</p>
<p class="text-muted">Street Name : {{customer.address.streetNumber}} - {{customer.address.zipCode}}</p>
<p class="text-muted">Street Name : {{customer.address.streetNumber}} </p>
</div>
......
import { Component, Input, OnInit } from '@angular/core';
import { Customer } from '../../models/customer';
import { CustomerService } from '../../services/customer.service';
import { ActivatedRoute, Router, RouteReuseStrategy } from '@angular/router';
import { ToastrService } from 'ngx-toastr';
@Component({
selector: 'customer-details',
templateUrl: './customer-details.component.html',
styleUrl: './customer-details.component.css'
})
export class CustomerDetailsComponent implements OnInit {
customer: Customer | undefined;
constructor(
private router : Router,
private route: ActivatedRoute,
private customerService: CustomerService,
private toastr: ToastrService
) {}
ngOnInit(): void {
const id = Number(this.route.snapshot.paramMap.get('id'));
this.customerService.getCustomerById(id).subscribe({
next :(data) => {
console.log(data.validationErrors)
if(data.isSuccess){
this.customer = data.value;
}else {
this.toastr.error(data.validationErrors[0].errorMessage);
// this.router()
}
},
error : (err)=>{ console.log(err)}
});
}
}
\ No newline at end of file
<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)="this.router.navigate(['customers/create'])" class="btn btn-primary"><span class="fe fe-file-plus fe-12 mr-2"></span>إضافة جهة جديدة</button>
</div>
</div>
<div class="row">
<customer-item (click)="this.router.navigate(['customers/detail', cust.id])" *ngFor="let cust of customers" class="col-md-3" [customer]="cust"></customer-item>
</div>
</div>
</div>
import { Component, OnInit } from '@angular/core';
import { Customer } from '../models/customer';
import { CustomerService } from '../services/customer.service';
import { Customer } from '../../models/customer';
import { CustomerService } from '../../services/customer.service';
import { CustomerDetailsComponent } from '../customer-details/customer-details.component';
import { MatDialog } from '@angular/material/dialog';
import { UpdateCustomerComponent } from '../update-customer/update-customer.component';
import { config } from 'rxjs';
import { ToastrService } from 'ngx-toastr';
import { Router } from '@angular/router';
import { LoadingService } from '../../../core/services/loading/loading-service.service';
@Component({
selector: 'customer-list',
......@@ -14,46 +17,57 @@ import { config } from 'rxjs';
export class CustomerListComponent implements OnInit {
customers :Customer[]=[]
isCreate = false
loading = true
selectedCustomer: Customer;
currentPage = 1;
itemsPerPage = 5;
constructor(
private dialog: MatDialog,
private customerService : CustomerService) {
private customerService : CustomerService,
private toastr: ToastrService,
public router: Router,
private loadingService: LoadingService
) {
}
selectedCustomer: Customer;
onSelect(customer: Customer): void {
this.selectedCustomer = customer;
}
ngOnInit(): void {
this.loadCustomers();
}
loadCustomers() {
this.loadingService.show();
this.customerService.getCustomers().subscribe({
next : (res) =>{
console.log(res);
if(res.isSuccess){
this.toastr.success('تم تحميل الجهات الطارجة بنجاح');
this.customers = res.value;
}else {
this.toastr.error(res.errors[0],"error");
}
this.loadingService.hide();
},
error: (err)=>{this.customers= CustomerService.customers}
});;
}
openEditForm(data: Customer | null) {
const dialogRef = this.dialog.open(UpdateCustomerComponent, {
data:data,
width:'auto',
height:'500px'
error: (err)=>{
this.toastr.error('Failed to load customers');
this.loadingService.hide();
}
});
dialogRef.afterClosed().subscribe({
next: (val) => {
if (val) {
this.customers;
}
},
});
}
toggle():void{
this.isCreate = ! this.isCreate
}
pageChanged(event: number): void {
this.currentPage = event;
}
}
......@@ -16,10 +16,7 @@
<label for="ustomerCity" class="form-label"></label>
<input id="customerCity" [(ngModel)]="customer.address.city" class="form-control" />
</div>
<div class="form-group mb-4">
<label for="customerZipcode" class="form-label"></label>
<input id="customerZipcode" [(ngModel)]="customer.address.zipCode" class="form-control" />
</div>
<div class="form-group mb-4">
<label for="CustomerStreetName" class="form-label"></label>
<input id="CustomerStreetName" [(ngModel)]="customer.address.streetName" class="form-control" />
......
import { Component, Input, input, Output } from '@angular/core';
import { Customer } from '../models/customer';
import { CustomerService } from '../services/customer.service';
import { Customer } from '../../models/customer';
import { CustomerService } from '../../services/customer.service';
@Component({
selector: 'update-customer',
......
......@@ -4,58 +4,13 @@ import { HttpClient } from '@angular/common/http';
import { ConfigurationService } from '../../core/services/configuration/configuration.service';
import { Observable } from 'rxjs';
import { Result } from '../../core/models/result';
import { CreateCustomerRequest } from '../models/createCustomerRequest';
@Injectable({
providedIn: 'root'
})
export class CustomerService {
public static customers : Customer[] = [
{ id :1,
customerName:"CQRE",
email :"CQRE@CC.mail",
address :{
streetName:"Barzeh",
streetNumber:12,
city:"Damascus",
zipCode:1223
},
contactInfo :[
{
contactType:"mob",
contactValue:"096734635"
},
{
contactType:"fax",
contactValue:"32434-32434-34"
},
]
},{
id :2,
customerName:"BBS",
email :"BBS@CC.mail",
address :{
streetName:"Barzeh",
streetNumber:112,
city:"Damascus",
zipCode:1223
},
contactInfo :[]
},{
id :3,
customerName:"ERW",
email :"EWR@CC.mail",
address :{
streetName:"Barzeh",
streetNumber:232,
city:"Damascus",
zipCode:1223
},
contactInfo :[]
}
];
constructor(private http :HttpClient ,private config : ConfigurationService) { }
public getCustomers():Observable<Result<Customer[]>>{
......@@ -68,9 +23,9 @@ export class CustomerService {
return this.http.get<Result<Customer>>(this.config.getServerUrl()+ "/Customers/"+id);
}
public createCustomer(customer :Customer):Observable<Result<void>>{
public createCustomer(customer :CreateCustomerRequest):Observable<Result<Customer>>{
return this.http.post<Result<void>>(this.config.getServerUrl()+ "/Customers",customer);
return this.http.post<Result<Customer>>(this.config.getServerUrl()+ "/Customers",customer);
}
public updateCustomer(id :number ,customer :Customer):Observable<Result<void>>{
......
import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { LoginRequest } from '../../core/models/authentication/loginRequest';
import { ConfigurationService } from '../../core/services/configuration/configuration.service';
import { AuthenticationService } from '../../core/services/authentication/authentication.service';
import { AuthenticationResponse } from '../../core/models/authentication/authenticationResponse';
import { DataStorageService } from '../../core/services/dataStorage/data-storage.service';
import { ToastrService } from 'ngx-toastr';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrl: './login.component.css'
})
export class LoginComponent {
export class LoginComponent implements OnInit {
loginRequest:LoginRequest = {
email :"",
passWord:""
}
ngOnInit(): void {
if(this.authService.isAuthenticated()){
this.toastr.info('أنت مسجل بالفعل لاداعي لإعادة التسجيل', ' ')
this.router.navigateByUrl('/home');
}
}
constructor(private dataStorage : DataStorageService,private router: Router,private authService :AuthenticationService ) {
constructor(
private dataStorage : DataStorageService,
private router: Router,
private authService :AuthenticationService,
private toastr: ToastrService ) {
}
......@@ -32,16 +44,23 @@ export class LoginComponent {
this.dataStorage.setItem('userDetails', JSON.stringify(res));
this.dataStorage.setItem('token', JSON.stringify(res.token));
console.log(res.token)
this.toastr.info('مرحبا بك مجددا يا ' + res.firstName+" " +res.lastName);
this.router.navigateByUrl('/home');
} else {
}
},
error: (err)=>{
console.log(err);
this.router.navigateByUrl('/home');
this.showErrors(err.errors || ['An unexpected error occurred.']);
// this.router.navigateByUrl('/home');
}
});
}
private showErrors(errors: string[]): void {
errors.forEach(error => this.toastr.error(error, 'Login Failed'));
}
}
<div class="pagetitle">
<h1>ملامح المشروع</h1>
<p> أسئلة يجب أن تطلع عليها قبل البدء بتخطيط مشروع </p>
</div><!-- End Page Title -->
<section class="section faq">
<div class="row">
<div class="col-lg-6">
<div class="card basic">
<div class="card-body">
<h5 class="card-title">أسئلة تعريفية</h5>
<div>
<h6> ما هو الهدف من المشروع ؟ </h6>
<p>ضع صورة واضحة في ذهنك عن هدف المشروع فهي أساسيةلإنجاح المشروع </p>
</div>
<div class="pt-2">
<h6>ماهي متطلبات الجهة الطارحة ؟ </h6>
<p>قم بتحديد متطلبات الجهة الطارحة بدقة</p>
</div>
<div class="pt-2">
<h6>ما هو العمل الذي ستقوم به ومانطاقه ؟</h6>
<p>قم بتحديد نطاق المشروع وهدفه بدقة</p>
</div>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<h5 class="card-title">ماذا يجب أن تفعل اثناء تخطيط المشروع</h5>
<div class="accordion accordion-flush" id="faq-group-1">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" data-bs-target="#faqsOne-1" type="button" data-bs-toggle="collapse">
إضافة خطة الانفاق التقديرية
</button>
</h2>
<div id="faqsOne-1" class="accordion-collapse collapse" data-bs-parent="#faq-group-1">
<div class="accordion-body">
Ut quasi odit odio totam accusamus vero eius. Nostrum asperiores voluptatem eos nulla ab dolores est asperiores iure. Quo est quis praesentium aut maiores. Corrupti sed aut expedita fugit vero dolorem. Nemo rerum sapiente. A quaerat dignissimos.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" data-bs-target="#faqsOne-2" type="button" data-bs-toggle="collapse">
دراسة الجدوى الاقتصادية</button>
</h2>
<div id="faqsOne-2" class="accordion-collapse collapse" data-bs-parent="#faq-group-1">
<div class="accordion-body">
In minus quia impedit est quas deserunt deserunt et. Nulla non quo dolores minima fugiat aut saepe aut inventore. Qui nesciunt odio officia beatae iusto sed voluptatem possimus quas. Officia vitae sit voluptatem nostrum a.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" data-bs-target="#faqsOne-3" type="button" data-bs-toggle="collapse">
تحديد فريق العمل
</button>
</h2>
<div id="faqsOne-3" class="accordion-collapse collapse" data-bs-parent="#faq-group-1">
<div class="accordion-body">
Voluptates magni amet enim perspiciatis atque excepturi itaque est. Sit beatae animi incidunt eum repellat sequi ea saepe inventore. Id et vel et et. Nesciunt itaque corrupti quia ducimus. Consequatur maiores voluptatum fuga quod ut non fuga.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" data-bs-target="#faqsOne-4" type="button" data-bs-toggle="collapse">
تحديد الخطة
</button>
</h2>
<div id="faqsOne-4" class="accordion-collapse collapse" data-bs-parent="#faq-group-1">
<div class="accordion-body">
Numquam ut reiciendis aliquid. Quia veritatis quasi ipsam sed quo ut eligendi et non. Doloremque sed voluptatem at in voluptas aliquid dolorum.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" data-bs-target="#faqsOne-5" type="button" data-bs-toggle="collapse">
صنف المشروع
</button>
</h2>
<div id="faqsOne-5" class="accordion-collapse collapse" data-bs-parent="#faq-group-1">
<div class="accordion-body">
Aut necessitatibus maxime quis dolor et. Nihil laboriosam molestiae qui molestias placeat corrupti non quo accusamus. Nemo qui quis harum enim sed. Aliquam molestias pariatur delectus voluptas quidem qui rerum id quisquam. Perspiciatis voluptatem voluptatem eos. Vel aut minus labore at rerum eos.
</div>
</div>
</div>
</div>
</div>
<!-- F.A.Q Group 2 -->
</div><!-- End F.A.Q Group 2 -->
<!-- F.A.Q Group 3 -->
<div class="card">
<div class="card-body">
<h5 class="card-title">Dolore occaecati ducimus quam</h5>
<div class="accordion accordion-flush" id="faq-group-3">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" data-bs-target="#faqsThree-1" type="button" data-bs-toggle="collapse">
Assumenda doloribus est fugiat sint incidunt animi totam nisi?
</button>
</h2>
<div id="faqsThree-1" class="accordion-collapse collapse" data-bs-parent="#faq-group-3">
<div class="accordion-body">
Ut quasi odit odio totam accusamus vero eius. Nostrum asperiores voluptatem eos nulla ab dolores est asperiores iure. Quo est quis praesentium aut maiores. Corrupti sed aut expedita fugit vero dolorem. Nemo rerum sapiente. A quaerat dignissimos.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" data-bs-target="#faqsThree-2" type="button" data-bs-toggle="collapse">
Consequatur saepe explicabo odio atque nisi?
</button>
</h2>
<div id="faqsThree-2" class="accordion-collapse collapse" data-bs-parent="#faq-group-3">
<div class="accordion-body">
In minus quia impedit est quas deserunt deserunt et. Nulla non quo dolores minima fugiat aut saepe aut inventore. Qui nesciunt odio officia beatae iusto sed voluptatem possimus quas. Officia vitae sit voluptatem nostrum a.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" data-bs-target="#faqsThree-3" type="button" data-bs-toggle="collapse">
Voluptates vel est fugiat molestiae rem sit eos sint?
</button>
</h2>
<div id="faqsThree-3" class="accordion-collapse collapse" data-bs-parent="#faq-group-3">
<div class="accordion-body">
Voluptates magni amet enim perspiciatis atque excepturi itaque est. Sit beatae animi incidunt eum repellat sequi ea saepe inventore. Id et vel et et. Nesciunt itaque corrupti quia ducimus. Consequatur maiores voluptatum fuga quod ut non fuga.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" data-bs-target="#faqsThree-4" type="button" data-bs-toggle="collapse">
Ab ipsa cum autem voluptas doloremque velit?
</button>
</h2>
<div id="faqsThree-4" class="accordion-collapse collapse" data-bs-parent="#faq-group-3">
<div class="accordion-body">
Numquam ut reiciendis aliquid. Quia veritatis quasi ipsam sed quo ut eligendi et non. Doloremque sed voluptatem at in voluptas aliquid dolorum.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" data-bs-target="#faqsThree-5" type="button" data-bs-toggle="collapse">
Aliquam magni ducimus facilis numquam dolorum harum eveniet iusto?
</button>
</h2>
<div id="faqsThree-5" class="accordion-collapse collapse" data-bs-parent="#faq-group-3">
<div class="accordion-body">
Aut necessitatibus maxime quis dolor et. Nihil laboriosam molestiae qui molestias placeat corrupti non quo accusamus. Nemo qui quis harum enim sed. Aliquam molestias pariatur delectus voluptas quidem qui rerum id quisquam. Perspiciatis voluptatem voluptatem eos. Vel aut minus labore at rerum eos.
</div>
</div>
</div>
</div>
</div>
</div><!-- End F.A.Q Group 3 -->
</div>
</div>
</section>
import { Component } from '@angular/core';
@Component({
selector: 'project-faq',
templateUrl: './project-faq.component.html',
styleUrl: './project-faq.component.css'
})
export class ProjectFAQComponent {
}
import { Component } from '@angular/core';
@Component({
selector: 'attachment',
templateUrl: './attachment.component.html',
styleUrl: './attachment.component.css'
})
export class AttachmentComponent {
}
<div class="card shadow mb-4">
<div class="card-body text-center">
<div class="avatar avatar-lg mt-4">
<a href="">
<img src="/assets/images/users/4.jpg" alt="..." class="avatar-img rounded-circle">
</a>
</div>
<div class="card-text my-2">
<strong class="card-title my-0">{{project.projectInfo.name}} </strong>
<p class="small">{{project.projectInfo.description}}</p>
<p class="small">ينفذ من قبل {{project.executer.name}}</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>
</div>
</div> <!-- ./card-text -->
<div class="card-footer">
<div class="row align-items-center justify-content-between">
<div class="col-auto">
<small>
<span class=" mr-1"></span> </small>
</div>
<div class="col-auto">
<div class="file-action">
{{project.currentState}}
</div>
</div>
</div>
</div> <!-- /.card-footer -->
</div>
import { Component, Input } from '@angular/core';
import { Router } from '@angular/router';
import { Project } from '../../models/responses/project';
@Component({
selector: 'project-item',
templateUrl: './project-item.component.html',
styleUrl: './project-item.component.css'
})
export class ProjectItemComponent {
@Input() project :Project
constructor( public router: Router){
}
}
import { FinancialFund } from "../valueObjects/FinancialFund"
import { ProjectInfo } from "../valueObjects/ProjectInfo"
import { ProposalInfo } from "../valueObjects/proposalInfo"
export class Project
{
id:number
proposalInfo : ProposalInfo
projectInfo :ProjectInfo
currentState: any
projectAggreement :any
teamLeaderId: number
teamLeader :any
projectManagerId:number
executer:any
proposerId:any
steps :any
financialFund:FinancialFund
}
export interface FinancialFund {
financialStatus: string;
source: string;
}
export interface ProjectInfo {
name: string;
code: String;
description: String;
startDate: Date;
expectedEndDate: Date;
}
export interface ProposalInfo{
proposingBookNumber :number
proposingBookDate : Date
}
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-12 col-lg-10 col-xl-8">
<div class="row align-items-center mb-4">
<div class="col">
<h2 class="h5 page-title"><small class="text-muted text-uppercase">Invoice</small><br />#1806</h2>
</div>
<div class="col-auto">
<button type="button" class="btn btn-secondary m-1">Print</button>
</div>
</div>
<div class="card shadow">
<div class="card-body p-5">
<div class="row mb-5">
<div class="col-12 text-center mb-4">
<img src="/assets/images/users/4.jpg" class="navbar-brand-img brand-sm mx-auto mb-4" alt="...">
<h2 class="mb-0 text-uppercase"> مشروع أتمتة أعمال شؤون الطلاب</h2>
<p class="text-muted"> بدء بتاريخ<br /> 9022 Suspendisse Rd. </p>
</div>
<div class="col-md-7">
<p class="small text-muted text-uppercase mb-2">Invoice from</p>
<p class="mb-4">
<strong>Imani Lara</strong><br /> Asset Management<br /> 9022 Suspendisse Rd.<br /> High Wycombe<br /> (478) 446-9234<br />
</p>
<p>
<span class="small text-muted text-uppercase">Invoice #</span><br />
<strong>1806</strong>
</p>
</div>
<div class="col-md-5">
<p class="small text-muted text-uppercase mb-2">Invoice to</p>
<p class="mb-4">
<strong>Walter Sawyer</strong><br /> Human Resources<br /> Ap #992-8933 Sagittis Street<br /> Ivanteyevka<br /> (803) 792-2559<br />
</p>
<p>
<small class="small text-muted text-uppercase">Due date</small><br />
<strong>April, 20, 2020</strong>
</p>
</div>
</div> <!-- /.row -->
<table class="table table-borderless table-striped">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Description</th>
<th scope="col" class="text-right">Rate</th>
<th scope="col" class="text-right">Hours</th>
<th scope="col" class="text-right">Ammout</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td> Creative Design<br />
<span class="small text-muted">Design responsive website with existing prototype</span>
</td>
<td class="text-right">$15.00</td>
<td class="text-right">2</td>
<td class="text-right">$30.00</td>
</tr>
<tr>
<th scope="row">2</th>
<td> Front-End Development<br />
<span class="small text-muted">Markup conversion and adding JavaScript</span>
</td>
<td class="text-right">$20.00</td>
<td class="text-right">5</td>
<td class="text-right">$100.00</td>
</tr>
<tr>
<th scope="row">2</th>
<td> Back-End Development<br />
<span class="small text-muted">Database intergration with model functions</span>
</td>
<td class="text-right">$25.00</td>
<td class="text-right">7</td>
<td class="text-right">$155.00</td>
</tr>
</tbody>
</table>
<div class="row mt-5">
<div class="col-2 text-center">
<img src="/assets/images/users/4.jpg" class="navbar-brand-img brand-sm mx-auto my-4" alt="...">
</div>
<div class="col-md-5">
<p class="text-muted small">
<strong>Note :</strong> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam hendrerit nisi sed sollicitudin pellentesque. Nunc posuere purus rhoncus pulvinar aliquam. </p>
</div>
<div class="col-md-5">
<div class="text-right mr-2">
<p class="mb-2 h6">
<span class="text-muted">Subtotal : </span>
<strong>$285.00</strong>
</p>
<p class="mb-2 h6">
<span class="text-muted">VAT (10%) : </span>
<strong>$28.50</strong>
</p>
<p class="mb-2 h6">
<span class="text-muted">Total : </span>
<span>$313.50</span>
</p>
</div>
</div>
</div> <!-- /.row -->
</div> <!-- /.card-body -->
</div> <!-- /.card -->
</div> <!-- /.col-12 -->
</div> <!-- .row -->
</div> <!-- .container-fluid -->
\ No newline at end of file
import { Component, OnInit } from '@angular/core';
import { ProjectService } from '../../services/project.service';
import { ActivatedRoute, Router } from '@angular/router';
import { ToastrService } from 'ngx-toastr';
import { Project } from '../../models/responses/project';
@Component({
selector: 'project-details',
templateUrl: './project-details.component.html',
styleUrl: './project-details.component.css'
})
export class ProjectDetailsComponent implements OnInit {
project : Project
constructor(
private router : Router,
private route: ActivatedRoute,
private projectService: ProjectService,
private toastr: ToastrService
) {}
ngOnInit(): void {
const id = Number(this.route.snapshot.paramMap.get('id'));
this.projectService.getProjectById(id).subscribe({
next :(data) => {
console.log(data.validationErrors)
if(data.isSuccess){
this.project = data.value;
}else {
this.toastr.error(data.validationErrors[0].errorMessage);
// this.router()
}
},
error : (err)=>{ console.log(err)}
});
}
}
<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)="this.router.navigate(['project/create'])" class="btn btn-primary"><span class="fe fe-file-plus fe-12 mr-2"></span>طرح مشروع</button>
</div>
</div>
<div class="row">
<project-item class="col-md-4" *ngFor="let project of projects" [project]="project"></project-item>
</div>
</div>
</div>
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ProjectService } from '../../services/project.service';
import { ToastrService } from 'ngx-toastr';
import { LoadingService } from '../../../core/services/loading/loading-service.service';
import { Project } from '../../models/responses/project';
@Component({
selector: 'project-list',
templateUrl: './project-list.component.html',
styleUrl: './project-list.component.css'
})
export class ProjectListComponent implements OnInit{
projects : Project[]
constructor(
private projectService : ProjectService,
private toastr: ToastrService,
public router: Router,
private loadingService: LoadingService
) {
}
ngOnInit(): void {
this.loadProjects();
}
loadProjects():void{
this.projectService.getByFilter()
.subscribe(
{
next: (res)=>{
if(res.isSuccess){
this.projects = res.value;
this.toastr.success("تم تحميل المشاريع بنجاح");
}
},
error: (err)=>{
this.toastr.error("لقد حدث خظاء ما");
}
}
);
}
}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ProjectListComponent } from './pages/project-list/project-list.component';
import { ProjectDetailsComponent } from './pages/project-details/project-details.component';
const routes: Routes = [
{path:'',component :ProjectListComponent},
{ path: 'detail/:id', component: ProjectDetailsComponent },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ProjectRoutingModule { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ProjectItemComponent } from './components/project-item/project-item.component';
import { AttachmentComponent } from './components/attachment/attachment.component';
import { ProjectListComponent } from './pages/project-list/project-list.component';
import { ProjectDetailsComponent } from './pages/project-details/project-details.component';
import { ProjectService } from './services/project.service';
import { FormsModule } from '@angular/forms';
import { SharedModule } from '../shared/shared.module';
import { ProjectRoutingModule } from './project-routing.module';
@NgModule({
declarations: [
ProjectItemComponent,
AttachmentComponent,
ProjectListComponent,
ProjectDetailsComponent
],
providers:[
ProjectService
],
exports:[
ProjectRoutingModule
],
imports: [
CommonModule,
FormsModule,
SharedModule
]
})
export class ProjectsModule { }
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ConfigurationService } from '../../core/services/configuration/configuration.service';
import { Project } from '../models/responses/project';
import { Result } from '../../core/models/result';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ProjectService {
constructor(private http :HttpClient ,private config : ConfigurationService) { }
public getByFilter():Observable<Result<Project[]>>{
return this.http.get<Result<Project[]>>(this.config.getServerUrl()+ "/Projects/ByFilter");
}
public getProjectById(id : number ):Observable<Result<Project>>{
return this.http.get<Result<Project>>(this.config.getServerUrl()+ "/Projects/"+id);
}
}
\ No newline at end of file
.spinner-wrapper {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.spinner {
border: 4px solid rgba(0, 0, 0, 0.1);
border-left-color: #22a6b3;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
\ No newline at end of file
<div class="spinner-wrapper">
<div class="spinner"></div>
</div>
\ No newline at end of file
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { LoadingService } from '../../../core/services/loading/loading-service.service';
@Component({
selector: 'loading-spinner',
templateUrl: './loading-spinner.component.html',
styleUrl: './loading-spinner.component.css'
})
export class LoadingSpinnerComponent {
isLoading$: Observable<boolean> = this.loadingService.isLoading$;
constructor(private loadingService: LoadingService) {
}
}
<p>list-item works!</p>
<li class="nav-item">
<a class="nav-link " [class.collapsed]="item.haschild" data-bs-target="#components-nav" data-bs-toggle="collapse" href="#">
<i class="fe fe-menu"></i><span>{{item.name}}</span><i class="bi bi-chevron-down ms-auto"></i>
</a>
<ul *ngFor="let i of item.child">
<nav-item [item]="i"></nav-item>
</ul>
</li><!-- End Components Nav -->
\ No newline at end of file
import { Component } from '@angular/core';
import { Component, Input } from '@angular/core';
export interface NavItem {
name : string ,
child : NavItem []| null,
haschild:boolean
}
@Component({
selector: 'nav-item',
templateUrl: './nav-item.component.html',
styleUrl: './nav-item.component.css'
})
export class NavItemComponent {
@Input()item:NavItem
}
......@@ -6,7 +6,8 @@ import { SidebarComponent } from './sharedLayout/sidebar/sidebar.component';
import { LayoutComponent } from './sharedLayout/layout/layout.component';
import { RouterModule } from '@angular/router';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { NavItemComponent } from './componenets/nav-item/nav-item.component';
import { LoadingSpinnerComponent } from './componenets/loading-spinner/loading-spinner.component';
@NgModule({
......@@ -15,7 +16,9 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
HeaderComponent,
FooterComponent,
SidebarComponent,
LayoutComponent
LayoutComponent,
NavItemComponent,
LoadingSpinnerComponent
],
imports: [
......@@ -26,7 +29,8 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
HeaderComponent,
FooterComponent,
SidebarComponent,
LayoutComponent
LayoutComponent,
LoadingSpinnerComponent
],schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class SharedModule { }
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FooterComponent } from './footer.component';
describe('FooterComponent', () => {
let component: FooterComponent;
let fixture: ComponentFixture<FooterComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [FooterComponent]
})
.compileComponents();
fixture = TestBed.createComponent(FooterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
.o-income .c3 line, .o-income .c3 path {
stroke: rgba(120, 130, 140, 0.13); }
\ No newline at end of file
.logo {
line-height: 1;
}
@media (min-width: 1200px) {
.logo {
width: 280px;
}
}
.logo img {
max-height: 26px;
margin-right: 16px;
}
.logo span {
font-size: 26px;
color: #012970;
font-family: "Nunito", sans-serif;
}
.header {
transition: all 0.5s;
z-index: 997;
height: 60px;
box-shadow: 0px 2px 20px rgba(1, 41, 112, 0.1);
background-color: #fff;
padding-left: 20px;
/* Toggle Sidebar Button */
/* Search Bar */
}
.header .toggle-sidebar-btn {
font-size: 32px;
padding-left: 10px;
padding-right: 20px;
cursor: pointer;
color: #012970;
}
.header .search-bar {
min-width: 360px;
padding: 0 20px;
}
@media (max-width: 1199px) {
.header .search-bar {
position: fixed;
top: 50px;
left: 0;
right: 0;
padding: 20px;
box-shadow: 0px 0px 15px 0px rgba(1, 41, 112, 0.1);
background: white;
z-index: 9999;
transition: 0.3s;
visibility: hidden;
opacity: 0;
}
.header .search-bar-show {
top: 60px;
visibility: visible;
opacity: 1;
}
}
.header .search-form {
width: 100%;
}
.header .search-form input {
border: 0;
font-size: 14px;
color: #012970;
border: 1px solid rgba(1, 41, 112, 0.2);
padding: 7px 38px 7px 8px;
border-radius: 3px;
transition: 0.3s;
width: 100%;
}
.header .search-form input:focus,
.header .search-form input:hover {
outline: none;
box-shadow: 0 0 10px 0 rgba(1, 41, 112, 0.15);
border: 1px solid rgba(1, 41, 112, 0.3);
}
.header .search-form button {
border: 0;
padding: 0;
margin-left: -30px;
background: none;
}
.header .search-form button i {
color: #012970;
}
/*--------------------------------------------------------------
# Header Nav
--------------------------------------------------------------*/
.header-nav ul {
list-style: none;
}
.header-nav>ul {
margin: 0;
padding: 0;
}
.header-nav .nav-icon {
font-size: 22px;
color: #012970;
margin-right: 25px;
margin-left: 25px;
position: relative;
}
.header-nav .nav-profile {
color: #012970;
}
.header-nav .nav-profile img {
max-height: 36px;
}
.header-nav .nav-profile span {
font-size: 14px;
font-weight: 600;
}
.header-nav .badge-number {
position: absolute;
inset: -2px -5px auto auto;
font-weight: normal;
font-size: 12px;
padding: 3px 6px;
}
.header-nav .notifications {
inset: 8px -15px auto auto !important;
}
.header-nav .notifications .notification-item {
display: flex;
align-items: center;
padding: 15px 10px;
transition: 0.3s;
}
.header-nav .notifications .notification-item i {
margin: 0 20px 0 10px;
font-size: 24px;
}
.header-nav .notifications .notification-item h4 {
font-size: 16px;
font-weight: 600;
margin-bottom: 5px;
}
.header-nav .notifications .notification-item p {
font-size: 13px;
margin-bottom: 3px;
color: #919191;
}
.header-nav .notifications .notification-item:hover {
background-color: #f6f9ff;
}
.header-nav .messages {
inset: 8px -15px auto auto !important;
}
.header-nav .messages .message-item {
padding: 15px 10px;
transition: 0.3s;
}
.header-nav .messages .message-item a {
display: flex;
}
.header-nav .messages .message-item img {
margin: 0 20px 0 10px;
max-height: 40px;
}
.header-nav .messages .message-item h4 {
font-size: 16px;
margin-bottom: 5px;
color: #444444;
}
.header-nav .messages .message-item p {
font-size: 13px;
margin-bottom: 3px;
color: #919191;
}
.header-nav .messages .message-item:hover {
background-color: #f6f9ff;
}
.msi-auto{
margin-right: auto!important;
}
.header-nav .profile {
min-width: 240px;
padding-bottom: 0;
top: 8px !important;
}
.header-nav .profile .dropdown-header h6 {
font-size: 18px;
margin-bottom: 0;
font-weight: 600;
color: #444444;
}
.header-nav .profile .dropdown-header span {
font-size: 14px;
}
.header-nav .profile .dropdown-item {
font-size: 14px;
padding: 10px 15px;
transition: 0.3s;
}
.header-nav .profile .dropdown-item i {
margin-right: 10px;
font-size: 18px;
line-height: 0;
}
.header-nav .profile .dropdown-item:hover {
background-color: #f6f9ff;
}
@media (min-width: 1200px) {
#main,
#footer {
margin-right: 300px;
}
}
\ No newline at end of file
<header id="header" class="header fixed-top d-flex align-items-center">
<div class="d-flex align-items-center justify-content-between">
<a href="index.html" class="logo d-flex align-items-center">
<img src="assets/images/logo/logo.ico" alt="">
<span class="d-none d-lg-block">نظام إدارة المشاريع</span>
</a>
<i class="bi fe-align-justify toggle-sidebar-btn" (click)="toggleSidebar()"></i>
</div><!-- End Logo -->
<div class="search-bar">
<form class="search-form d-flex align-items-center" method="POST" action="#">
<input type="text" name="query" placeholder="Search" title="Enter search keyword">
<button type="submit" title="Search"><i class="fe fe-search"></i></button>
</form>
</div><!-- End Search Bar -->
<nav class="header-nav ms-auto">
<header dir="ltr" id="header" class="header fixed-top d-flex align-items-center">
<nav class="header-nav msi-auto">
<ul class="d-flex align-items-center">
<li class="nav-item d-block d-lg-none">
......@@ -24,146 +8,6 @@
</a>
</li><!-- End Search Icon-->
<li class="nav-item dropdown">
<a class="nav-link nav-icon" href="#" data-bs-toggle="dropdown">
<i class="fe fe-bell"></i>
<span class="badge bg-primary badge-number">4</span>
</a><!-- End Notification Icon -->
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow notifications">
<li class="dropdown-header">
You have 4 new notifications
<a href="#"><span class="badge rounded-pill bg-primary p-2 ms-2">View all</span></a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="fe fe-navigation text-warning"></i>
<div>
<h4>Lorem Ipsum</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>30 min. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="fe fe-x-circle text-danger"></i>
<div>
<h4>Atque rerum nesciunt</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>1 hr. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="fe fe-check-circle text-success"></i>
<div>
<h4>Sit rerum fuga</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>2 hrs. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="fe fe-info-circle text-primary"></i>
<div>
<h4>Dicta reprehenderit</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>4 hrs. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-footer">
<a href="#">Show all notifications</a>
</li>
</ul><!-- End Notification Dropdown Items -->
</li><!-- End Notification Nav -->
<li class="nav-item dropdown">
<a class="nav-link nav-icon" href="#" data-bs-toggle="dropdown">
<i class="fe fe-navigation"></i>
<span class="badge bg-success badge-number">3</span>
</a><!-- End Messages Icon -->
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow messages">
<li class="dropdown-header">
You have 3 new messages
<a href="#"><span class="badge rounded-pill bg-primary p-2 ms-2">View all</span></a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="message-item">
<a href="#">
<img src="assets/images/users/3.jpg" alt="" class="rounded-circle">
<div>
<h4>Maria Hudson</h4>
<p>Velit asperiores et ducimus soluta repudiandae labore officia est ut...</p>
<p>4 hrs. ago</p>
</div>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="message-item">
<a href="#">
<img src="assets/images/users/3.jpg" alt="" class="rounded-circle">
<div>
<h4>Anna Nelson</h4>
<p>Velit asperiores et ducimus soluta repudiandae labore officia est ut...</p>
<p>6 hrs. ago</p>
</div>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="message-item">
<a href="#">
<img src="assets/images/users/3.jpg" alt="" class="rounded-circle">
<div>
<h4>David Muldon</h4>
<p>Velit asperiores et ducimus soluta repudiandae labore officia est ut...</p>
<p>8 hrs. ago</p>
</div>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-footer">
<a href="#">Show all messages</a>
</li>
</ul><!-- End Messages Dropdown Items -->
</li><!-- End Messages Nav -->
<li class="nav-item dropdown pe-3">
......@@ -223,5 +67,25 @@
</ul>
</nav><!-- End Icons Navigation -->
<div class="search-bar">
<form class="search-form d-flex align-items-center" method="POST" action="#">
<input type="text" name="query" placeholder="Search" title="Enter search keyword">
<button type="submit" title="Search"><i class="fe fe-search"></i></button>
</form>
</div><!-- End Search Bar -->
<div class="d-flex align-items-center justify-content-between">
<i class="fe fe-align-justify toggle-sidebar-btn pr-10" (click)="toggleSidebar()"></i>
<a href="index.html" class="logo d-flex align-items-center justify-content-evenly pl-10">
<span class="d-none d-lg-block">نظام إدارة حالة المشاريع</span>
<img src="assets/images/logo/logo.ico" alt="">
</a>
</div><!-- End Logo -->
</header><!-- End Header -->
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HeaderComponent } from './header.component';
describe('HeaderComponent', () => {
let component: HeaderComponent;
let fixture: ComponentFixture<HeaderComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HeaderComponent]
})
.compileComponents();
fixture = TestBed.createComponent(HeaderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { Component, Input, input, OnInit } from '@angular/core';
import { Router, RouterLink } from '@angular/router';
@Component({
......@@ -10,10 +10,12 @@ import { Router, RouterLink } from '@angular/router';
styleUrl: './header.component.css'
})
export class HeaderComponent {
isSidebarVisible: boolean;
@Input() isToggled :Boolean;
constructor(private router: Router) { }
toggleSidebar() {
this.isSidebarVisible = !this.isSidebarVisible;
console.log(this.isToggled)
this.isToggled = !this.isToggled;
}
}
.mynav {
background-color: #0747a6!important;
color: #fff!important;
background-color: #0747a6!important;
color: #fff!important;
}
.content-hover:hover {
background-color: #033681!important;
background-color: #033681!important;
}
.nav-link, .navbar-brand {
color: #fff!important;
color: #fff!important;
}
/*--------------------------------------------------------------
# Main
--------------------------------------------------------------*/
#main {
margin-top: 60px;
padding: 20px 30px;
transition: all 0.3s;
}
@media (max-width: 1199px) {
#main {
padding: 20px;
}
}
/*--------------------------------------------------------------
# Page Title
--------------------------------------------------------------*/
.pagetitle {
margin-bottom: 10px;
}
.pagetitle h1 {
font-size: 24px;
margin-bottom: 0;
font-weight: 600;
color: #012970;
margin-top: 60px;
padding: 20px 30px;
transition: all 0.3s;
}
@media (max-width: 1199px) {
#main {
padding: 20px;
}
\ No newline at end of file
}
/*--------------------------------------------------------------
# Page Title
--------------------------------------------------------------*/
.pagetitle {
margin-bottom: 10px;
}
.pagetitle h1 {
font-size: 24px;
margin-bottom: 0;
font-weight: 600;
color: #012970;
}
<div>
<app-header></app-header>
<app-header [isToggled]="isToggled"></app-header>
<div id="main" class="main">
<router-outlet></router-outlet>
</div>
<app-sidebar></app-sidebar>
<app-sidebar [isToggled]="isToggled"></app-sidebar>
<app-footer></app-footer>
</div>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LayoutComponent } from './layout.component';
describe('LayoutComponent', () => {
let component: LayoutComponent;
let fixture: ComponentFixture<LayoutComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [LayoutComponent]
});
fixture = TestBed.createComponent(LayoutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
......@@ -8,9 +8,13 @@ import { Component } from '@angular/core';
})
export class LayoutComponent {
isToggled :Boolean= false ;
constructor( ) {
}
toggleSidebar(){
this.isToggled=!this.isToggled;
}
}
a {
text-decoration: none !important;
}
\ No newline at end of file
}
.sidebar {
position: fixed;
top: 60px;
right: 0;
bottom: 0;
width: 300px;
z-index: 996;
transition: all 0.3s;
padding: 20px;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: #aab7cf transparent;
box-shadow: 0px 0px 20px rgba(1, 41, 112, 0.1);
background-color: #fff;
}
@media (max-width: 1199px) {
.sidebar {
right: -300px;
}
}
.toggled {
right: -300px!important;
}
.sidebar::-webkit-scrollbar {
width: 5px;
height: 8px;
background-color: #fff;
}
.sidebar::-webkit-scrollbar-thumb {
background-color: #aab7cf;
}
@media (max-width: 1199px) {
.toggle-sidebar .sidebar {
right: 0;
}
}
@media (min-width: 1200px) {
.toggle-sidebar #main,
.toggle-sidebar #footer {
margin-right: 0;
}
.toggle-sidebar .sidebar {
right: -300px;
}
}
.sidebar-nav {
padding: 0;
margin: 0;
list-style: none;
}
.sidebar-nav li {
padding: 0;
margin: 0;
list-style: none;
}
.sidebar-nav .nav-item {
margin-bottom: 5px;
}
.sidebar-nav .nav-heading {
font-size: 11px;
text-transform: uppercase;
color: #899bbd;
font-weight: 600;
margin: 10px 0 5px 15px;
}
.sidebar-nav .nav-link {
display: flex;
align-items: center;
font-size: 15px;
font-weight: 600;
color: #4154f1;
transition: 0.3;
background: #f6f9ff;
padding: 10px 15px;
border-radius: 4px;
}
.sidebar-nav .nav-link i {
font-size: 16px;
margin-left: 10px;
color: #4154f1;
}
.sidebar-nav .nav-link.collapsed {
color: #012970;
background: #fff;
}
.sidebar-nav .nav-link.collapsed i {
color: #899bbd;
}
.sidebar-nav .nav-link:hover {
color: #4154f1;
background: #f6f9ff;
}
.sidebar-nav .nav-link:hover i {
color: #4154f1;
}
.sidebar-nav .nav-link .bi-chevron-down {
margin-right: 0;
transition: transform 0.2s ease-in-out;
}
.sidebar-nav .nav-link:not(.collapsed) .bi-chevron-down {
transform: rotate(180deg);
}
.sidebar-nav .nav-content {
padding: 5px 0 0 0;
margin: 0;
list-style: none;
}
.sidebar-nav .nav-content a {
display: flex;
align-items: center;
font-size: 14px;
font-weight: 600;
color: #012970;
transition: 0.3;
padding: 10px 0 10px 40px;
transition: 0.3s;
}
.sidebar-nav .nav-content a i {
font-size: 6px;
margin-left: 8px;
line-height: 0;
border-radius: 50%;
}
.sidebar-nav .nav-content a:hover,
.sidebar-nav .nav-content a.active {
color: #4154f1;
}
.sidebar-nav .nav-content a.active i {
background-color: #4154f1;
}
<!-- ======= Sidebar ======= -->
<aside dir="" id="sidebar" class="sidebar" [class.active]="false">
<aside dir="rtl" id="sidebar" class="sidebar" [class.toggled]="isToggled">
<ul class="sidebar-nav" id="sidebar-nav">
<li class="nav-item">
<a class="nav-link " href="index.html">
<i class="fe fe-grid"></i>
......@@ -23,7 +22,7 @@
</li>
<li>
<a href="components-alerts.html">
<i class="fe fe-circle"></i><span>تعديل المتابعة</span>
<i class="fe fe-circle"></i><span>اتمام عملية متابعة</span>
</a>
</li>
</ul>
......@@ -59,16 +58,17 @@
</ul>
</li><!-- End Components Nav -->
<li class="nav-heading">الجهات الطارحة</li>
<li class="nav-item">
<a class="nav-link collapsed " href="components-badges.html">
<i class="fe fe-file-text"></i><span>طلب تقرير</span>
<a routerLink="/customers" class="nav-link collapsed ">
<i class="fe fe-map"></i><span> استعراض الجهات الطارحة</span>
</a>
</li>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="components-badges.html">
<i class="fe fe-file-text"></i><span>تعديل تقرير</span>
<a routerlink="/customers/create" class="nav-link collapsed " >
<i class="fe fe-edit-2"></i><span>إضافة جهة طارحة</span>
</a>
</li>
</li>
<li class="nav-heading">إدارة المشاريع</li>
<li class="nav-item">
......@@ -109,8 +109,12 @@
</li>
</ul>
</li><!-- End Tables Nav -->
<li class="nav-heading">Pages</li>
<li class="nav-heading">متفرقات</li>
<li class="nav-item">
<a class="nav-link collapsed" routerlink="/ProjectFAQ">
<i class="bi bi-layout-text-window-reverse"></i><span>ملامح المشروع</span><i class="bi bi-chevron-down ms-auto"></i>
</a>
</li>
</ul>
</aside><!-- End Sidebar-->
\ No newline at end of file
import { Component } from '@angular/core';
import { Component, Input, input } from '@angular/core';
import { NavItem } from '../../componenets/nav-item/nav-item.component';
@Component({
selector: 'app-sidebar',
templateUrl: './sidebar.component.html',
styleUrl: './sidebar.component.css'
})
export class SidebarComponent {
items : NavItem[ ]=[
{
name: "الصفحة الرئيسية",
haschild:false,
child:[]
}
]
@Input() isToggled: Boolean;
}
{
"title":"إدارة حالة المشاريع"
}
\ No newline at end of file
{
"title": "fldfjgfkdgfdghfndm"
}
\ No newline at end of file
......@@ -12,7 +12,7 @@
<link href="assets/vendor/boxicons/css/boxicons.min.css" rel="stylesheet">
<link href="assets/vendor/remixicon/remixicon.css" rel="stylesheet">
</head>
<body >
<body dir="rtl">
<app-root ></app-root>
<script src="assets/js/jquery.min.js"></script>
......
......@@ -6,6 +6,51 @@
* License: https://bootstrapmade.com/license/
*/
/* src/styles.css */
#toast-container {
width: 100%;
top: 30px;
left: 50%;
transform: translateX(-50%);
position: fixed;
text-align: center;
pointer-events: none;
}
#toast-container > div {
display: inline-block;
margin: 0 auto;
background-color: #323232;
color: #fff;
border-radius: 8px;
box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.2);
padding: 16px;
font-family: 'Roboto', sans-serif;
min-width: 300px;
max-width: 500px;
pointer-events: auto;
}
#toast-container .toast-success {
background-color: #4caf50;
}
#toast-container .toast-error {
background-color: #f44336;
}
#toast-container .toast-info {
background-color: #2196f3;
}
#toast-container .toast-warning {
background-color: #ff9800;
}
#toast-container .toast-progress {
background-color: rgba(255, 255, 255, 0.7);
}
/*--------------------------------------------------------------
# General
--------------------------------------------------------------*/
......@@ -47,13 +92,18 @@ h6 {
--------------------------------------------------------------*/
#main {
margin-top: 60px;
padding: 20px 30px;
padding: 30px 20px;
transition: all 0.3s;
}
@media (min-width: 1200px) {
#main, #footer {
margin-right: 300px;
}
}
@media (max-width: 1199px) {
#main {
padding: 20px;
}
}
......@@ -355,412 +405,15 @@ h6 {
border-bottom: 2px solid #4154f1;
}
/*--------------------------------------------------------------
# Header
--------------------------------------------------------------*/
.logo {
line-height: 1;
}
@media (min-width: 1200px) {
.logo {
width: 280px;
}
}
.logo img {
max-height: 26px;
margin-right: 6px;
}
.logo span {
font-size: 26px;
font-weight: 700;
color: #012970;
font-family: "Nunito", sans-serif;
}
.header {
transition: all 0.5s;
z-index: 997;
height: 60px;
box-shadow: 0px 2px 20px rgba(1, 41, 112, 0.1);
background-color: #fff;
padding-left: 20px;
/* Toggle Sidebar Button */
/* Search Bar */
}
.header .toggle-sidebar-btn {
font-size: 32px;
padding-left: 10px;
cursor: pointer;
color: #012970;
}
.header .search-bar {
min-width: 360px;
padding: 0 20px;
}
@media (max-width: 1199px) {
.header .search-bar {
position: fixed;
top: 50px;
left: 0;
right: 0;
padding: 20px;
box-shadow: 0px 0px 15px 0px rgba(1, 41, 112, 0.1);
background: white;
z-index: 9999;
transition: 0.3s;
visibility: hidden;
opacity: 0;
}
.header .search-bar-show {
top: 60px;
visibility: visible;
opacity: 1;
}
}
.header .search-form {
width: 100%;
}
.header .search-form input {
border: 0;
font-size: 14px;
color: #012970;
border: 1px solid rgba(1, 41, 112, 0.2);
padding: 7px 38px 7px 8px;
border-radius: 3px;
transition: 0.3s;
width: 100%;
}
.header .search-form input:focus,
.header .search-form input:hover {
outline: none;
box-shadow: 0 0 10px 0 rgba(1, 41, 112, 0.15);
border: 1px solid rgba(1, 41, 112, 0.3);
}
.header .search-form button {
border: 0;
padding: 0;
margin-left: -30px;
background: none;
}
.header .search-form button i {
color: #012970;
}
/*--------------------------------------------------------------
# Header Nav
--------------------------------------------------------------*/
.header-nav ul {
list-style: none;
}
.header-nav>ul {
margin: 0;
padding: 0;
}
.header-nav .nav-icon {
font-size: 22px;
color: #012970;
margin-right: 25px;
position: relative;
}
.header-nav .nav-profile {
color: #012970;
}
.header-nav .nav-profile img {
max-height: 36px;
}
.header-nav .nav-profile span {
font-size: 14px;
font-weight: 600;
}
.header-nav .badge-number {
position: absolute;
inset: -2px -5px auto auto;
font-weight: normal;
font-size: 12px;
padding: 3px 6px;
}
.header-nav .notifications {
inset: 8px -15px auto auto !important;
}
.header-nav .notifications .notification-item {
display: flex;
align-items: center;
padding: 15px 10px;
transition: 0.3s;
}
.header-nav .notifications .notification-item i {
margin: 0 20px 0 10px;
font-size: 24px;
}
.header-nav .notifications .notification-item h4 {
font-size: 16px;
font-weight: 600;
margin-bottom: 5px;
}
.header-nav .notifications .notification-item p {
font-size: 13px;
margin-bottom: 3px;
color: #919191;
}
.header-nav .notifications .notification-item:hover {
background-color: #f6f9ff;
}
.header-nav .messages {
inset: 8px -15px auto auto !important;
}
.header-nav .messages .message-item {
padding: 15px 10px;
transition: 0.3s;
}
.header-nav .messages .message-item a {
display: flex;
}
.header-nav .messages .message-item img {
margin: 0 20px 0 10px;
max-height: 40px;
}
.header-nav .messages .message-item h4 {
font-size: 16px;
font-weight: 600;
margin-bottom: 5px;
color: #444444;
}
/* dfghj */
.header-nav .messages .message-item p {
font-size: 13px;
margin-bottom: 3px;
color: #919191;
}
.header-nav .messages .message-item:hover {
background-color: #f6f9ff;
}
.header-nav .profile {
min-width: 240px;
padding-bottom: 0;
top: 8px !important;
}
.header-nav .profile .dropdown-header h6 {
font-size: 18px;
margin-bottom: 0;
font-weight: 600;
color: #444444;
}
.header-nav .profile .dropdown-header span {
font-size: 14px;
}
.header-nav .profile .dropdown-item {
font-size: 14px;
padding: 10px 15px;
transition: 0.3s;
}
.header-nav .profile .dropdown-item i {
margin-right: 10px;
font-size: 18px;
line-height: 0;
}
.header-nav .profile .dropdown-item:hover {
background-color: #f6f9ff;
}
/* dfghjkkkkkkkkkkkkkkk */
/*--------------------------------------------------------------
# Sidebar
# Header
--------------------------------------------------------------*/
.sidebar {
position: fixed;
top: 60px;
left: 0;
bottom: 0;
width: 300px;
z-index: 996;
transition: all 0.3s;
padding: 20px;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: #aab7cf transparent;
box-shadow: 0px 0px 20px rgba(1, 41, 112, 0.1);
background-color: #fff;
}
@media (max-width: 1199px) {
.sidebar {
left: -300px;
}
}
.sidebar::-webkit-scrollbar {
width: 5px;
height: 8px;
background-color: #fff;
}
.sidebar::-webkit-scrollbar-thumb {
background-color: #aab7cf;
}
@media (min-width: 1200px) {
#main,
#footer {
margin-left: 300px;
}
}
@media (max-width: 1199px) {
.toggle-sidebar .sidebar {
left: 0;
}
}
@media (min-width: 1200px) {
.toggle-sidebar #main,
.toggle-sidebar #footer {
margin-left: 0;
}
.toggle-sidebar .sidebar {
left: -300px;
}
}
.sidebar-nav {
padding: 0;
margin: 0;
list-style: none;
}
.sidebar-nav li {
padding: 0;
margin: 0;
list-style: none;
}
.sidebar-nav .nav-item {
margin-bottom: 5px;
}
.sidebar-nav .nav-heading {
font-size: 11px;
text-transform: uppercase;
color: #899bbd;
font-weight: 600;
margin: 10px 0 5px 15px;
}
.sidebar-nav .nav-link {
display: flex;
align-items: center;
font-size: 15px;
font-weight: 600;
color: #4154f1;
transition: 0.3;
background: #f6f9ff;
padding: 10px 15px;
border-radius: 4px;
}
.sidebar-nav .nav-link i {
font-size: 16px;
margin-right: 10px;
color: #4154f1;
}
.sidebar-nav .nav-link.collapsed {
color: #012970;
background: #fff;
}
.sidebar-nav .nav-link.collapsed i {
color: #899bbd;
}
.sidebar-nav .nav-link:hover {
color: #4154f1;
background: #f6f9ff;
}
.sidebar-nav .nav-link:hover i {
color: #4154f1;
}
.sidebar-nav .nav-link .bi-chevron-down {
margin-right: 0;
transition: transform 0.2s ease-in-out;
}
.sidebar-nav .nav-link:not(.collapsed) .bi-chevron-down {
transform: rotate(180deg);
}
.sidebar-nav .nav-content {
padding: 5px 0 0 0;
margin: 0;
list-style: none;
}
.sidebar-nav .nav-content a {
display: flex;
align-items: center;
font-size: 14px;
font-weight: 600;
color: #012970;
transition: 0.3;
padding: 10px 0 10px 40px;
transition: 0.3s;
}
.sidebar-nav .nav-content a i {
font-size: 6px;
margin-right: 8px;
line-height: 0;
border-radius: 50%;
}
.sidebar-nav .nav-content a:hover,
.sidebar-nav .nav-content a.active {
color: #4154f1;
}
.sidebar-nav .nav-content a.active i {
background-color: #4154f1;
}
/*--------------------------------------------------------------
# Dashboard
--------------------------------------------------------------*/
......
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