first commit

This commit is contained in:
2024-04-19 12:53:45 +07:00
commit 71a3a661dc
1943 changed files with 246917 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { StatisticsComponent } from './statistics/statistics.component';
import { ChartistModule } from 'ng-chartist';
import { SocialComponent } from './social/social.component';
import { RouterModule } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NgChartsModule } from 'ng2-charts';
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
import { ChartsComponent } from './charts/charts.component';
import { CardModule } from '../partials/general/card/card.module';
import { MatchHeightModule } from '../partials/general/match-height/match-height.module';
@NgModule({
imports: [
CommonModule,
NgbModule,
ChartistModule,
CardModule,
NgChartsModule,
BreadcrumbModule,
MatchHeightModule,
RouterModule.forChild([
{
path: 'statistics',
component: StatisticsComponent
},
{
path: 'social',
component: SocialComponent
},
{
path: 'charts',
component: ChartsComponent
}
])
],
declarations: [StatisticsComponent, SocialComponent, ChartsComponent],
exports: [RouterModule]
})
export class AdvanceCardsModule {}

View File

@@ -0,0 +1,159 @@
:host ::ng-deep .areaChartLegend .ct-series-a .ct-line {
stroke:#1e9ff2;
}
:host ::ng-deep .areaChartLegend .ct-series-a .ct-line {
stroke: url(#gradient1);
stroke-width: 5px;
stroke-linecap: round;
}
:host ::ng-deep .areaChartLegend {
-webkit-filter: drop-shadow(0px 20px 11px rgba(0, 0, 0, 0.5)) !important;
filter: drop-shadow(0px 20px 11px rgba(0, 0, 0, 0.5));
}
:host ::ng-deep .areaChartLegend .ct-series-a .ct-area {
fill: #ffffff;
}
:host ::ng-deep .areaChartLegend .ct-series-a .ct-line {
stroke: #3da2ea;
}
:host ::ng-deep .earningchart .ct-series-a .ct-line {
stroke: #FF4961;
}
:host ::ng-deep .earningchart .ct-series-a .ct-point-circle {
stroke-width: 3px;
stroke: #FF4961;
fill: #ffffff;
}
:host ::ng-deep .barchart .ct-series-a .ct-bar {
stroke: #ff394f !important;
stroke-width: 7px !important;
}
:host ::ng-deep .Revenuechartist .ct-series-a .ct-line {
stroke: url(#gradient2);
stroke-linecap: round;
}
:host ::ng-deep .Revenuechartist {
filter: drop-shadow(0px 20px 11px rgba(252, 198, 198, 0.8)) !important;
}
:host ::ng-deep .Revenuechartist .ct-grid{
stroke-dasharray: 0px;
stroke: rgba(0, 0, 0, 0.4);
stroke-width: 0.6px;
}
:host ::ng-deep .Revenuechartist .ct-series-a .ct-line {
stroke: #ff4961;
}
:host ::ng-deep .Revenuechartist .ct-series-b .ct-line {
stroke: #c8c2c3;
stroke-dasharray: 8px 3px;
}
:host ::ng-deep .Revenuechartist .ct-label.ct-vertical.ct-start {
font-weight: 600;
color: #636161;
font-size: 12px;
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-a .ct-point-circle {
stroke-width: 5px;
stroke: #ffffff;
fill: #1e9ff2;
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-b .ct-point-circle {
stroke-width: 5px;
stroke: #ffffff;
fill: #58e0cd;
;
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-a .ct-area {
fill: #4105f9f5;
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-b .ct-area {
fill: #03f7b2fa;
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-b .ct-line {
stroke: #58e0cd;
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-a .ct-line {
stroke: #1e9ff2;
}
:host ::ng-deep .donut-chart2{
margin-bottom: -25px;
margin-top: -17px;
}
:host ::ng-deep .donut-chart2 .ct-series-a .ct-slice-donut {
stroke: #28d094;
stroke-width: 5.5px !important;
}
:host ::ng-deep .donut-chart2 .ct-series-b .ct-slice-donut {
stroke: #ff4961;
stroke-width: 5.5px !important;
}
:host ::ng-deep .donut-chart2 {
-webkit-filter: drop-shadow(0px 10px 11px rgba(187,187,187)) !important;
filter: drop-shadow(0px 10px 11px rgba(187,187,187));
height: 288px;
}
:host ::ng-deep .donut-chart2 .ct-label {
fill: #ff4b62;
color: rgba(0, 0, 0, 0.4);
font-size: 1.75rem;
line-height: 1;
}
:host ::ng-deep .donut-chart1 {
margin-bottom: -25px;
margin-top: -17px;
height: 288px;
}
:host ::ng-deep .donut-chart1 .ct-series-a .ct-slice-donut {
stroke: #ff7889;
stroke-width: 5.5px !important;
}
:host ::ng-deep .donut-chart1 .ct-series-b .ct-slice-donut {
stroke: #ffffff;
stroke-width: 5.5px !important;
}
:host ::ng-deep .donut-chart1 .ct-label {
fill: #ffffff;
color: rgba(0, 0, 0, 0.4);
font-size: 1.75rem;
line-height: 1;
}
:host ::ng-deep .donut .ct-done .ct-slice-donut {
stroke: #28d094;
stroke-width: 24px !important;
}
:host ::ng-deep .donut .ct-progress .ct-slice-donut {
stroke: #ff4558;
stroke-width: 16px !important;
}
:host ::ng-deep .donut .ct-outstanding .ct-slice-donut {
stroke: #ff7d4d;
stroke-width: 8px !important;
}
:host ::ng-deep .donut .ct-started .ct-slice-donut {
stroke: #666ECC;
stroke-width: 32px !important;
}
:host ::ng-deep .donut .ct-label {
text-anchor: middle;
font-size: 20px;
fill: #868e96;
}
:host ::ng-deep .dountchartheader{
margin-top: 10px;
}

View File

@@ -0,0 +1,194 @@
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
</div>
<div class="content-body">
<!-- Charts section start -->
<section id="charts-section">
<div class="row">
<div class="col-12 mt-3 mb-1">
<h4 class="text-uppercase">Charts</h4>
</div>
</div>
<div class="row" matchHeight="card">
<div class="col-xl-4 col-lg-12">
<div class="card text-white">
<div class="card-content">
<div class="position-relative">
<div class="chart-title position-absolute mt-2 ml-2 white">
</div>
<div class="earningchart">
<x-chartist *ngIf="earningchart" [data]="earningchart.data" [type]="earningchart.type" [options]="earningchart.options"
[responsiveOptions]="earningchart.responsiveOptions" [events]="earningchart.events">
</x-chartist>
</div>
<div class="chart-stats position-absolute position-bottom-0 position-right-0 mb-2 mr-3">
<a href="#" class="btn bg-danger mr-1 white">Statistics <i class="feather ft-bar-chart"></i></a> <span
class="text-muted">for the <a href="#" class="danger darken-2">last year.</a></span>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-8 col-lg-12">
<div class="card">
<div class="card-content">
<div class="row">
<div class="card-body">
<ul class="list-inline text-center">
<li class="mr-1">
<h6><i class="la la-circle danger"></i> <span>iOS</span></h6>
</li>
<li class="mr-1">
<h6><i class="la la-circle warning"></i> <span>Windows</span></h6>
</li>
<li class="mr-1">
<h6><i class="la la-circle success"></i> <span>Android</span></h6>
</li>
</ul>
<div class="areaChartLegend">
<x-chartist *ngIf="lineArea" [data]="lineArea.data" [type]="lineArea.type" [options]="lineArea.options"
[responsiveOptions]="lineArea.responsiveOptions" [events]="lineArea.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" matchHeight="card">
<div class="col-xl-4 col-lg-12">
<div class="card">
<div class="card-content">
<div class="earning-chart position-relative">
<div class="chart-title position-absolute mt-2 ml-2">
</div>
<p class="font-medium-2 text-muted text-center dountchartheader">Project Tasks</p>
<div class="donut">
<x-chartist class="pr_stats" *ngIf="DonutChart" [data]="DonutChart.data" [type]="DonutChart.type"
[options]="DonutChart.options" [responsiveOptions]="DonutChart.responsiveOptions"
[events]="DonutChart.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-12">
<m-card [options]="hitRateOptions" id="card">
<ng-container mCardHeaderTitle>
Hit Rate <span class="danger">-12%</span>
</ng-container>
<ng-container mCardBody>
<div id="donut-chart2" class="height-230 donut-chart2">
<x-chartist *ngIf="donutChart2" [data]="donutChart2.data" [type]="donutChart2.type" [options]="donutChart2.options"
[responsiveOptions]="donutChart2.responsiveOptions" [events]="donutChart2.events">
</x-chartist>
</div>
</ng-container>
</m-card>
</div>
<div class="col-xl-4 col-lg-12">
<m-card [options]="dealsOptions">
<ng-container mCardBody>
<h4 class="card-title white">Deals <span class="white">-55%</span>
<span class="float-right">
<span class="white">152</span><span class="red lighten-4">/200</span>
</span>
</h4>
<div id="donut-chart1" class="height-230 donut-chart1">
<x-chartist *ngIf="donutChart1" [data]="donutChart1.data" [type]="donutChart1.type" [options]="donutChart1.options"
[responsiveOptions]="donutChart1.responsiveOptions" [events]="donutChart1.events">
</x-chartist>
</div>
</ng-container>
</m-card>
</div>
</div>
<div class="row" matchHeight="card">
<div class="col-xl-4 col-lg-12">
<div class="card">
<div class="card-content">
<div class="card-body sales-growth-chart">
<div class="barchart">
<x-chartist *ngIf="barChart" [data]="barChart.data" [type]="barChart.type" [options]="barChart.options"
[responsiveOptions]="barChart.responsiveOptions" [events]="barChart.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-8 col-lg-12">
<div class="card">
<div class="card-content">
<div class="card-body">
<div class="Revenuechartist">
<x-chartist *ngIf="lineArea1" [data]="lineArea1.data" [type]="lineArea1.type" [options]="lineArea1.options"
[responsiveOptions]="lineArea1.responsiveOptions" [events]="lineArea1.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" matchHeight="card">
<div class="col-xl-12 col-lg-12">
<div class="card">
<div class="card-content ">
<div id="cost-revenue" class="ecommercesaleslineArea position-relative">
<x-chartist *ngIf="ecommercesaleslineArea" [data]="ecommercesaleslineArea.data" [type]="ecommercesaleslineArea.type"
[options]="ecommercesaleslineArea.options"
[responsiveOptions]="ecommercesaleslineArea.responsiveOptions"
[events]="ecommercesaleslineArea.events">
</x-chartist>
</div>
</div>
<div class="card-footer">
<div class="row mt-1">
<div class="col-3 text-center">
<h6 class="text-muted">Total Products</h6>
<h2 class="block font-weight-normal">18.6 k</h2>
<div class="progress progress-sm mt-1 mb-0 box-shadow">
<div class="progress-bar bg-gradient-x-info" role="progressbar" style="width: 70%"
aria-valuenow="70" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="col-3 text-center">
<h6 class="text-muted">Total Sales</h6>
<h2 class="block font-weight-normal">64.54 M</h2>
<div class="progress progress-sm mt-1 mb-0 box-shadow">
<div class="progress-bar bg-gradient-x-warning" role="progressbar" style="width: 60%"
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="col-3 text-center">
<h6 class="text-muted">Total Cost</h6>
<h2 class="block font-weight-normal">24.38 B</h2>
<div class="progress progress-sm mt-1 mb-0 box-shadow">
<div class="progress-bar bg-gradient-x-danger" role="progressbar" style="width: 40%"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="col-3 text-center">
<h6 class="text-muted">Total Revenue</h6>
<h2 class="block font-weight-normal">36.72 M</h2>
<div class="progress progress-sm mt-1 mb-0 box-shadow">
<div class="progress-bar bg-gradient-x-success" role="progressbar" style="width: 90%"
aria-valuenow="90" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- // Charts section end -->
</div>
</div>
</div>
<!-- END: Content-->

View File

@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ChartsComponent } from './charts.component';
describe('ChartsComponent', () => {
let component: ChartsComponent;
let fixture: ComponentFixture<ChartsComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ChartsComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ChartsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,472 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import * as Chartist from 'chartist';
import { ChartEvent, ChartType } from 'ng-chartist';
import { ChartApiService } from '../../../_services/chart.api';
export interface Chart {
type: ChartType;
data: Chartist.IChartistData;
options?: any;
responsiveOptions?: any;
events?: ChartEvent;
}
@Component({
selector: 'app-charts',
templateUrl: './charts.component.html',
styleUrls: ['./charts.component.css']
})
export class ChartsComponent implements OnInit {
public breadcrumb: any;
salesData: any;
ChartistData: any;
lineArea: any;
earningchart: any;
DonutChart: any;
barChart: any;
lineArea1: any;
ecommercesaleslineArea: any;
donutChart2: any;
donutChart1: any;
constructor(private chartApiservice: ChartApiService) { }
hitRateOptions = {
bodyClass: ['bg-hexagons', 'pt-0'],
headerClass: ['bg-hexagons'],
cardClass: ['pull-up'],
close: false,
expand: false,
minimize: false,
reload: true
};
dealsOptions = {
bodyClass: ['bg-hexagons-danger'],
cardClass: ['pull-up'],
contentClass: ['bg-gradient-directional-danger']
};
getlineArea() {
const Chartdata = this.ChartistData;
this.lineArea = {
type: 'Line',
data: Chartdata['lineArea'],
options: {
lineSmooth: Chartist.Interpolation.simple({
divisor: 1.8
}),
fullwidth: true,
height: '320px',
low: 0,
showArea: true,
fullWidth: true,
showPoint: false,
axisX: {
showGrid: false
},
axisY: {
low: 0,
offset: 16,
scaleMinSpace: 40,
labelInterpolationFnc: function (value) {
return value + 'K';
}
}
},
responsiveOptions: [
[
'screen and (max-width: 640px) and (min-width: 200px)',
{
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}
],
[
'screen and (max-width: 380px)',
{
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}
]
],
events: {
created(data: any): void {
const defs = data.svg.elem('defs');
defs
.elem('linearGradient', {
id: 'gradient1',
x1: 1,
y1: 1,
x2: 1,
y2: 1
})
.elem('stop', {
offset: 0,
'stop-color': 'rgba(22, 141, 238, 1)'
})
.parent()
.elem('stop', {
offset: 1,
'stop-color': 'rgba(98, 188, 270, 11)'
});
}
}
};
this.DonutChart = {
type: 'Pie',
data: Chartdata['donutDashboard'],
options: {
width: '100%',
height: '280px',
donut: true,
startAngle: 0,
labelInterpolationFnc: function (value) {
const total = Chartdata['donutDashboard'].series.reduce(function (
prev,
series
) {
return prev + series.value;
},
0);
return total + '%';
}
},
events: {
draw(data: any): void {
if (data.type === 'label') {
if (data.index === 0) {
data.element.attr({
dx: data.element.root().width() / 2,
dy: data.element.root().height() / 2
});
} else {
data.element.remove();
}
}
}
}
};
this.barChart = {
type: 'Bar',
data: Chartdata['Bar'],
options: {
fullwidth: true,
height: '320px',
seriesBarDistance: 21,
chartPadding: {
top: 0
},
axisX: {
showLable: true,
showGrid: false,
offset: 60,
labelInterpolationFnc: function (value) {
return value.slice(0, 3);
}
},
axisY: {
scaleMinSpace: 40
}
}
};
this.ecommercesaleslineArea = {
type: 'Line',
data: Chartdata['lineArea2'],
options: {
height: '300px',
low: 0,
showArea: true,
fullWidth: true,
onlyInteger: true,
axisX: {
showGrid: false
},
axisY: {
low: 0,
scaleMinSpace: 40,
showGrid: false
}
},
responsiveOptions: [
[
'screen and (max-width: 640px) and (min-width: 381px)',
{
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}
],
[
'screen and (max-width: 380px)',
{
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}
]
],
events: {
draw(data: any): void {
const circleRadius = 6;
if (data.type === 'point') {
const circle = new Chartist.Svg('circle', {
cx: data.x,
cy: data.y,
r: circleRadius,
class: 'ct-point-circle'
});
data.element.replace(circle);
}
}
}
};
}
getChartData() {
const SaleschartData = this.salesData;
this.earningchart = {
type: 'Line',
data: SaleschartData['earningchart'],
options: {
chartPadding: 0,
height: '440px',
low: 0,
showArea: true,
fullWidth: true,
onlyInteger: true,
axisX: {
showGrid: false,
showLabel: false,
offset: -1
},
axisY: {
scaleMinSpace: 40,
showGrid: false,
showLabel: false,
offset: -2
}
},
responsiveOptions: [
[
'screen and (max-width: 640px) and (min-width: 381px)',
{
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}
],
[
'screen and (max-width: 380px)',
{
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}
]
],
events: {
created(data: any): void {
const defs = data.svg.elem('defs');
defs
.elem('linearGradient', {
id: 'gradient1',
x1: 0,
y1: 0,
x2: 1,
y2: 0
})
.elem('stop', {
offset: 0,
'stop-color': 'rgb(255,73,97)'
})
.parent()
.elem('stop', {
offset: 1,
'stop-color': 'rgb(255,73,97)'
});
},
draw(data: any): void {
const circleRadius = 6;
if (data.type === 'point') {
const circle = new Chartist.Svg('circle', {
cx: data.x,
cy: data.y,
r: circleRadius,
class: 'ct-point-circle'
});
data.element.replace(circle);
}
}
}
};
this.lineArea1 = {
type: 'Line',
data: SaleschartData['lineArea'],
options: {
lineSmooth: Chartist.Interpolation.simple({
divisor: 2.8
}),
fullWidth: true,
height: '320px',
showArea: false,
showPoint: false,
axisX: {
showGrid: false,
showLabel: true,
offset: 32
},
axisY: {
showGrid: true,
showLabel: true,
scaleMinSpace: 28,
offset: 44
}
},
events: {
created(data: any): void {
const defs = data.svg.elem('defs');
defs
.elem('linearGradient', {
id: 'gradient2',
x1: 0,
y1: 0,
x2: 1,
y2: 0
})
.elem('stop', {
offset: 0,
'stop-color': 'rgb(255,73,97)'
})
.parent()
.elem('stop', {
offset: 1,
'stop-color': 'rgb(255,73,97)'
});
},
draw(data: any): void {
const circleRadius = 4;
if (data.type === 'point') {
const circle = new Chartist.Svg('circle', {
cx: data.x,
cy: data.y,
r: circleRadius,
class: 'ct-point-circle'
});
data.element.replace(circle);
} else if (data.type === 'label') {
// adjust label position for rotation
const dX = data.width / 2 + (26 - data.width);
data.element.attr({ x: data.element.attr('x') - dX });
}
}
}
};
this.donutChart2 = {
type: 'Pie',
data: SaleschartData['donut1'],
options: {
chartPadding: 0,
fullwidth: true,
height: '273px',
donut: true,
showLabel: true,
startAngle: 0,
labelInterpolationFnc: function (value) {
const total = 82;
return total + '%';
}
},
events: {
draw(data: any): void {
if (data.type === 'label') {
if (data.index === 0) {
data.element.attr({
dx: data.element.root().width() / 2,
dy: data.element.root().height() / 2
});
} else {
data.element.remove();
}
}
}
}
};
this.donutChart1 = {
type: 'Pie',
data: SaleschartData['donut2'],
options: {
chartPadding: 0,
fullwidth: true,
height: '273px',
donut: true,
showLabel: true,
labelInterpolationFnc: function (value) {
const total = 76;
return total + '%';
}
},
events: {
draw(data: any): void {
if (data.type === 'label') {
if (data.index === 0) {
data.element.attr({
dx: data.element.root().width() / 2,
dy: data.element.root().height() / 2
});
} else {
data.element.remove();
}
}
}
}
};
}
ngOnInit() {
this.breadcrumb = {
mainlabel: 'Advance Charts Cards',
links: [
{
name: 'Home',
isLink: true,
link: '/dashboard/sales'
},
{
name: 'Advance Cards',
isLink: true,
link: '#'
},
{
name: 'Charts',
isLink: false,
link: '#'
}
]
};
this.chartApiservice.getSalesData().subscribe(Response => {
this.salesData = Response;
this.getChartData();
});
this.chartApiservice.getEcommerceData().subscribe(Response => {
this.ChartistData = Response;
this.getlineArea();
});
}
}

View File

@@ -0,0 +1,206 @@
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
</div>
<div class="content-body">
<!-- Social cards section start -->
<section id="social-cards">
<div class="row">
<div class="col-12 mt-3 mb-1">
<h4 class="text-uppercase">Social Cards</h4>
<p>User's social profile cards with followers - following numbers and follow button.</p>
</div>
</div>
<div class="row mt-2">
<div class="col-xl-4 col-md-6 col-12">
<div class="card profile-card-with-cover">
<div class="card-content">
<div class="card-img-top img-fluid bg-cover height-200"
style="background: url('../../../../../assets/images/backgrounds/fb.jpg') 0 30%;"></div>
<div class="card-profile-image">
<img src="../../../../../assets/images/portrait/small/avatar-s-4.png"
class="rounded-circle img-border box-shadow-1" alt="Card image">
</div>
<div class="profile-card-with-cover-content text-center">
<div class="profile-details mt-2">
<h4 class="card-title">Linda Holland</h4>
<ul class="list-inline clearfix mt-2">
<li class="mr-3">
<h2 class="block">3.5K</h2> Likes
</li>
<li class="mr-3">
<h2 class="block">2845</h2> Followers
</li>
<li>
<h2 class="block">645</h2> Following
</li>
</ul>
</div>
<div class="card-body">
<a [routerLink]="" class="btn btn-social btn-min-width mr-1 mb-1 btn-facebook"><i
class="la la-facebook"></i> Follow</a>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-md-6 col-12">
<div class="card profile-card-with-cover">
<div class="card-content">
<div class="card-img-top img-fluid bg-cover height-200"
style="background: url('../../../../../assets/images/backgrounds/in.jpg') 0 40%;"></div>
<div class="card-profile-image">
<img src="../../../../../assets/images/portrait/small/avatar-s-9.png"
class="rounded-circle img-border box-shadow-1" alt="Card image">
</div>
<div class="profile-card-with-cover-content text-center">
<div class="profile-details mt-2">
<h4 class="card-title">Philip Garrett</h4>
<ul class="list-inline clearfix mt-2">
<li class="mr-3">
<h2 class="block">500+</h2> Connections
</li>
<li class="mr-3">
<h2 class="block">485</h2> Posts
</li>
<li>
<h2 class="block">35</h2> Following
</li>
</ul>
</div>
<div class="card-body">
<a [routerLink]="" class="btn btn-social btn-min-width mr-1 mb-1 btn-linkedin"><span
class="la la-linkedin"></span> Follow</a>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-md-6 col-12">
<div class="card profile-card-with-cover">
<div class="card-content">
<div class="card-img-top img-fluid bg-cover height-200"
style="background: url('../../../../../assets/images/backgrounds/tw.jpg') 0 30%;"></div>
<div class="card-profile-image">
<img src="../../../../../assets/images/portrait/small/avatar-s-8.png"
class="rounded-circle img-border box-shadow-1" alt="Card image">
</div>
<div class="profile-card-with-cover-content text-center">
<div class="profile-details mt-2">
<h4 class="card-title">Christine Wood</h4>
<ul class="list-inline clearfix mt-2">
<li class="mr-3">
<h2 class="block">1.6K</h2> Likes
</li>
<li class="mr-3">
<h2 class="block">264</h2> Followers
</li>
<li>
<h2 class="block">85</h2> Following
</li>
</ul>
</div>
<div class="card-body">
<a [routerLink]="" class="btn btn-social btn-min-width mr-1 mb-1 btn-twitter white"><span
class="la la-twitter"></span> Follow</a>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-4 col-md-12">
<div class="card bg-twitter white">
<div class="card-content p-2">
<div class="card-body">
<div class="text-center mb-1">
<i class="la la-twitter font-large-3"></i>
</div>
<div class="tweet-slider carousel slide text-center" data-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<p>Congratulations to Rob Jones in accounting for winning our <span class="yellow">#NFL</span>
football pool!</p>
</div>
<div class="carousel-item">
<p>Contests are a great thing to partner on. Partnerships immediately <span
class="yellow">#DOUBLE</span> the reach.</p>
</div>
<div class="carousel-item">
<p>Puns, humor, and quotes are great content on <span class="yellow">#Twitter</span>. Find some
related to your business.</p>
</div>
<div class="carousel-item">
<p>Are there <span class="yellow">#common-sense</span> facts related to your business? Combine
them with a great photo.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-4 col-md-12">
<div class="card bg-facebook white">
<div class="card-content p-2">
<div class="card-body">
<div class="text-center mb-1">
<i class="la la-facebook font-large-3"></i>
</div>
<div class="fb-post-slider carousel slide text-center" data-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<p>Congratulations to Rob Jones in accounting for winning our #NFL football pool!</p>
</div>
<div class="carousel-item">
<p>Contests are a great thing to partner on. Partnerships immediately #DOUBLE the reach.</p>
</div>
<div class="carousel-item">
<p>Puns, humor, and quotes are great content on #Twitter. Find some related to your business.
</p>
</div>
<div class="carousel-item">
<p>Are there #common-sense facts related to your business? Combine them with a great photo.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-4 col-md-12">
<div class="card bg-linkedin white">
<div class="card-content p-2">
<div class="card-body">
<div class="text-center mb-1">
<i class="la la-linkedin font-large-3"></i>
</div>
<div class="linkedin-post-slider carousel slide text-center" data-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<p>Congratulations to Rob Jones in accounting for winning our #NFL football pool!</p>
</div>
<div class="carousel-item">
<p>Contests are a great thing to partner on. Partnerships immediately #DOUBLE the reach.</p>
</div>
<div class="carousel-item">
<p>Puns, humor, and quotes are great content on #Twitter. Find some related to your business.
</p>
</div>
<div class="carousel-item">
<p>Are there #common-sense facts related to your business? Combine them with a great photo.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- // Social cards section end -->
</div>
</div>
</div>

View File

@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SocialComponent } from './social.component';
describe('SocialComponent', () => {
let component: SocialComponent;
let fixture: ComponentFixture<SocialComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [SocialComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SocialComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,35 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-social',
templateUrl: './social.component.html',
styleUrls: ['./social.component.css']
})
export class SocialComponent implements OnInit {
public breadcrumb: any;
constructor() {}
ngOnInit() {
this.breadcrumb = {
mainlabel: 'Advance Social Cards',
links: [
{
name: 'Home',
isLink: true,
link: '/dashboard/sales'
},
{
name: 'Advance Cards',
isLink: true,
link: '#'
},
{
name: 'Social',
isLink: false,
link: '#'
}
]
};
}
}

View File

@@ -0,0 +1,140 @@
:host ::ng-deep .Likes .ct-series-a .ct-point {
stroke: #28d094;
}
:host ::ng-deep .Likes .ct-line {
fill: none;
stroke-width: 2px;
}
:host ::ng-deep .Likes .ct-point{
stroke-width: 0px;
}
:host ::ng-deep .Likes .ct-series-a .ct-line {
stroke: #28d094;
}
:host ::ng-deep .Likes .ct-series-a .ct-area {
fill: #28d094;
}
:host ::ng-deep .Comments .ct-series-a .ct-point {
stroke: #FF9149;
}
:host ::ng-deep .Comments .ct-line {
fill: none;
stroke-width: 2px;
}
:host ::ng-deep .Comments .ct-point{
stroke-width: 0px;
}
:host ::ng-deep .Comments .ct-series-a .ct-line {
stroke: #FF9149;
}
:host ::ng-deep .Comments .ct-series-a .ct-area {
fill: #FF9149;
}
:host ::ng-deep .Views .ct-series-a .ct-point {
stroke: #FF4961;
}
:host ::ng-deep .Views .ct-line {
fill: none;
stroke-width: 2px;
}
:host ::ng-deep .Views .ct-point{
stroke-width: 0px;
}
:host ::ng-deep .Views .ct-series-a .ct-line {
stroke: #FF4961;
}
:host ::ng-deep .Views .ct-series-a .ct-area {
fill: #FF4961;
}
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-point{
stroke: #ff9149;
}
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-line{
stroke: #ff9149;
}
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-area{
fill: #ff9149;
fill-opacity: 1;
}
:host ::ng-deep .sp-line-total-cost .ct-point{
stroke-width: 0px;
}
:host ::ng-deep .sp-line-total-cost svg {
margin-left: 13px;
}
:host ::ng-deep .sp-line-total-sales .ct-series-a .ct-point{
stroke: #28d094;
}
:host ::ng-deep .sp-line-total-sales .ct-series-a .ct-line{
stroke: #28d094;
}
:host ::ng-deep .sp-line-total-sales .ct-series-a .ct-area{
fill: #28d094;
fill-opacity: 1;
}
:host ::ng-deep .sp-line-total-sales .ct-point{
stroke-width: 0px;
}
:host ::ng-deep .sp-line-total-sales svg {
margin-left: 13px;
}
:host ::ng-deep .sp-line-total-revenue .ct-series-a .ct-point{
stroke: #ff4961;
}
:host ::ng-deep .sp-line-total-revenue .ct-series-a .ct-line{
stroke: #ff4961;
}
:host ::ng-deep .sp-line-total-revenue .ct-series-a .ct-area{
fill: #ff4961;
fill-opacity: 1;
}
:host ::ng-deep .sp-line-total-revenue .ct-point{
stroke-width: 0px;
}
:host ::ng-deep .sp-line-total-revenue svg {
margin-left: 13px;
}
:host ::ng-deep .ct-bar {
fill: none;
stroke-width: 2px;
}
:host ::ng-deep .sp-bar-total-cost .ct-series-a .ct-bar{
stroke: #ff9148;
}
:host ::ng-deep .sp-bar-total-sales .ct-series-a .ct-bar{
stroke: #28d094;
}
:host ::ng-deep .sp-bar-total-revenue .ct-series-a .ct-bar{
stroke: #ff4961;
}
:host ::ng-deep .sp-bar-total-cost {
margin-bottom: -90px;
}
:host ::ng-deep .sp-bar-total-sales{
margin-bottom: -90px;
}
:host ::ng-deep .sp-bar-total-revenue{
margin-bottom: -90px;
}
:host ::ng-deep .feedbacks .ct-series-a .ct-slice-donut {
stroke: #28d094;
stroke-width: 10px !important;
}
:host ::ng-deep .Subscribers .ct-series-a .ct-slice-donut {
stroke: #ff9149;
stroke-width: 10px !important;
}
:host ::ng-deep .Users .ct-series-a .ct-slice-donut {
stroke: #ff4961;
stroke-width: 10px !important;
}
:host ::ng-deep .ct-series-b .ct-slice-donut {
stroke: #eeeeee;
stroke-width: 12px !important;
}
:host ::ng-deep .text-muted {
position: absolute;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { StatisticsComponent } from './statistics.component';
describe('StatisticsComponent', () => {
let component: StatisticsComponent;
let fixture: ComponentFixture<StatisticsComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ StatisticsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StatisticsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,224 @@
import { Component, OnInit } from '@angular/core';
import * as Chartist from 'chartist';
import { ChartEvent, ChartType } from 'ng-chartist';
import { ChartApiService } from '../../../_services/chart.api';
export interface Chart {
type: ChartType;
data: Chartist.IChartistData;
options?: any;
responsiveOptions?: any;
events?: ChartEvent;
}
@Component({
selector: 'app-statistics',
templateUrl: './statistics.component.html',
styleUrls: ['./statistics.component.css']
})
export class StatisticsComponent implements OnInit {
Data: any;
public breadcrumb: any;
feedbacksdonutChart: any;
subscribersdonutChart: any;
usersdonutChart: any;
lineArea: any;
commentslineArea: any;
viewslineArea: any;
sparklineArea: any;
barChart1: any;
barChart: any;
constructor(private chartApiservice: ChartApiService) {}
getlineArea() {
const ChartData = this.Data;
this.feedbacksdonutChart = {
type: 'Pie',
data: ChartData['feedbacksdonutChart'],
options: {
showLabel: false,
chartPadding: 0,
fullwidth: true,
height: '200px',
donut: true,
startAngle: 0
}
};
this.subscribersdonutChart = {
type: 'Pie',
data: ChartData['subscribersdonutChart'],
options: {
chartPadding: 0,
fullwidth: true,
height: '200px',
donut: true,
showLabel: false,
startAngle: 0
}
};
this.usersdonutChart = {
type: 'Pie',
data: ChartData['usersdonutChart'],
options: {
showLabel: false,
chartPadding: 0,
fullwidth: true,
height: '200px',
donut: true,
startAngle: 0
}
};
this.lineArea = {
type: 'Line',
data: ChartData['lineArea'],
options: {
// low: 650,
fullwidth: true,
height: '80px',
showArea: true,
axisX: {
showGrid: false,
showLabel: false
},
axisY: {
showGrid: false,
showLabel: false
}
}
};
this.commentslineArea = {
type: 'Line',
data: ChartData['commentslineArea'],
options: {
// low: 650,
fullwidth: true,
height: '80px',
showArea: true,
axisX: {
showGrid: false,
showLabel: false
},
axisY: {
showGrid: false,
showLabel: false
}
}
};
this.viewslineArea = {
type: 'Line',
data: ChartData['viewslineArea'],
options: {
// low: 650,
fullwidth: true,
height: '80px',
showArea: true,
axisX: {
showGrid: false,
showLabel: false
},
axisY: {
showGrid: false,
showLabel: false
}
}
};
this.sparklineArea = {
type: 'Line',
data: ChartData['sparklineArea'],
options: {
chartPadding: 0,
showArea: true,
showLine: false,
showPoint: false,
lineSmooth: Chartist.Interpolation.none(),
axisX: {
showGrid: false,
offset: -1
},
axisY: {
showGrid: false,
offset: -1
}
}
};
this.barChart = {
type: 'Bar',
data: ChartData['Bar'],
options: {
fullwidth: true,
axisX: {
showGrid: false,
showLabel: false,
offset: 100
},
axisY: {
showGrid: false,
showLabel: false
}
}
};
this.barChart1 = {
type: 'Bar',
data: ChartData['Bar1'],
options: {
fullwidth: true,
axisX: {
showGrid: false,
showLabel: false,
offset: 100
},
axisY: {
showGrid: false,
showLabel: false
}
}
};
this.lineArea = {
type: 'Line',
data: ChartData['lineArea'],
options: {
// low: 650,
fullwidth: true,
height: '75px',
showArea: true,
axisX: {
showGrid: false,
showLabel: false
},
axisY: {
showGrid: false,
showLabel: false
}
}
};
}
ngOnInit() {
this.breadcrumb = {
mainlabel: 'Advance Statistics Cards',
links: [
{
name: 'Home',
isLink: true,
link: '/dashboard/sales'
},
{
name: 'Advance Cards',
isLink: true,
link: '#'
},
{
name: 'Statistics Cards',
isLink: false,
link: '#'
}
]
};
this.chartApiservice.getStatisticsData().subscribe(Response => {
this.Data = Response;
this.getlineArea();
});
}
}

View File

@@ -0,0 +1,88 @@
import { ChangeDetectorRef, Component, forwardRef, Input } from '@angular/core';
import {
getSeconds,
getMinutes,
getHours,
getDate,
getMonth,
getYear,
setSeconds,
setMinutes,
setHours,
setDate,
setMonth,
setYear
} from 'date-fns';
import { NgbDateStruct, NgbTimeStruct } from '@ng-bootstrap/ng-bootstrap';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
export const DATE_TIME_PICKER_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DateTimePickerComponent),
multi: true
};
@Component({
selector: 'app-mwl-demo-utils-date-time-picker',
templateUrl: 'dateTimeComponent.component.html',
styleUrls: ['dateTimePickerComponent.component.css'],
providers: [DATE_TIME_PICKER_CONTROL_VALUE_ACCESSOR]
})
export class DateTimePickerComponent implements ControlValueAccessor {
@Input() placeholder: string;
date: Date;
dateStruct: NgbDateStruct;
timeStruct: NgbTimeStruct;
datePicker: any;
private onChangeCallback: (date: Date) => void = () => { };
constructor(private cdr: ChangeDetectorRef) { }
writeValue(date: Date): void {
this.date = date;
this.dateStruct = {
day: getDate(date),
month: getMonth(date) + 1,
year: getYear(date)
};
this.timeStruct = {
second: getSeconds(date),
minute: getMinutes(date),
hour: getHours(date)
};
this.cdr.detectChanges();
}
registerOnChange(fn: any): void {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any): void { }
updateDate(): void {
const newDate: Date = setYear(
setMonth(
setDate(this.date, this.dateStruct.day),
this.dateStruct.month - 1
),
this.dateStruct.year
);
this.onChangeCallback(newDate);
}
updateTime(): void {
const newDate: Date = setHours(
setMinutes(
setSeconds(this.date, this.timeStruct.second),
this.timeStruct.minute
),
this.timeStruct.hour
);
this.onChangeCallback(newDate);
}
}

View File

@@ -0,0 +1,57 @@
:host ::ng-deep .card-block .h4 {
font-size: 1.32rem;
font-family: bold;
}
:host ::ng-deep .content-sub-header {
margin-top: 0;
margin-bottom: 3rem;
}
:host ::ng-deep .mb-3,
.my-3 {
margin-bottom: 2rem !important;
}
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}
:host ::ng-deep .ngb-datepicker-month-view {
display: block;
background-color: red !important;
}
@media screen and (max-width: 767px) {
.bottom_space {
padding-bottom: 1rem !important;
text-align: unset !important;
padding-left: 0px !important;
}
}
@media screen and (max-width: 767px) {
.pull-right {
float: left !important;
}
}
.close {
outline: none;
}
::ng-deep ngb-modal-backdrop {
z-index: 1050 !important;
}
:host ::ng-deep .ngb-dp-header {
background-color: var(--light) !important;
}
:host ::ng-deep .ngb-dp-weekdays {
background-color: var(--light);
}
:host ::ng-deep .ngb-dp-month-name {
background-color: var(--light);
}

View File

@@ -0,0 +1,144 @@
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
</div>
<div class="content-body">
<section id="calendar">
<div class="row">
<div class="col-12" *blockUI="'default'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadDefault($event)">
<ng-container mCardHeaderTitle>
Add Event
</ng-container>
<ng-container mCardBody>
<p class="content-sub-header">This is the most advanced example having various features. This
example lists all the events on the calendar with Add new event functionality.</p>
<ng-template #modalContent let-close="close">
<div class="modal-header">
<h5 class="modal-title">{{ modalData?.action }}</h5>
<button type="button" class="close" (click)="close()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-body">
<div class="form-group">
<label>Event Title:</label>
<input type="text" name="event-title" class="form-control" [(ngModel)]="modalData?.event.title"
(keyup)="refresh.next()">
</div>
<div class="row">
<div class="col-md-6 col-12">
<div class="form-group">
<label>Primary Color:</label>
<input type="color" name="primary-color" [(ngModel)]="modalData?.event.color.primary"
(change)="refresh.next()">
</div>
</div>
<div class="col-md-6 col-12">
<div class="form-group">
<label>Secondary Color:</label>
<input type="color" name="secondary-color" [(ngModel)]="modalData?.event.color.secondary"
(change)="refresh.next()">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-12">
<div class="form-group">
<label>Starts At:</label>
<!-- <input type="date" name="starts-at" [(ngModel)]="modalData?.event.start" (ngModelChange)="refresh.next()" placeholder="Not set"> -->
<!-- <input type="date" class="form-control" id="date" > -->
<app-mwl-demo-utils-date-time-picker name="starts-at" [(ngModel)]="modalData?.event.start" (ngModelChange)="refresh.next()" placeholder="Not set">
</app-mwl-demo-utils-date-time-picker>
</div>
</div>
<div class="col-md-6 col-12">
<div class="form-group">
<label>Ends At:</label>
<app-mwl-demo-utils-date-time-picker name="ends-at" [(ngModel)]="modalData?.event.end" (ngModelChange)="refresh.next()" placeholder="Not set">
</app-mwl-demo-utils-date-time-picker>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" (click)="close()">OK</button>
</div>
</ng-template>
<div class="card">
<div class="card-block">
<div class=" row d-flex flex-wrap justify-content-md-between mb-3 no-gutters">
<div class="col-md-4 bottom_space">
<div class="btn-group">
<div class="btn btn-primary" mwlCalendarPreviousView [view]="view" [(viewDate)]="viewDate"
(viewDateChange)="activeDayIsOpen = false">
Previous
</div>
<div class="btn btn-outline-secondary" mwlCalendarToday [(viewDate)]="viewDate">
Today
</div>
<div class="btn btn-primary" mwlCalendarNextView [view]="view" [(viewDate)]="viewDate"
(viewDateChange)="activeDayIsOpen = false">
Next
</div>
</div>
</div>
<div class="col-md-4 text-center align-self-center bottom_space">
<h3 class="text-uppercase mb-0">{{ viewDate | calendarDate:(view + 'ViewTitle'):'en' }}</h3>
</div>
<div class="col-md-4 text-right bottom_space">
<div class="btn-group">
<div class="btn btn-primary" (click)="view = CalendarView.Month"
[class.active]="view === CalendarView.Month">
Month
</div>
<div class="btn btn-primary" (click)="view = CalendarView.Week"
[class.active]="view === CalendarView.Week">
Week
</div>
<div class="btn btn-primary" (click)="view = CalendarView.Day"
[class.active]="view === CalendarView.Day">
Day
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<button class="btn btn-raised btn-primary pull-right" (click)="addEvent()">
Add Event
</button>
</div>
</div>
<div [ngSwitch]="view">
<mwl-calendar-month-view *ngSwitchCase="'month'" [viewDate]="viewDate" [events]="events"
[refresh]="refresh" [activeDayIsOpen]="activeDayIsOpen" (dayClicked)="dayClicked($event.day)"
(eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-month-view>
<mwl-calendar-week-view *ngSwitchCase="'week'" [viewDate]="viewDate" [events]="events"
[refresh]="refresh" (eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-week-view>
<mwl-calendar-day-view *ngSwitchCase="'day'" [viewDate]="viewDate" [events]="events"
[refresh]="refresh" (eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-day-view>
</div>
</div>
</div>
</ng-container>
</m-card>
</div>
</div>
</section>
</div>
</div>
</div>

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { AddeventComponent } from './addevent.component';
describe('AddeventComponent', () => {
let component: AddeventComponent;
let fixture: ComponentFixture<AddeventComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ AddeventComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AddeventComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,233 @@
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { ViewChild, TemplateRef } from '@angular/core';
import { Subject } from 'rxjs';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { startOfDay, endOfDay, subDays, addDays, endOfMonth, startOfMonth, isSameDay, isSameMonth, addHours } from 'date-fns';
import { CalendarEventTimesChangedEvent, CalendarView, CalendarEvent, CalendarEventAction } from 'angular-calendar';
import { NgbDateStruct, NgbTimeStruct } from '@ng-bootstrap/ng-bootstrap';
import { BlockUI, NgBlockUI } from 'ng-block-ui';
const colors: any = {
red: {
primary: '#ad2121',
secondary: '#FAE3E3'
},
blue: {
primary: '#1e90ff',
secondary: '#D1E8FF'
},
yellow: {
primary: '#e3bc08',
secondary: '#FDF1BA'
}
};
@Component({
selector: 'app-adddeleteevent',
templateUrl: './addevent.component.html',
styleUrls: ['./addevent.component.css']
})
export class AddeventComponent implements OnInit {
@BlockUI('default') blockUIDefault: NgBlockUI;
date: Date;
options = {
close: true,
expand: true,
minimize: true,
reload: true
};
@ViewChild('modalContent') modalContent: TemplateRef<any>;
view: CalendarView = CalendarView.Month;
CalendarView = CalendarView;
newEvent: CalendarEvent;
viewDate: Date = new Date();
activeDayIsOpen = true;
modalData: {action: string;
event: CalendarEvent;
};
actions: CalendarEventAction[] = [
{
label: '<i class="fa fa-fw fa-pencil"></i>',
onClick: ({ event }: { event: CalendarEvent }): void => {
this.handleEvent('Edited', event);
}
},
{
label: '<i class="fa fa-fw fa-times"></i>',
onClick: ({ event }: { event: CalendarEvent }): void => {
this.events = this.events.filter(iEvent => iEvent !== event);
this.handleEvent('Deleted', event);
}
}
];
refresh: Subject<any> = new Subject();
events: CalendarEvent[] = [
{
start: subDays(startOfDay(new Date()), 0),
end: addDays(new Date(), 1),
title: 'Business Lunch',
color: colors.red,
actions: this.actions,
allDay: true,
resizable: {
beforeStart: true,
afterEnd: true
},
draggable: true
},
{
start: subDays(endOfMonth(new Date()), 2),
end: addDays(endOfMonth(new Date()), 1),
title: 'A long event that spans 2 months',
color: colors.blue,
allDay: true
},
{
start: subDays(startOfMonth(new Date()), 1),
end: addDays(startOfMonth(new Date()), 0),
title: 'Meeting',
color: colors.yellow,
actions: this.actions,
resizable: {
beforeStart: true,
afterEnd: true
},
draggable: true
}
];
dateStruct: NgbDateStruct;
timeStruct: NgbTimeStruct;
public breadcrumb: any;
datePicker: any;
private onChangeCallback: (date: Date) => void = () => { };
/**
*
* @param NgbModal modal
*/
constructor(private modal: NgbModal) { }
/**
* onInit
*/
ngOnInit() {
this.breadcrumb = {
'mainlabel': 'Calendar AddEvent',
'links': [
{
'name': 'Home',
'isLink': true,
'link': '/dashboard/sales'
},
{
'name': 'Apps',
'isLink': true,
'link': '#'
},
{
'name': 'Calendars',
'isLink': true,
'link': '#'
},
{
'name': 'AddEvent',
'isLink': false,
'link': '#'
}
]
};
}
/**
* selacted date
*
* @param date Clicked date in datepicker
* @param events Events of selected date
*/
dayClicked({ date, events }: { date: Date; events: CalendarEvent[] }): void {
if (isSameMonth(date, this.viewDate)) {
this.viewDate = date;
if (
(isSameDay(this.viewDate, date) && this.activeDayIsOpen === true) ||
events.length === 0
) {
this.activeDayIsOpen = false;
} else {
this.activeDayIsOpen = true;
}
}
}
/**
*
* @param event Event of the time change
* @param newStart Event start date
* @param newEnd Event end date
*/
eventTimesChanged({
event,
newStart,
newEnd
}: CalendarEventTimesChangedEvent): void {
event.start = newStart;
event.end = newEnd;
this.handleEvent('Dropped or resized', event);
this.refresh.next({});
}
/**
*
* @param action Event action
* @param event calendar event
*/
handleEvent(action: string, event: CalendarEvent): void {
this.modalData = { event, action };
this.modal.open(this.modalContent, { size: 'lg' });
}
/**
* Add new event in modal
*/
addEvent(): void {
this.newEvent = {
title: 'New event',
start: startOfDay(new Date()),
end: endOfDay(new Date()),
color: colors.red,
draggable: true,
resizable: {
beforeStart: true,
afterEnd: true
},
actions: this.actions,
};
this.events.push(this.newEvent);
// this.refresh.next();
this.handleEvent('Add new event', this.newEvent);
this.refresh.next({});
}
/**
* Reload card
*/
reloadDefault () {
this.blockUIDefault.start('Loading..');
setTimeout(() => {
this.blockUIDefault.stop();
}, 2500);
}
}

View File

@@ -0,0 +1,25 @@
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input
readonly
class="form-control"
[placeholder]="placeholder"
name="date"
[(ngModel)]="dateStruct"
(ngModelChange)="updateDate()"
ngbDatepicker
#datePicker="ngbDatepicker">
<div class="input-group-append">
<div class="input-group-text" (click)="datePicker.toggle()" >
<i class="fa fa-calendar"></i>
</div>
</div>
</div>
</div>
</form>
<ngb-timepicker
[(ngModel)]="timeStruct"
(ngModelChange)="updateTime()"
[meridian]="true">
</ngb-timepicker>

View File

@@ -0,0 +1,143 @@
.form-group {
width: 100%;
}
:host ::ng-deep .btn-light:not(:disabled):not(.disabled):active {
color: unset !important;
background-color: unset !important;
border-color: #d3d9df !important;
}
:host ::ng-deep .btn-light:hover:not(.disabled):active {
background-color: #e2e6ea !important;
border-color: #dae0e5 !important;
}
:host ::ng-deep .btn-light {
color: unset !important;
background-color: unset !important;
border-color: unset !important;
}
:host ::ng-deep .bg-primary {
background-color: #007bff !important;
}
:host ::ng-deep .text-white {
color: #fff !important;
}
:host ::ng-deep .custom-day {
text-align: center;
padding: .185rem .25rem;
display: inline-block;
height: 2rem;
width: 2rem;
}
:host ::ng-deep .custom-day:active {
color: white !important;
}
div.bg-light {
background-color: #f8f9fa !important;
}
:host ::ng-deep .hidden {
display: block !important;
}
.ngb-dp-weekday {
color: #17a2b8;
}
.ngb-dp-week-number,
.ngb-dp-weekday {
line-height: 2rem;
text-align: center;
font-style: italic;
}
.ngb-datepicker-month-view {
pointer-events: auto;
}
.small {
font-size: 80%;
font-weight: 400;
}
.ngb-dp-day {
cursor: pointer !important;
}
.ngb-dp-month {
pointer-events: none;
}
.btn-light:hover {
color: #212529 !important;
background-color: #e2e6ea !important;
border-color: #dae0e5 !important;
}
.ngb-datepicker-month-view {
pointer-events: auto;
}
.ngb-dp-header {
border-bottom: 0;
border-radius: .25rem .25rem 0 0;
padding-top: .25rem;
}
.ngb-dp-day,
.ngb-dp-week-number,
.ngb-dp-weekday {
width: 2rem;
height: 2rem;
}
.custom-day {
text-align: center;
padding: 0.185rem 0.25rem;
display: inline-block;
height: 2rem;
width: 2rem;
}
.custom-day.focused {
background-color: #e6e6e6;
}
.custom-day.range,
.custom-day:hover {
background-color: rgb(2, 117, 216);
color: white;
}
.custom-day.faded {
background-color: rgba(2, 117, 216, 0.5);
}
:host ::ng-deep.visually-hidden {
position: absolute !important;
width: 1px !important;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
:host ::ng-deep .ngb-dp-header {
background-color: var(--light) !important;
}
:host ::ng-deep .ngb-dp-weekdays {
background-color: var(--light);
}
:host ::ng-deep .ngb-dp-month-name {
background-color: var(--light);
}

View File

@@ -0,0 +1,55 @@
:host ::ng-deep .h3 {
margin: 0 0 10px;
}
:host ::ng-deep .pre {
background-color: #f5f5f5;
padding: 15px;
}
:host ::ng-deep.card-header .heading-elements, .card-header .heading-elements-toggle {
background-color: inherit;
position: absolute;
top: 60px;
right: 77px;
}
:host ::ng-deep .cal-month-view .cal-open-day-events {
padding: 0px !important;
color: white;
background-color: #555;
-webkit-box-shadow: inset 0 0 15px 0 rgba(0, 0, 0, 0.5);
box-shadow: inset 0 0 15px 0 rgba(0, 0, 0, 0.5);
}
:host ::ng-deep .card-header .heading-elements {
background-color: inherit;
position: absolute;
top: 19px;
right: 19px;
}
.fc-toolbar .fc-left {
float: left;
}
.fc-toolbar .fc-right {
float: right;
}
.fc-toolbar.fc-header-toolbar {
margin-bottom: 3em;
}
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}
@media screen and (max-width: 767px) {
.bottom_space {
padding-bottom: 1rem !important;
text-align: unset !important;
padding-left: 0px !important;
}
}
::ng-deep ngb-modal-backdrop {
z-index: 1050 !important;
}

View File

@@ -0,0 +1,183 @@
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
</div>
<div class="content-body">
<section id="basic-examples">
<div class="row">
<div class="col-12" *blockUI="'basicViews'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadBasicViews($event)">
<ng-container mCardHeaderTitle>
Basic Views
</ng-container>
<ng-container mCardBody>
<p>This is the most basic example having navigation buttons as well as month, week and day views. In
this example you have the option to change your view to a basicWeek or basicDay view. In the Basic
Week or Basic Day View events are listed all together.</p>
<br>
<ng-template #modalContent let-close="close">
<div class="modal-header">
<h5 class="modal-title">Event action occurred</h5>
<button type="button" class="close" (click)="close()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div>
Action:
<pre>{{ modalData?.action }}</pre>
</div>
<div>
Event:
<pre>{{ modalData?.event | json }}</pre>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" (click)="close()">
OK
</button>
</div>
</ng-template>
<div class="row">
<div class="col-md-6 bottom_space">
<h3>{{ BviewDate | calendarDate:(Bview + 'ViewTitle'):'en' }}</h3>
</div>
<div class="col-md-6 text-right bottom_space">
<div class="btn-group">
<div class="btn btn-primary" mwlCalendarPreviousView [view]="Bview" [(viewDate)]="BviewDate"
(viewDateChange)="activeDayIsOpen = false">
Previous
</div>
<div class="btn btn-outline-secondary" mwlCalendarToday [(viewDate)]="BviewDate">
Today
</div>
<div class="btn btn-primary" mwlCalendarNextView [view]="Bview" [(viewDate)]="BviewDate"
(viewDateChange)="activeDayIsOpen = false">
Next
</div>
</div>
</div>
</div>
<br />
<div [ngSwitch]="Bview">
<mwl-calendar-month-view *ngSwitchCase="CalendarView.Month" [viewDate]="BviewDate" [refresh]="refresh"
[activeDayIsOpen]="activeDayIsOpen" (eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-month-view>
<mwl-calendar-week-view *ngSwitchCase="CalendarView.Week" [viewDate]="BviewDate" [refresh]="refresh"
(eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-week-view>
<mwl-calendar-day-view *ngSwitchCase="CalendarView.Day" [viewDate]="BviewDate" [refresh]="refresh"
(eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-day-view>
</div>
<br /><br /><br />
</ng-container>
</m-card>
</div>
</div>
</section>
</div>
<div class="content-body">
<section id="basic-examples">
<div class="row">
<div class="col-12" *blockUI="'basicViews'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadBasicViews($event)">
<ng-container mCardHeaderTitle>
Basic Views
</ng-container>
<ng-container mCardBody>
<p>This is the most basic example having navigation buttons as well as month, week and day views. In
this example you have the option to change your view to a basicWeek or basicDay view. In the Basic
Week or Basic Day View events are listed all together.</p>
<br>
<ng-template #modalContent let-close="close">
<div class="modal-header">
<h5 class="modal-title">Event action occurred</h5>
<button type="button" class="close" (click)="close()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div>
Action:
<pre>{{ modalData?.action }}</pre>
</div>
<div>
Event:
<pre>{{ modalData?.event | json }}</pre>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" (click)="close()">
OK
</button>
</div>
</ng-template>
<div class="row">
<div class="col-md-4 bottom_space">
<div class="btn-group">
<div class="btn btn-primary" mwlCalendarPreviousView [view]="Bview" [(viewDate)]="BviewDate"
(viewDateChange)="activeDayIsOpen = false">
Previous
</div>
<div class="btn btn-outline-secondary" mwlCalendarToday [(viewDate)]="BviewDate">
Today
</div>
<div class="btn btn-primary" mwlCalendarNextView [view]="Bview" [(viewDate)]="BviewDate"
(viewDateChange)="activeDayIsOpen = false">
Next
</div>
</div>
</div>
<div class="col-md-4 text-center bottom_space">
<h3>{{ BviewDate | calendarDate:(Bview + 'ViewTitle'):'en' }}</h3>
</div>
<div class="col-md-4 text-right bottom_space">
<div class="btn-group">
<div class="btn btn-primary" (click)="Bview = CalendarView.Month"
[class.active]="Bview === CalendarView.Month">
Month
</div>
<div class="btn btn-primary" (click)="Bview = CalendarView.Week"
[class.active]="Bview === CalendarView.Week">
Week
</div>
<div class="btn btn-primary" (click)="Bview = CalendarView.Day"
[class.active]="Bview === CalendarView.Day">
Day
</div>
</div>
</div>
</div>
<br />
<div [ngSwitch]="Bview">
<mwl-calendar-month-view *ngSwitchCase="CalendarView.Month" [viewDate]="BviewDate" [refresh]="refresh"
[activeDayIsOpen]="activeDayIsOpen" (eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-month-view>
<mwl-calendar-week-view *ngSwitchCase="CalendarView.Week" [viewDate]="BviewDate" [refresh]="refresh"
(eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-week-view>
<mwl-calendar-day-view *ngSwitchCase="CalendarView.Day" [viewDate]="BviewDate" [refresh]="refresh"
(eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-day-view>
</div>
<br /><br /><br />
</ng-container>
</m-card>
</div>
</div>
</section>
</div>
</div>
</div>

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { BasicComponent } from './basic.component';
describe('BasicComponent', () => {
let component: BasicComponent;
let fixture: ComponentFixture<BasicComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ BasicComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BasicComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,89 @@
import { Component, OnInit } from '@angular/core';
import { ViewChild, TemplateRef } from '@angular/core';
import { Subject } from 'rxjs';
import { CalendarView } from 'angular-calendar';
import { BlockUI, NgBlockUI } from 'ng-block-ui';
@Component({
selector: 'app-basic',
templateUrl: './basic.component.html',
styleUrls: ['./basic.component.css']
})
export class BasicComponent implements OnInit {
@BlockUI('default') blockUIDefault: NgBlockUI;
@BlockUI('basicViews') blockUIBasicViews: NgBlockUI;
public breadcrumb: any;
options = {
close: true,
expand: true,
minimize: true,
reload: true
};
@ViewChild('modalContent', { static: true }) modalContent: TemplateRef<any>;
view: CalendarView = CalendarView.Month;
Bview: CalendarView = CalendarView.Month;
CalendarView = CalendarView;
viewDate: Date = new Date();
BviewDate: Date = new Date();
modalData: {action: string};
refresh: Subject<any> = new Subject();
activeDayIsOpen: boolean;
/**
* onInit
*/
ngOnInit() {
this.breadcrumb = {
mainlabel: 'Calendar Basic',
links: [
{
name: 'Home',
isLink: true,
link: '/dashboard/sales'
},
{
name: 'Apps',
isLink: true,
link: '#'
},
{
name: 'Calendars',
isLink: true,
link: '#'
},
{
name: 'Basic',
isLink: false,
link: '#'
}
]
};
}
/**
* realod card
*/
reloadDefault() {
this.blockUIDefault.start('Loading..');
setTimeout(() => {
this.blockUIDefault.stop();
}, 2500);
}
/**
* Realod card
*/
reloadBasicViews() {
this.blockUIBasicViews.start('Loading..');
setTimeout(() => {
this.blockUIBasicViews.stop();
}, 2500);
}
}

View File

@@ -0,0 +1,13 @@
import { CalenderModule } from './calender.module';
describe('CalenderModule', () => {
let calenderModule: CalenderModule;
beforeEach(() => {
calenderModule = new CalenderModule();
});
it('should create an instance', () => {
expect(calenderModule).toBeTruthy();
});
});

View File

@@ -0,0 +1,61 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { CalendarModule, DateAdapter } from 'angular-calendar';
import { adapterFactory } from 'angular-calendar/date-adapters/date-fns';
import { RouterModule } from '@angular/router';
import { FlatpickrModule } from 'angularx-flatpickr';
import { BasicComponent } from './basic/basic.component';
import { EventsComponent } from './events/events.component';
import { AddeventComponent } from './addevent/addevent.component';
import { CardModule } from '../../partials/general/card/card.module';
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
import { BlockUIModule } from 'ng-block-ui';
import { BlockTemplateComponent } from 'src/app/_layout/blockui/block-template.component';
import { DateTimePickerComponent } from './addevent/DateTimePickerComponent';
import {
NgbModalModule,
NgbDatepickerModule,
NgbTimepickerModule
} from '@ng-bootstrap/ng-bootstrap';
@NgModule({
imports: [
CommonModule,
CardModule,
BreadcrumbModule,
FormsModule,
FlatpickrModule.forRoot(),
BlockUIModule.forRoot({
template: BlockTemplateComponent
}),
NgbModalModule,
NgbDatepickerModule,
NgbTimepickerModule,
CalendarModule.forRoot({
provide: DateAdapter,
useFactory: adapterFactory
}),
RouterModule.forChild([
{
path: 'basic',
component: BasicComponent
},
{
path: 'events',
component: EventsComponent
},
{
path: 'addevent',
component: AddeventComponent
}
])
],
declarations: [
BasicComponent,
EventsComponent,
AddeventComponent,
DateTimePickerComponent
]
})
export class CalenderModule {}

View File

@@ -0,0 +1,27 @@
:host ::ng-deep .cal-month-view .cal-open-day-events {
padding: 0px !important;
color: white;
background-color: #555;
-webkit-box-shadow: inset 0 0 15px 0 rgba(0, 0, 0, 0.5);
box-shadow: inset 0 0 15px 0 rgba(0, 0, 0, 0.5);
}
:host ::ng-deep .title {
width: 140px;
}
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}
@media screen and (max-width: 767px) {
.bottom_space {
padding-bottom: 1rem !important;
text-align: unset !important;
padding-left: 0px !important;
}
}
::ng-deep ngb-modal-backdrop {
z-index: 1050 !important;
}

View File

@@ -0,0 +1,181 @@
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
</div>
<div class="content-body">
<section id="basic-examples">
<div class="row">
<div class="col-12">
<m-card [options]="options" (reloadFunction)="reloadEvents()">
<ng-container mCardHeaderTitle>
Events
</ng-container>
<ng-container mCardBody>
<p>This is the most basic example having navigation button to navigate next and previous months and
today button. This example lists all the events on the calendar with Add new event functionality. </p>
<br>
<ng-template #modalContent let-close="close">
<div class="modal-header">
<h5 class="modal-title">Event action occurred</h5>
<button type="button" class="close" (click)="close()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div>
Action:
<pre>{{ modalData?.action }}</pre>
</div>
<div>
Event:
<pre>{{ modalData?.event | json }}</pre>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" (click)="close()">
OK
</button>
</div>
</ng-template>
<div class="row">
<div class="col-md-4 bottom_space">
<div class="btn-group">
<div class="btn btn-primary" mwlCalendarPreviousView [view]="view" [(viewDate)]="viewDate"
(viewDateChange)="activeDayIsOpen = false">
Previous
</div>
<div class="btn btn-outline-secondary" mwlCalendarToday [(viewDate)]="viewDate">
Today
</div>
<div class="btn btn-primary" mwlCalendarNextView [view]="view" [(viewDate)]="viewDate"
(viewDateChange)="activeDayIsOpen = false">
Next
</div>
</div>
</div>
<div class="col-md-4 text-center bottom_space">
<h3>{{ viewDate | calendarDate:(view + 'ViewTitle'):'en' }}</h3>
</div>
<div class="col-md-4 text-right bottom_space">
<div class="btn-group">
<div class="btn btn-primary" (click)="view = CalendarView.Month"
[class.active]="view === CalendarView.Month">
Month
</div>
<div class="btn btn-primary" (click)="view = CalendarView.Week"
[class.active]="view === CalendarView.Week">
Week
</div>
<div class="btn btn-primary" (click)="view = CalendarView.Day"
[class.active]="view === CalendarView.Day">
Day
</div>
</div>
</div>
</div>
<br />
<div [ngSwitch]="view">
<mwl-calendar-month-view *ngSwitchCase="CalendarView.Month" [viewDate]="viewDate" [events]="events"
[refresh]="refresh" [activeDayIsOpen]="activeDayIsOpen" (dayClicked)="dayClicked($event.day)"
(eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-month-view>
<mwl-calendar-week-view *ngSwitchCase="CalendarView.Week" [viewDate]="viewDate" [events]="events"
[refresh]="refresh" (eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-week-view>
<mwl-calendar-day-view *ngSwitchCase="CalendarView.Day" [viewDate]="viewDate" [events]="events"
[refresh]="refresh" (eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-day-view>
</div>
<br /><br /><br />
<h3>
Edit events
<button class="btn btn-primary pull-right" (click)="addEvent()">
Add new
</button>
<div class="clearfix"></div>
</h3>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>Title</th>
<th>Primary color</th>
<th>Secondary color</th>
<th>Starts at</th>
<th>Ends at</th>
<th>Remove</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let event of events; let index = index">
<td>
<input type="text" name="event-title" class="form-control title" [(ngModel)]="event.title"
>
</td>
<td>
<input type="color" [(ngModel)]="event.color.primary" (change)="refresh.next()" />
</td>
<td>
<input type="color" [(ngModel)]="event.color.secondary" (change)="refresh.next()" />
</td>
<td>
<input class="form-control" type="text" mwlFlatpickr [(ngModel)]="event.start"
(ngModelChange)="refresh.next()" [altInput]="true" [convertModelValue]="true"
[enableTime]="true" dateFormat="Y-m-dTH:i" altFormat="F j, Y H:i" placeholder="Not set" />
</td>
<td>
<input class="form-control" type="text" mwlFlatpickr [(ngModel)]="event.end"
(ngModelChange)="refresh.next()" [convertModelValue]="true"
[enableTime]="true" dateFormat="Y-m-dTH:i" altFormat="F j, Y H:i" placeholder="Not set" />
</td>
<td>
<button class="btn btn-danger" (click)="events.splice(index, 1); refresh.next()">
Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
<br /><br /><br />
<ng-template #modalContent let-close="close">
<div class="modal-header">
<h5 class="modal-title">Event action occurred</h5>
<button type="button" class="close" (click)="close()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div>
Action:
<pre>{{ modalData?.action }}</pre>
</div>
<div>
Event:
<pre>{{ modalData?.event | json }}</pre>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" (click)="close()">
OK
</button>
</div>
</ng-template>
</ng-container>
</m-card>
</div>
</div>
</section>
</div>
</div>
</div>

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { EventsComponent } from './events.component';
describe('EventsComponent', () => {
let component: EventsComponent;
let fixture: ComponentFixture<EventsComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ EventsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EventsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,214 @@
import { Component, OnInit } from '@angular/core';
import { ViewChild, TemplateRef } from '@angular/core';
import { Subject } from 'rxjs';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
startOfDay,
endOfDay,
subDays,
addDays,
endOfMonth,
isSameDay,
isSameMonth,
addHours
} from 'date-fns';
import {
CalendarEventTimesChangedEvent,
CalendarView,
CalendarEvent,
CalendarEventAction
} from 'angular-calendar';
import { BlockUI, NgBlockUI } from 'ng-block-ui';
const colors: any = {
red: {
primary: '#ad2121',
secondary: '#FAE3E3'
},
blue: {
primary: '#1e90ff',
secondary: '#D1E8FF'
},
yellow: {
primary: '#e3bc08',
secondary: '#FDF1BA'
}
};
@Component({
selector: 'app-events',
templateUrl: './events.component.html',
styleUrls: ['./events.component.css']
})
export class EventsComponent implements OnInit {
public breadcrumb: any;
options = {
close: true,
expand: true,
minimize: true,
reload: true
};
@BlockUI('events') blockUIEvents: NgBlockUI;
@ViewChild('modalContent', { static: true }) modalContent: TemplateRef<any>;
view: CalendarView = CalendarView.Month;
CalendarView = CalendarView;
viewDate: Date = new Date();
activeDayIsOpen = true;
modalData: {
action: string;
event: CalendarEvent;
};
actions: CalendarEventAction[] = [
{
label: '<i class="fa fa-fw fa-pencil"></i>',
onClick: ({ event }: { event: CalendarEvent }): void => {
this.handleEvent('Edited', event);
}
},
{
label: '<i class="fa fa-fw fa-times"></i>',
onClick: ({ event }: { event: CalendarEvent }): void => {
this.events = this.events.filter(iEvent => iEvent !== event);
this.handleEvent('Deleted', event);
}
}
];
refresh: Subject<any> = new Subject();
events: CalendarEvent[] = [
{
start: subDays(startOfDay(new Date()), 1),
end: addDays(new Date(), 1),
title: 'A 3 day event',
color: colors.red,
actions: this.actions,
allDay: true,
resizable: {
beforeStart: true,
afterEnd: true
},
draggable: true
},
{
start: startOfDay(new Date()),
title: 'An event with no end date',
color: colors.yellow,
actions: this.actions
},
{
start: subDays(endOfMonth(new Date()), 3),
end: addDays(endOfMonth(new Date()), 3),
title: 'A long event that spans 2 months',
color: colors.blue,
allDay: true
},
{
start: addHours(startOfDay(new Date()), 2),
end: new Date(),
title: 'A draggable and resizable event',
color: colors.yellow,
actions: this.actions,
resizable: {
beforeStart: true,
afterEnd: true
},
draggable: true
}
];
ngOnInit() {
this.breadcrumb = {
mainlabel: 'Full Calendar Events',
links: [
{
name: 'Home',
isLink: true,
link: '/dashboard/sales'
},
{
name: 'Apps',
isLink: true,
link: '#'
},
{
name: 'Calendars',
isLink: true,
link: '#'
},
{
name: 'Events',
isLink: false,
link: '#'
}
]
};
}
constructor(private modal: NgbModal) {}
dayClicked({ date, events }: { date: Date; events: CalendarEvent[] }): void {
if (isSameMonth(date, this.viewDate)) {
this.viewDate = date;
if (
(isSameDay(this.viewDate, date) && this.activeDayIsOpen === true) ||
events.length === 0
) {
this.activeDayIsOpen = false;
} else {
this.activeDayIsOpen = true;
}
}
}
eventTimesChanged({
event,
newStart,
newEnd
}: CalendarEventTimesChangedEvent): void {
event.start = newStart;
event.end = newEnd;
this.handleEvent('Dropped or resized', event);
this.refresh.next({});
}
handleEvent(action: string, event: CalendarEvent): void {
this.modalData = { event, action };
this.modal.open(this.modalContent, { size: 'lg' });
}
addEvent(): void {
this.events.push({
title: 'New event',
start: startOfDay(new Date()),
end: endOfDay(new Date()),
color: colors.red,
draggable: true,
resizable: {
beforeStart: true,
afterEnd: true
}
});
this.refresh.next({});
}
deleteEvent(eventToDelete: CalendarEvent) {
this.events = this.events.filter(event => event !== eventToDelete);
}
setView(view: CalendarView) {
this.view = view;
}
closeOpenMonthViewDay() {
this.activeDayIsOpen = false;
}
reloadEvents() {
this.blockUIEvents.start('Loading..');
setTimeout(() => {
this.blockUIEvents.stop();
}, 2500);
}
}

View File

@@ -0,0 +1,56 @@
:host ::ng-deep .content-right {
width: calc(100% - 300px) !important;
}
:host ::ng-deep .mx-75 {
margin-left: .75rem!important;
margin-right: .75rem!important;
}
:host ::ng-deep .py-75 {
padding-bottom: .75rem!important;
padding-top: .75rem!important;
}
:host ::ng-deep .px-1 {
padding-left: 1rem!important;
padding-right: 1rem!important;
}
:host ::ng-deep .mr-50, .mx-50 {
margin-right: .5rem!important;
margin-left: .5rem!important;
}
:host ::ng-deep .mb-50, .my-50 {
margin-bottom: .5rem!important;
}
:host ::ng-deep .dropdown-menu
{
transform: translate3d(-131px, 18px, 0px) !important;
}
:host ::ng-deep .chat-sidebar .chat-sidebar-list-wrapper {
overflow-y: scroll;
}
:host ::ng-deep .sidebar-fixed {
overflow: hidden !important;
width: 300px;
}
:host ::ng-deep .app-content {
overflow-y: hidden !important;
}
:host ::ng-deep .pb-25, .py-25 {
padding-bottom: .25rem!important;
}
:host ::ng-deep .ml-25, .mx-25 {
margin-left: .25rem!important;
}
:host ::ng-deep .ps--active-y > .ps__rail-y {
display: none;
}
@media(max-width:767px) {
:host ::ng-deep .content-right {
width: calc(100% - 0px) !important;
}
}
:host ::ng-deep .d-inline-block {
display: inline !important;
}

View File

@@ -0,0 +1,254 @@
<div class="app-content content" >
<div class="sidebar-left" id="sidebar-left">
<div class="sidebar"><!-- app chat user profile left sidebar start -->
<div class="chat-user-profile" id="user-profile" >
<header class="chat-user-profile-header text-center border-bottom">
<span class="chat-profile-close" (click)="showProfile($event)" >
<i class="ficon feather ft-x" ></i>
</span>
<div class="my-2">
<img *ngIf="loggedInUser.photoURL" src="{{loggedInUser.photoURL}}" class="round mb-1" alt="user_avatar" height="100" width="100" >
<img *ngIf="!loggedInUser.photoURL" src="../../../../assets/images/portrait/small/avatar-s-19.png" class="round mb-1" alt="user_avatar"
alt="avatar" height="100" width="100" >
<!-- <img src="../../../assets/images/portrait/small/avatar-s-16.png" class="round mb-1" alt="user_avatar"
height="100" width="100" > -->
<h5 class="mb-0">{{loggedInUser.displayName}}</h5>
<span>Designer</span>
</div>
</header>
<div class="chat-user-profile-content">
<div class="chat-user-profile-scroll" fxFlex="auto" [perfectScrollbar]="config">
<h6 class="text-uppercase mb-1">ABOUT</h6>
<p class="mb-2">It is a long established fact that a reader will be distracted by the readable content .</p>
<h6>PERSONAL INFORAMTION</h6>
<ul class="list-unstyled mb-2">
<li class="mb-25">email@gmail.com</li>
<li>+1(789) 950 -7654</li>
</ul>
<h6 class="text-uppercase mb-1">CHANNELS</h6>
<ul class="list-unstyled mb-2">
<li><a href=""># Devlopers</a></li>
<li><a href=""># Designers</a></li>
</ul>
<h6 class="text-uppercase mb-1">SETTINGS</h6>
<ul class="list-unstyled">
<li class="mb-50 "><a href="" class="d-flex align-items-center"><i class="ficon feather ft-tag mr-50"></i>
Add
Tag</a></li>
<li class="mb-50 "><a href="" class="d-flex align-items-center"><i class="ficon feather ft-star mr-50"></i>
Important Contact</a>
</li>
<li class="mb-50 "><a href="" class="d-flex align-items-center"><i
class="ficon feather ft-image mr-50"></i>
Shared
Documents</a></li>
<li class="mb-50 "><a href="" class="d-flex align-items-center"><i
class="ficon feather ft-trash-2 mr-50"></i>
Deleted
Documents</a></li>
<li><a href="" class="d-flex align-items-center"><i class="ficon feather ft-x-circle mr-50"></i> Blocked
Contact</a></li>
</ul>
</div>
</div>
</div>
<!-- app chat user profile left sidebar ends -->
<!-- app chat sidebar start -->
<div class="chat-sidebar card" id="sidebar-card">
<span class="chat-sidebar-close" (click) = "Sidebar($event)">
<i class="ficon feather ft-x" ></i>
</span>
<div class="chat-sidebar-search">
<div class="d-flex align-items-center">
<div class="chat-sidebar-profile-toggle" (click)="showProfile($event)">
<div class="avatar">
<img *ngIf="loggedInUser.photoURL" src="{{loggedInUser.photoURL}}" class="cursor-pointer" alt="user_avatar" height="36" width="36">
<img *ngIf="!loggedInUser.photoURL" src="../../../../assets/images/portrait/small/avatar-s-19.png"
alt="avatar" height="36" width="36">
<!-- <img src="../../../assets/images/portrait/small/avatar-s-16.png" class="cursor-pointer" alt="user_avatar"
height="36" width="36"> -->
</div>
</div>
<fieldset class="form-group position-relative has-icon-left mx-75 mb-0">
<input type="text" class="form-control round" id="chat-search" (keyup)="searchContact($event)" placeholder="Search">
<div class="form-control-position">
<i class="ficon feather ft-search text-dark"></i>
</div>
</fieldset>
</div>
</div>
<div class="chat-sidebar-list-wrapper pt-2 " fxFlex="auto" [perfectScrollbar]="config" >
<h6 class="px-2 pb-25 mb-0">CHANNELS<i class="ficon feather ft-plus float-right cursor-pointer"></i></h6>
<ul class="chat-sidebar-list">
<li>
<h6 class="mb-0"># Devlopers</h6>
</li>
<li>
<h6 class="mb-0"># Designers</h6>
</li>
</ul>
<h6 class="px-2 pt-2 pb-25 mb-0">CHATS</h6>
<ul class="chat-sidebar-list" >
<li class = "chatSidebar" *ngFor="let chat of chatList" id="users-list" (click)="loadMyChatRoom(chat)" (click)="contentOverlay($event)"
id="_media" [ngClass]="(chat.uid === clickedUser) ? 'active': ''">
<div class="d-flex align-items-center" >
<div class="avatar m-0 mr-50" ><img [src]="chat.image" height="36"
width="36" >
<span class="avatar-status-busy"></span>
</div>
<div class="chat-sidebar-name">
<span class="mb-0">{{chat.name}}</span>
<span class="badge badge-pill float-right badge-danger mr-2">{{chat.unreadMessageCount ? chat.unreadMessageCount : ''}}</span>
<span class="text-muted"></span>
</div>
</div>
</li>
</ul>
<h6 class="px-2 pt-2 pb-25 mb-0">CONTACTS<i class="ficon feather ft-plus float-right cursor-pointer"></i></h6>
<ul class="chat-sidebar-list" >
<li class = "chatSidebar" *ngFor="let contact of contactList" (click)="showChat(contact)" (click)="contentOverlay($event)"
id="_media" [ngClass]="(contact.uid === clickedUser) ? 'active': ''">
<div class="d-flex align-items-center">
<div class="avatar m-0 mr-50"><img [src]="contact.image" height="36"
width="36" >
<span class="avatar-status-away"></span>
</div>
<div class="chat-sidebar-name">
<h6 class="mb-0">{{contact.name}}</h6><span class="text-muted"> {{contact.showMessage}}</span>
</div>
</div>
</li>
</ul>
</div>
</div>
<!-- app chat sidebar ends -->
</div>
</div>
<div class="content-right ">
<div class="content-overlay" ></div>
<div class="content-wrapper">
<div class="content-header row">
</div>
<div class="content-body"><!-- app chat overlay -->
<div class="chat-overlay " id="overlayChat" (click) = "Sidebar($event)"></div>
<!-- app chat window start -->
<section class="chat-window-wrapper">
<div class="chat-start" id='chat-overlay1'>
<span class="ficon feather ft-message-square chat-sidebar-toggle chat-start-icon font-large-3 p-3 mb-1" (click)="showSidebar($event)" ></span>
<h4 class="d-none d-lg-block py-50 text-bold-500">Select a contact to start a chat!</h4>
<button class="btn btn-light-primary chat-start-text chat-sidebar-toggle d-block d-lg-none py-50 px-1" (click)="showSidebar($event)" >Start
Conversation!</button>
</div>
<div class="chat-area d-none" id = "chat-area d-none">
<div class="chat-header">
<header class="d-flex justify-content-between align-items-center px-1 py-75">
<div class="d-flex align-items-center" >
<div class="chat-sidebar-toggle d-block d-lg-none mr-1" id="chat-sidebar"><i
class="ficon feather ft-align-justify font-large-1 cursor-pointer" (click)="showSidebar($event)"></i>
</div>
<div class="avatar chat-profile-toggle m-0 mr-1" (click)="ShowChatProfile($event)">
<span >
<img [src]="headerImage" class="cursor-pointer" alt="avatar"/>
</span>
<span class="avatar-status-busy"></span>
</div>
<h6 class="mb-0">{{headerName}}</h6>
</div>
<div class="chat-header-icons">
<span class="chat-icon-favorite" id='chat-icon'(click)="chatFavorite($event)" >
<i class="ficon feather ft-star font-medium-5 cursor-pointer"></i>
</span>
<span class="dropdown">
<span ngbDropdown [open]="false" [autoClose]="true" class="d-inline-block">
<i class="ficon feather ft-more-vertical font-medium-4 ml-25 cursor-pointer dropdown-toggle nav-hide-arrow cursor-pointer"
id="dropdownMenuButton" dropdown-menu dropdown-menu-left show data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="menu" ngbDropdownToggle>
</i>
<div ngbDropdownMenu ="dropdownMenuButton">
<a class="dropdown-item">Pin to top</a>
<a class="dropdown-item">Delete chat</a>
<a class="dropdown-item ">Block</a>
</div>
</span>
</span>
</div>
</header>
</div>
<!-- chat card start -->
<div class="card chat-wrapper shadow-none mb-0">
<div class="card-content">
<div class="card-body chat-container" id="componentRef">
<perfect-scrollbar [config]="config" #chatPS>
<div class="chat-content" #content>
<div id="chatWindow" class="chat" [ngClass]="(currentUserUid === messages.uid)?'chat-right':'chat-left'"
*ngFor="let messages of displayChat">
<div class="chat-avatar">
<a [routerLink]="" class="avatar m-0">
<img [src]="messages.userImage" *ngIf="messages.userImage"/>
</a>
</div>
<div class="chat-body">
<div class="chat-message">
<p>{{messages.message}}</p>
<span class="chat-time" title="{{messages.date | date}}">{{messages.date| date: 'HH:mm a'}}</span>
</div>
</div>
</div>
</div>
</perfect-scrollbar>
</div>
</div>
<div class="card-footer chat-footer px-2 py-1 pb-0">
<form class="d-flex align-items-center">
<i class="ficon feather ft-user cursor-pointer"></i>
<i class="ficon feather ft-paperclip ml-1 cursor-pointer"></i>
<input type="text" class="form-control chat-message-send mx-1" [(ngModel)]="newMessage" name="newmessage" id="iconLeft4"
placeholder="Type your message here...." #box (keyup.enter)="onEnter(box.value)">
<button type="submit" class="btn btn-primary glow send d-lg-flex" (click)="sendMessage()"><i class="ficon feather ft-play"></i>
<span class="d-none d-lg-block mx-50">Send</span></button>
</form>
</div>
</div>
<!-- chat card ends -->
</div>
</section>
<section class="chat-profile " id="chat-profile">
<header class="chat-profile-header text-center border-bottom">
<span class="chat-profile-close" (click)="ChatProfile($event)">
<i class="ficon feather ft-x"></i>
</span>
<div class="my-2">
<img [src]="headerImage" class="round mb-1" alt="chat avatar"
height="100" width="100">
<h5 class="app-chat-user-name mb-0">{{headerName}}</h5>
<span>Devloper</span>
</div>
</header>
<div class="chat-profile-content p-2">
<h6 class="mt-1">ABOUT</h6>
<p>It is a long established fact that a reader will be distracted by the readable content.</p>
<h6 class="mt-2">PERSONAL INFORMATION</h6>
<ul class="list-unstyled">
<li class="mb-25">email@gmail.com</li>
<li>+1(789) 950-7654</li>
</ul>
</div>
</section>
<!-- app chat window ends -->
</div>
</div>
</div>
</div>
<!-- END: Content-->
<!-- app chat profile right sidebar ends -->

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ChatsComponent } from './chats.component';
describe('ChatComponent', () => {
let component: ChatsComponent;
let fixture: ComponentFixture<ChatsComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ ChatsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ChatsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,543 @@
import { Component, OnInit, AfterViewInit, ViewChild, Renderer2, ViewChildren, QueryList, ElementRef } from '@angular/core';
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
import { UserService } from '../../../../../src/app/_api/user/user.service';
import { ChatService } from '../../../../../src/app/_api/chat/chat.service';
import { Chats } from './chats';
import { AppConstants } from '../../../_helpers/app.constants';
import * as _ from 'lodash';
@Component({
selector: 'app-chat',
templateUrl: './chats.component.html',
styleUrls: ['./chats.component.css']
})
export class ChatsComponent implements OnInit, AfterViewInit {
showicon: boolean;
name: any;
isicon: boolean;
isactive: boolean;
isSelected: boolean;
chatArray: any;
status = true;
newMessage = '';
contactId: string;
messageInfo: any;
userInfo: any;
public displayName: boolean;
public config: PerfectScrollbarConfigInterface = { wheelPropagation: false };
@ViewChild('chatPS') public chatPS?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective, { static: true })
directiveRef?: PerfectScrollbarDirective;
@ViewChildren('messages') messages: QueryList<any>;
@ViewChild('content', { static: true }) content: ElementRef;
contactList = [];
contactChats = [];
headerName: string;
headerImage: any;
showChatInProgress = false;
createInProgress = false;
contactMaster = this.contactList;
chatListMaster = [];
temp = [];
loggedInUser = JSON.parse(localStorage.getItem('currentUser'));
currentUserUid = this.loggedInUser.uid;
currentUser = ''; // UID of user 1
clickedUser = ''; // UID of user 2
chatList = [];
displayChat = [];
chatId = '';
senderImage = '';
currentUserImage = '';
loadContacts = false;
prevMsg = '';
/**
* Constructor
*
* @param ApplicationApiService chatApiService;
* @param Renderer2 renderer
*/
constructor(
private renderer: Renderer2,
private userService: UserService,
private chatService: ChatService) {
}
/**
* Scroll chat to bottom
*/
ngAfterViewInit() {
this.messages.forEach(this.scrollToBottom);
this.messages.changes.subscribe(this.scrollToBottom);
}
getLoggedInUserChats () {
if (this.contactChats) {
const chatsWithHistory = this.contactChats.filter((item: Chats) => {
return item.chatHistory.length > 0;
});
const loggedInUserChats = chatsWithHistory.filter(chatHistory => {
return chatHistory.name.indexOf(this.loggedInUser.uid) !== -1;
});
return loggedInUserChats;
}
return [];
}
/**
* OnInit
*/
ngOnInit() {
this.userService.getUsers().subscribe(users => {
let contactList = users.map(item => {
return {
...item.payload.doc.data() as {},
id: item.payload.doc['id']
};
});
contactList = contactList.filter(element => {
return this.loggedInUser.uid !== element['uid'];
});
this.contactMaster = contactList;
this.chatService.getChats().subscribe(chats => {
this.chatList = [];
this.contactList = [];
const chatRooms = chats.map(item => {
return {
...item.payload.doc.data() as Chats,
id: item.payload.doc['id']
};
});
this.contactChats = chatRooms;
const loggedInUserChats = this.getLoggedInUserChats();
const contactListMap = [];
const chatListMap = [];
this.contactMaster.forEach(element => {
const userChat = this.isChatExistsWithUser(loggedInUserChats, element.uid);
if (userChat && !chatListMap[element.uid]) {
element['chatRoomId'] = userChat['id'];
if (userChat['chatHistory'] && userChat['chatHistory'].length > 0) {
const unreadMessages = userChat['chatHistory'].filter( history => {
return history.uid !== this.loggedInUser.uid && history.status === 'send';
});
if (unreadMessages.length > 0 && this.clickedUser !== element.uid) {
element['unreadMessageCount'] = unreadMessages.length;
} else {
element['unreadMessageCount'] = 0;
}
element['chatHistory'] = userChat['chatHistory'];
}
chatListMap[element.uid] = true;
this.chatList.push(element);
this.chatListMaster.push(element);
} else if (!contactListMap[element.uid]) {
contactListMap[element.uid] = true;
this.contactList.push(element);
}
});
this.chatList = _.orderBy(this.chatList, [user => user.name.toLowerCase()], ['asc']);
this.contactList = _.orderBy(this.contactList, [user => user.name && user.name.toLowerCase()], ['asc']);
this.currentUserImage = this.loggedInUser.photoURL;
this.senderImage = this.contactList[0].image;
this.createInProgress = false;
});
});
}
isChatExistsWithUser (userChats, userId) {
for (let index = 0; index < userChats.length; index++) {
if (userChats[index].name.indexOf(userId) !== -1) {
return userChats[index];
}
}
return false;
}
/**
* Chat scroll to bottom
*/
scrollToBottom = () => {
try {
this.content.nativeElement.scrollTop = this.content.nativeElement.scrollHeight;
this.chatPS.directiveRef.scrollToBottom(0, 500);
} catch (err) { }
}
/**
* Filter Chat
*
* @param event search event
*/
searchContact (event) {
const value = event.target.value.toLowerCase();
// filter our data
let temp = this.contactMaster.filter(function (d) {
return d.name && d.name.toLowerCase().indexOf(value) !== -1 || !value;
});
const loggedInUserChats = this.getLoggedInUserChats();
const _self = this;
temp = temp.filter(function (user) {
return !_self.isChatExistsWithUser(loggedInUserChats, user.uid);
});
// update the rows
this.contactList = [];
const contactListMap = [];
temp.forEach(element => {
if (!contactListMap[element.uid]) {
contactListMap[element.uid] = true;
this.contactList.push(element);
}
});
// filter our data
const tempChat = this.chatListMaster.filter(function (d) {
return d.name && d.name.toLowerCase().indexOf(value) !== -1 || !value;
});
// update the rows
this.chatList = [];
const chatListMap = [];
tempChat.forEach(element => {
if (!chatListMap[element.uid]) {
chatListMap[element.uid] = true;
this.chatList.push(element);
}
});
}
/**
* Send message
*/
sendMessage() {
if (this.newMessage !== null && this.newMessage !== '') {
this.messageInfo = {
message: this.newMessage,
date: Date.now(),
uid: this.loggedInUser.uid,
status: 'send'
};
if (this.chatId !== '') {
this.chatService.sendMessage(this.chatId, this.messageInfo);
} else {
this.currentUser = this.loggedInUser.uid;
const roomName = (this.currentUser < this.clickedUser ? this.currentUser + '_' +
this.clickedUser : this.clickedUser + '_' + this.currentUser);
this.userInfo = {
uid: this.loggedInUser.uid,
name: roomName,
image: this.loggedInUser.photoURL,
time: Date.now(),
showMessage: '',
badge: '',
showicon: true,
isicon: false,
isactive: 'online',
isSelected: false,
chatHistory: []
};
// Add message to box before sending
this.displayChat.push(this.messageInfo);
this.createInProgress = true;
this.chatService.createChatRoom(this.userInfo).then(chatRoom => {
this.chatId = chatRoom.id;
this.loadChatRoom(chatRoom.id);
this.chatService.sendMessage(this.chatId, this.messageInfo);
this.createInProgress = false;
});
}
this.newMessage = null;
}
}
/**
* Message send on Enter
*
* @param value New message
*/
onEnter(value: string) {
this.newMessage = value;
this.sendMessage();
}
/**
* Display chat when click on contact
*
* @param friendId Friend id
*/
showChat(data) {
if (this.showChatInProgress || this.createInProgress) {
return;
}
this.showChatInProgress = true;
this.currentUser = this.loggedInUser.uid;
this.currentUserImage = this.loggedInUser.photoURL;
this.clickedUser = data.uid;
this.contactId = data.id;
this.senderImage = data.image;
this.showHeaderData();
const roomName = (this.currentUser < this.clickedUser ? this.currentUser + '_' +
this.clickedUser : this.clickedUser + '_' + this.currentUser);
this.userInfo = {
uid: this.loggedInUser.uid,
name: roomName,
image: this.loggedInUser.photoURL,
time: Date.now(),
showMessage: '',
badge: '',
showicon: true,
isicon: false,
isactive: 'online',
isSelected: false,
chatHistory: []
};
if (this.contactChats.length === 0) {
this.createAndLoadChatRoom();
} else if (this.contactChats.length !== 0) {
let chatExists = false;
for (let i = 0; i < this.contactChats.length; i++) {
const room = this.contactChats[i].name;
if (room === roomName) {
chatExists = true;
this.chatId = this.contactChats[i].id;
break;
}
}
if (!chatExists) {
this.createAndLoadChatRoom();
} else {
// subscribe
this.loadChatRoom(this.chatId);
this.showChatInProgress = false;
this.userInfo.isSelected = true;
}
}
}
createAndLoadChatRoom() {
this.createInProgress = true;
this.chatService.createChatRoom(this.userInfo).then(chatRoom => {
this.chatId = chatRoom.id;
this.loadChatRoom(chatRoom.id);
});
}
setUserImage(chatHistory) {
for (let i = 0; i < chatHistory.length; i++) {
if (chatHistory.length > 0) {
if (i > 0) {
this.prevMsg = chatHistory[i - 1];
}
if (i > 0 && chatHistory[i].uid === this.prevMsg['uid']) {
continue;
}
if (chatHistory[i].uid === this.loggedInUser.uid) {
chatHistory[i]['userImage'] = this.currentUserImage;
} else {
chatHistory[i]['userImage'] = this.senderImage;
}
}
}
}
loadMyChatRoom(selectedUser) {
this.chatId = selectedUser.chatRoomId;
this.loadChatRoom(selectedUser.chatRoomId);
this.clickedUser = selectedUser.uid;
this.contactId = selectedUser.id;
this.senderImage = selectedUser.image;
this.headerName = selectedUser.name;
this.headerImage = selectedUser.image;
this.setHistoryAsRead(selectedUser, selectedUser.chatRoomId, selectedUser.chatHistory);
}
setHistoryAsRead (selectedUser, chatRoomId, history) {
let unreadMsgExists = false;
history.forEach(element => {
if (element.uid !== this.loggedInUser.uid && element.status !== 'read') {
element.status = 'read';
unreadMsgExists = true;
}
});
if (unreadMsgExists) {
this.chatService.updateChatStatus(chatRoomId, history).then(result => {
delete selectedUser.unreadMessageCount;
});
}
}
loadChatRoom(chatRoomId) {
this.chatService.showChat(chatRoomId).subscribe(res => {
if (chatRoomId === this.chatId) {
this.setUserImage(res.chatHistory);
this.displayChat = res['chatHistory'];
this.chatId = res['chatId'];
}
this.showChatInProgress = false;
this.scrollToBottom();
});
}
showDefaultChat() {
this.currentUser = this.loggedInUser.uid;
const roomName = (this.currentUser < this.clickedUser ? this.currentUser + '_' +
this.clickedUser : this.clickedUser + '_' + this.currentUser);
for (let j = 0; j < this.contactChats.length; j++) {
if (this.contactChats[j].name === roomName) {
if (this.contactChats[j].chatHistory && this.contactChats[j].chatHistory.length > 0) {
this.displayChat = this.contactChats[j].chatHistory;
this.setUserImage(this.contactChats[j].chatHistory);
}
this.chatId = this.contactChats[j].id;
}
}
}
showLastMessage() {
for (let i = 0; i < this.contactList.length; i++) {
if (this.contactList[i]) {
for (let j = 0; j < this.contactChats.length; j++) {
const room = this.contactChats[j].name;
const index = room.indexOf(this.contactList[i].uid);
const currentUser = this.loggedInUser.uid;
const userUid = this.contactList[i].uid;
const roomName = (currentUser < userUid ? currentUser + '_' +
userUid : userUid + '_' + currentUser);
if (index >= 0) {
if (this.contactChats[j].chatHistory.length > 0 && roomName === room) {
this.contactList[i]['lastmsg'] = this.contactChats[j].chatHistory[this.contactChats[j].chatHistory.length - 1].message;
this.contactList[i]['isActive'] = this.contactChats[j].isactive;
this.contactList[i]['icon'] = this.contactChats[j].isicon;
this.contactList[i]['showicon'] = this.contactChats[j].showicon;
this.contactList[i]['lastmsgTime'] = this.contactChats[j].chatHistory[this.contactChats[j].chatHistory.length - 1].date;
}
}
}
}
}
}
/**
* Overlay add/remove fuction in responsive
*
* @param event Overlay click event
*/
contentOverlay(event) {
const toggleIcon = document.getElementById('chat-overlay1');
const toggle = document.getElementById('chat-area d-none');
if (event.currentTarget.className === 'chatSidebar ng-star-inserted') {
this.renderer.addClass(toggleIcon, 'd-none');
this.renderer.removeClass(toggle, 'd-none');
}
}
/**
* Show add/remove class at open profile
*
* @param event Overlay click event
*/
showProfile(event) {
const toggleIcon = document.getElementById('user-profile');
const toggle = document.getElementById('overlayChat');
if (event.currentTarget.className === 'chat-sidebar-profile-toggle') {
this.renderer.addClass(toggleIcon, 'show');
this.renderer.addClass(toggle, 'show');
} else if (event.currentTarget.className === 'chat-profile-close') {
this.renderer.removeClass(toggleIcon, 'show');
this.renderer.removeClass(toggle, 'show');
}
}
/**
* Show add/remove function in responsive
*
* @param event Overlay click event
*/
Sidebar(event) {
const toggleChat = document.getElementById('sidebar-card');
const toggleIcon = document.getElementById('chat-profile');
const toggle = document.getElementById('overlayChat');
if (event.currentTarget.className === 'chat-sidebar-close' || 'chat-overlay') {
this.renderer.removeClass(toggle, 'show');
this.renderer.removeClass(toggleIcon, 'show');
this.renderer.removeClass(toggleChat, 'show');
}
}
/**
* Show add/remove function in responsive
*
* @param event Overlay click event
*/
showSidebar(event) {
if (window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH) {
const toggleIcon = document.getElementById('sidebar-card');
const toggle = document.getElementById('overlayChat');
const toggleChat = document.getElementById('sidebar-left');
if (event.currentTarget.className === 'ficon feather ft-message-square chat-sidebar-toggle chat-start-icon font-large-3 p-3 mb-1' ||
'ficon feather ft-align-justify font-large-1 cursor-pointer') {
this.renderer.addClass(toggle, 'show');
this.renderer.addClass(toggleIcon, 'show');
}
if (window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH) {
this.renderer.removeClass(toggleChat, 'sidebar-fixed');
}
}
}
// FixChat() {
// const toggleIcon = document.getElementById('sidebar-left');
// if (window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH) {
// this.renderer.removeClass(toggleIcon, 'sidebar-fixed');
// }
// }
chatFavorite(event) {
const chatIcon = document.getElementById('chat-icon');
if (event.currentTarget.className === 'chat-icon-favorite') {
this.renderer.addClass(chatIcon, 'warning');
} else if (event.currentTarget.className === 'chat-icon-favorite warning') {
this.renderer.removeClass(chatIcon, 'warning');
}
}
showHeaderData() {
this.contactList.forEach(element => {
if (this.clickedUser === element['uid']) {
this.headerName = element.name;
this.headerImage = element.image;
}
});
}
/**
* Show add/remove function
*
* @param event Overlay click event
*/
ShowChatProfile(event) {
const toggleIcon = document.getElementById('chat-profile');
const toggle = document.getElementById('overlayChat');
if (event.currentTarget.className === 'avatar chat-profile-toggle m-0 mr-1') {
this.renderer.addClass(toggleIcon, 'show');
this.renderer.addClass(toggle, 'show');
}
}
/**
* Show add/remove function
*
* @param event Overlay click event
*/
ChatProfile(event) {
const toggleIcon = document.getElementById('chat-profile');
const toggle = document.getElementById('overlayChat');
if (event.currentTarget.className === 'chat-profile-close') {
this.renderer.removeClass(toggleIcon, 'show');
this.renderer.removeClass(toggle, 'show');
}
}
}

View File

@@ -0,0 +1,13 @@
import { ChatsModule } from './chats.module';
describe('ChatModule', () => {
let chatsModule: ChatsModule;
beforeEach(() => {
chatsModule = new ChatsModule();
});
it('should create an instance', () => {
expect(chatsModule).toBeTruthy();
});
});

View File

@@ -0,0 +1,33 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ChatsComponent } from './chats.component';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { ChatService } from 'src/app/_api/chat/chat.service';
import { StaticChatComponent } from './static-chat/static-chat.component';
import { ApplicationApiService } from 'src/app/_services/application-api.service';
import { ToastrModule } from 'ngx-toastr';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
@NgModule({
imports: [
CommonModule,
FormsModule,
NgbModule,
ToastrModule.forRoot(),
PerfectScrollbarModule,
RouterModule.forChild([
{
path: '',
component: ChatsComponent
},
{
path: 'static-chat',
component: StaticChatComponent
}
])
],
declarations: [ChatsComponent, StaticChatComponent],
providers: [ChatService, ApplicationApiService]
})
export class ChatsModule { }

View File

@@ -0,0 +1,20 @@
export class Chats {
uid: string;
senderUid: string;
name: string;
image: string;
time: Date;
showMessage: String;
badge: String;
showicon: boolean;
isicon: boolean;
isactive: boolean;
isSelected: boolean;
chatHistory: Array<ChatHistory>;
}
export class ChatHistory {
date: Date;
message: string;
uid: string;
}

View File

@@ -0,0 +1,86 @@
<div class="content-right">
<!-- <div class="content-wrapper"> -->
<div class="content-header row"></div>
<div class="content-overlay"></div>
<div class="chat-header">
<header class="d-flex justify-content-between align-items-center px-1 py-75">
<div class="d-flex align-items-center">
<div class="chat-sidebar-toggle d-block d-lg-none mr-1"><i
class="ft-align-justify font-large-1 cursor-pointer"></i>
</div>
<div class="avatar chat-profile-toggle m-0 mr-1">
<img src="../../../assets/images/portrait/small/avatar-s-26.png" class="cursor-pointer" alt="avatar"
height="36" width="36" />
<span class="avatar-status-busy"></span>
</div>
<h6 class="mb-0">Elizabeth Elliott</h6>
</div>
<div class="chat-header-icons">
<span class="chat-icon-favorite">
<i class="ficon feather ft-star font-medium-5 cursor-pointer"></i>
</span>
<span class="dropdown">
<i class="ficon feather ft-more-vertical font-medium-4 ml-25 cursor-pointer dropdown-toggle nav-hide-arrow cursor-pointer"
id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="menu">
</i>
<span class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href="JavaScript:void(0);"><i class="ficon feather ft-tag mr-25"></i> Pin to top</a>
<a class="dropdown-item" href="JavaScript:void(0);"><i class="ficon feather ft-trash-2 mr-25"></i> Delete chat</a>
<a class="dropdown-item" href="JavaScript:void(0);"><i class="ficon feather ft-x-circle mr-25"></i> Block</a>
</span>
</span>
</div>
</header>
</div>
<div class="card chat-wrapper shadow-none mb-0">
<div class="card-content">
<div class="content-body chat-container">
<div class="chat-content">
<div class="chat">
<div class="chat-avatar">
<div class="content-overlay" id='content-overlay' (click)="contentOverlay($event)"></div>
<section class="chat-app-window" #content>
<div class="sidebar-toggle d-block d-lg-none" (click)="sidebar($event)"><i class="feather ft-menu font-large-1"></i></div>
<div class="badge badge-secondary mb-1">Chat History</div>
<div class="chats" #messages>
<div class="chat" [ngClass]="{'chat-right': messages.sender == 0 , 'chat-left': messages.sender == 1 }"
*ngFor="let messages of contactChat">
<div class="chat-avatar">
<a [routerLink]="" class="avatar">
<span class="avatar-online"><img [src]="messages.senderImage" /></span>
</a>
</div>
<div class="chat-body">
<div class="chat-content">
<p>{{messages.message}}</p>
</div>
</div>
</div>
</div>
</section>
<section class="chat-app-form">
<form class="chat-app-input d-flex">
<fieldset class="form-group position-relative has-icon-left col-10 m-0">
<div class="form-control-position">
<i class="icon-emoticon-smile"></i>
</div>
<input type="text" class="form-control" [(ngModel)]="newMessage" name="newmessage" id="iconLeft4"
placeholder="Type your message" #box (keyup.enter)="onEnter(box.value)">
<div class="form-control-position control-position-right">
<i class="feather ft-image"></i>
</div>
</fieldset>
<fieldset class="form-group position-relative has-icon-left col-2 m-0">
<button type="button" class="btn btn-primary" (click)="sendMessage()" keyboardShouldPersistTaps={true}><i
class="la la-paper-plane-o d-lg-none"></i><span class="d-none d-lg-block">Send</span></button>
</fieldset>
</form>
</section>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- </div> -->
</div>

View File

@@ -0,0 +1,66 @@
:host ::ng-deep .content-right {
width: calc(100% - 300px) !important;
}
:host ::ng-deep .mx-75 {
margin-left: .75rem!important;
margin-right: .75rem!important;
}
:host ::ng-deep .py-75 {
padding-bottom: .75rem!important;
padding-top: .75rem!important;
}
:host ::ng-deep .px-1 {
padding-left: 1rem!important;
padding-right: 1rem!important;
}
:host ::ng-deep .mr-50, .mx-50 {
margin-right: .5rem!important;
margin-left: .5rem!important;
}
:host ::ng-deep .mb-50, .my-50 {
margin-bottom: .5rem!important;
}
:host ::ng-deep .dropdown-menu
{
transform: translate3d(-131px, 18px, 0px) !important;
}
:host ::ng-deep .chat-sidebar .chat-sidebar-list-wrapper {
overflow-y: scroll;
}
:host ::ng-deep .sidebar-fixed {
overflow: hidden !important;
width: 300px;
}
:host ::ng-deep .app-content {
overflow-y: hidden !important;
}
:host ::ng-deep .pb-25, .py-25 {
padding-bottom: .25rem!important;
}
:host ::ng-deep .ml-25, .mx-25 {
margin-left: .25rem!important;
}
@media(max-width:767px) {
:host ::ng-deep .chat-footer
{
position: relative !important;
bottom: 17px !important;
}
}
@media(max-width:767px) {
:host ::ng-deep .chat-wrapper
{
background-color: unset !important;
}
}
@media(max-width:767px) {
:host ::ng-deep .content-right {
width: calc(100% - 0px) !important;
}
}
:host ::ng-deep .d-inline-block {
display: inline !important;
}

View File

@@ -0,0 +1,239 @@
<div class="app-content content" >
<div class="sidebar-left " id="sidebar-left">
<div class="sidebar"><!-- app chat user profile left sidebar start -->
<div class="chat-user-profile" id="user-profile" >
<header class="chat-user-profile-header text-center border-bottom">
<span class="chat-profile-close" (click)="showProfile($event)" >
<i class="ficon feather ft-x" ></i>
</span>
<div class="my-2">
<img src="../../../assets/images/portrait/small/avatar-s-19.png" class="round mb-1" alt="user_avatar"
height="100" width="100" >
<h5 class="mb-0">John Doe</h5>
<span>Designer</span>
</div>
</header>
<div class="chat-user-profile-content">
<div class="chat-user-profile-scroll" fxFlex="auto" [perfectScrollbar]="config">
<h6 class="text-uppercase mb-1">ABOUT</h6>
<p class="mb-2">It is a long established fact that a reader will be distracted by the readable content .</p>
<h6>PERSONAL INFORAMTION</h6>
<ul class="list-unstyled mb-2">
<li class="mb-25">email@gmail.com</li>
<li>+1(789) 950 -7654</li>
</ul>
<h6 class="text-uppercase mb-1">CHANNELS</h6>
<ul class="list-unstyled mb-2">
<li><a href=""># Devlopers</a></li>
<li><a href=""># Designers</a></li>
</ul>
<h6 class="text-uppercase mb-1">SETTINGS</h6>
<ul class="list-unstyled">
<li class="mb-50 "><a href="" class="d-flex align-items-center"><i class="ficon feather ft-tag mr-50"></i>
Add
Tag</a></li>
<li class="mb-50 "><a href="" class="d-flex align-items-center"><i class="ficon feather ft-star mr-50"></i>
Important Contact</a>
</li>
<li class="mb-50 "><a href="" class="d-flex align-items-center"><i
class="ficon feather ft-image mr-50"></i>
Shared
Documents</a></li>
<li class="mb-50 "><a href="" class="d-flex align-items-center"><i
class="ficon feather ft-trash-2 mr-50"></i>
Deleted
Documents</a></li>
<li><a href="" class="d-flex align-items-center"><i class="ficon feather ft-x-circle mr-50"></i> Blocked
Contact</a></li>
</ul>
</div>
</div>
</div>
<!-- app chat user profile left sidebar ends -->
<!-- app chat sidebar start -->
<div class="chat-sidebar card " id="sidebar-card">
<span class="chat-sidebar-close" (click) = "Sidebar($event)">
<i class="ficon feather ft-x" ></i>
</span>
<div class="chat-sidebar-search">
<div class="d-flex align-items-center">
<div class="chat-sidebar-profile-toggle" (click)="showProfile($event)">
<div class="avatar">
<img src="../../../assets/images/portrait/small/avatar-s-19.png" class="cursor-pointer" alt="user_avatar"
height="36" width="36">
</div>
</div>
<fieldset class="form-group position-relative has-icon-left mx-75 mb-0">
<input type="text" class="form-control round" id="chat-search" (keyup)="updateFilter($event)" (keyup)="updateFilter1($event)" placeholder="Search">
<div class="form-control-position">
<i class="ficon feather ft-search text-dark"></i>
</div>
</fieldset>
</div>
</div>
<div class="chat-sidebar-list-wrapper pt-2 " [perfectScrollbar]="config" style="top: 0px; height: 450px;">
<h6 class="px-2 pb-25 mb-0">CHANNELS<i class="ficon feather ft-plus float-right cursor-pointer"></i></h6>
<ul class="chat-sidebar-list">
<li>
<h6 class="mb-0"># Devlopers</h6>
</li>
<li>
<h6 class="mb-0"># Designers</h6>
</li>
</ul>
<h6 class="px-2 pt-2 pb-25 mb-0">CHATS</h6>
<ul class="chat-sidebar-list" >
<li class = "chatSidebar" *ngFor="let chats of chatsList" id="users-list" (click)="contentOverlay($event)"
(click)="showChat(chats.friendId,1)" [ngClass]="{'active':chats.isSelected === true, '':chats.isSelected === false}">
<div class="d-flex align-items-center" >
<div class="avatar m-0 mr-50" ><img [src]="chats.image" height="36"
width="36" alt="sidebar user image">
<span class="avatar-status-busy"></span>
</div>
<div class="chat-sidebar-name">
<h6 class="mb-0">{{chats.name}}</h6><span class="text-muted">{{chats.showMessage}}</span>
</div>
</div>
</li>
</ul>
<h6 class="px-2 pt-2 pb-25 mb-0">CONTACTS<i class="ficon feather ft-plus float-right cursor-pointer"></i></h6>
<ul class="chat-sidebar-list" >
<li class = "chatSidebar" *ngFor="let contact of contactList" (click)="contentOverlay($event)"
(click)="showChat(contact.friendId,2)" id="_media" [ngClass]="{'active':contact.isSelected === true, '':contact.isSelected === false}">
<div class="d-flex align-items-center">
<div class="avatar m-0 mr-50"><img [src]="contact.image">
<span class="avatar-status-away"></span>
</div>
<div class="chat-sidebar-name">
<h6 class="mb-0">{{contact.name}}</h6><span class="text-muted"> {{contact.showMessage}}</span>
</div>
</div>
</li>
</ul>
</div>
</div>
<!-- app chat sidebar ends -->
</div>
</div>
<div class="content-right ">
<div class="content-overlay" ></div>
<div class="content-wrapper">
<div class="content-header row">
</div>
<div class="content-body"><!-- app chat overlay -->
<div class="chat-overlay " (click) = "Sidebar($event)" id="overlayChat" ></div>
<!-- app chat window start -->
<section class="chat-window-wrapper">
<div class="chat-start" id='chat-overlay1'>
<span class="ficon feather ft-message-square chat-sidebar-toggle chat-start-icon font-large-3 p-3 mb-1" (click)="showSidebar($event)" ></span>
<h4 class="d-none d-lg-block py-50 text-bold-500">Select a contact to start a chat!</h4>
<button class="btn btn-light-primary chat-start-text chat-sidebar-toggle d-block d-lg-none py-50 px-1" (click)="showSidebar($event)">Start
Conversation!</button>
</div>
<div class="chat-area d-none" id = "chat-area d-none">
<div class="chat-header">
<header class="d-flex justify-content-between align-items-center px-1 py-75">
<div class="d-flex align-items-center" *ngFor="let chats of headerChat">
<div class="chat-sidebar-toggle d-block d-lg-none mr-1" id="chat-sidebar"><i
class="ficon feather ft-align-justify font-large-1 cursor-pointer" (click)="showSidebar($event)"></i>
</div>
<div class="avatar chat-profile-toggle m-0 mr-1" (click)="ShowChatProfile($event)">
<span >
<img [src]="chats.headerImage" class="cursor-pointer" alt="avatar"/>
</span>
<span class="avatar-status-busy"></span>
</div>
<h6 class="mb-0">{{chats.senderName}}</h6>
</div>
<div class="chat-header-icons">
<span class="chat-icon-favorite" id='chat-icon' (click)="chatFavorite($event)">
<i class="ficon feather ft-star font-medium-5 cursor-pointer"></i>
</span>
<span ngbDropdown [open]="false" [autoClose]="true" class="d-inline-block dropdown">
<i class="ficon feather ft-more-vertical font-medium-4 ml-25 cursor-pointer dropdown-toggle nav-hide-arrow cursor-pointer"
id="dropdownMenuButton" dropdown-menu dropdown-menu-left show data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="menu" ngbDropdownToggle>
</i>
<div ngbDropdownMenu ="dropdownMenuButton">
<a class="dropdown-item">Pin to top</a>
<a class="dropdown-item">Delete chat</a>
<a class="dropdown-item ">Block</a>
</div>
</span>
</div>
</header>
</div>
<!-- chat card start -->
<div class="card chat-wrapper shadow-none mb-0">
<div class="card-content">
<div class="card-body chat-container" id="test" fxFlex="auto" [perfectScrollbar]="config">
<div class="chat-content">
<div class="chat" #messages [ngClass]="{'chat-right': messages.sender === 0 , 'chat-left': messages.sender === 1 }"
*ngFor="let messages of contactChat">
<div class="chat-avatar">
<a [routerLink]="" class="avatar m-0">
<img [src]="messages.senderImage" />
</a>
</div>
<div class="chat-body">
<div class="chat-message">
<p>{{messages.message}}</p>
<span class="chat-time">{{messages.time}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer chat-footer px-2 py-1 pb-0">
<form class="d-flex align-items-center">
<i class="ficon feather ft-user cursor-pointer"></i>
<i class="ficon feather ft-paperclip ml-1 cursor-pointer"></i>
<input type="text" class="form-control chat-message-send mx-1" [(ngModel)]="newMessage" name="newmessage" id="iconLeft4"
placeholder="Type your message here...." #box (keyup.enter)="onEnter(box.value)">
<button type="submit" class="btn btn-primary glow send d-lg-flex" (click)="sendMessage()" ><i class="ficon feather ft-play"></i>
<span class="d-none d-lg-block mx-50">Send</span></button>
</form>
</div>
</div>
<!-- chat card ends -->
</div>
</section>
<section class="chat-profile " id="chat-profile">
<header class="chat-profile-header text-center border-bottom">
<span class="chat-profile-close" (click)="ChatProfile($event)">
<i class="ficon feather ft-x"></i>
</span>
<div class="my-2" *ngFor="let chats of headerChat">
<img [src]="chats.headerImage"class="round mb-1" alt="chat avatar"
height="100" width="100">
<h5 class="app-chat-user-name mb-0">{{chats.senderName}}</h5>
<span>Devloper</span>
</div>
</header>
<div class="chat-profile-content p-2">
<h6 class="mt-1">ABOUT</h6>
<p>It is a long established fact that a reader will be distracted by the readable content.</p>
<h6 class="mt-2">PERSONAL INFORMATION</h6>
<ul class="list-unstyled">
<li class="mb-25">email@gmail.com</li>
<li>+1(789) 950-7654</li>
</ul>
</div>
</section>
<!-- app chat window ends -->
</div>
</div>
</div>
</div>
<!-- END: Content-->
<!-- app chat profile right sidebar ends -->

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { StaticChatComponent } from './static-chat.component';
describe('StaticChatComponent', () => {
let component: StaticChatComponent;
let fixture: ComponentFixture<StaticChatComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ StaticChatComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StaticChatComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,431 @@
import {
Component, OnInit, AfterViewInit, ViewChild, Renderer2,
ViewChildren, QueryList, ElementRef
} from '@angular/core';
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
import { ApplicationApiService } from '../../../../../../src/app/_services/application-api.service';
import { ToastrService } from 'ngx-toastr';
import { AppConstants } from '../../../../_helpers/app.constants';
/**
* ChatHistory class
*/
class ChatHistory {
constructor(
public message: string[],
public sender: number,
public senderImage: string,
public senderName: string,
public time: string
) { }
}
class ChatHeader {
constructor(
public senderImage: string,
public senderName: string
) { }
}
class ContactHeader {
constructor(
public senderImage: string,
public senderName: string
) { }
}
/**
* Chats class
*/
class Chats {
constructor(
public friendId: number,
public name: string,
public image: string,
public showMessage: string,
public _ChatHistory: Array<ChatHistory>,
public chatHeader: Array<ChatHeader>,
public isSelected: false
) { }
}
/**
* Contact class
*/
class Contact {
constructor(
public friendId: number,
public name: string,
public image: string,
public showMessage: string,
public isSelected: false,
public contactHeader: Array<ContactHeader>,
) {}
}
@Component({
selector: 'app-static-chat',
templateUrl: './static-chat.component.html',
styleUrls: ['./static-chat.component.css']
})
export class StaticChatComponent implements OnInit, AfterViewInit {
showicon: boolean;
isicon: boolean;
isactive: boolean;
isSelected: boolean;
chatArray: any;
headerArray: any;
status = true;
public contactChat = [];
public headerChat = [];
public Contact = [];
newMessage = '';
newMessageArray = [];
public config: PerfectScrollbarConfigInterface = { wheelPropagation: false };
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective, { static: true }) directiveRef?: PerfectScrollbarDirective;
@ViewChildren('messages') messages: QueryList<any>;
@ViewChild('content', { static: true }) content: ElementRef;
chatsList: any[] = [];
contactList: any[] = [];
temp = [];
temp2 = this.chatsList;
temp3 = this.contactList;
ContactHeader: any[] = [];
/**
* Constructor
*
* @param ApplicationApiService chatApiService;
* @param Renderer2 renderer
*/
constructor(
private chatApiService: ApplicationApiService,
private renderer: Renderer2,
private toastr: ToastrService) {
this.headerArray = this.chatApiService.getChatContactData().subscribe(Response => {
this.headerArray = Response;
});
}
/**
* Scroll chat to bottom
*/
ngAfterViewInit() {
this.messages.forEach(this.scrollToBottom);
this.messages.changes.subscribe(this.scrollToBottom);
}
/**
* OnInit
*/
ngOnInit() {
this.toastr.clear();
this.toastr.warning('', 'Please login through a personal account to experience the Live chat. We have it disabled for demo account.',
{ timeOut: 5000, disableTimeOut: true, closeButton: true });
this.chatArray = this.chatApiService.getChatsData().subscribe(Response => {
this.chatArray = Response;
this.contactChat = this.chatArray[2].ChatHistory;
this.chatsList.push(
new Chats(
2,
'Kristopher Candy',
'../../../assets/images/portrait/small/avatar-s-7.png',
' Thank you',
this.chatArray[1].ChatHistory,
this.chatArray[1].chatHeader,
false
)
);
this.chatsList.push(
new Chats(
3,
'Sarah Woods',
'../../../assets/images/portrait/small/avatar-s-8.png',
' Hello krish!',
this.chatArray[2].ChatHistory,
this.chatArray[2].chatHeader,
false
)
);
this.contactList.push(
new Contact(
1,
'Kristopher Candy',
'../../../assets/images/portrait/small/avatar-s-9.png',
'lemon drops',
false,
this.headerArray[0].contactHeader,
)
);
this.contactList.push(
new Contact(
2,
'Jenny Perich',
'../../../assets/images/portrait/small/avatar-s-10.png',
'candy canes',
false,
this.headerArray[1].contactHeader,
)
);
this.contactList.push(
new Contact(
3,
'Rock Montgomery',
'../../../assets/images/portrait/small/avatar-s-11.png',
'powder gum',
false,
this.headerArray[2].contactHeader,
)
);
this.contactList.push(
new Contact(
4,
'Heather Howell',
'../../../assets/images/portrait/small/avatar-s-12.png',
'cheesecake toffee',
false,
this.headerArray[3].contactHeader,
)
);
});
}
/**
* Chat scroll to bottom
*/
scrollToBottom = () => {
try {
this.content.nativeElement.scrollTop = this.content.nativeElement.scrollHeight;
} catch (err) { }
}
/**
* Filter Chat
*
* @param event search event
*/
updateFilter(event) {
const value = event.target.value.toLowerCase();
this.chatsList = [...this.temp2]; // and here you have to initialize it with your data
this.temp = [...this.chatsList];
// filter our data
const temp = this.chatsList.filter(function (d) {
return d.name.toLowerCase().indexOf(value) !== -1 || !value;
});
// update the rows
this.chatsList = temp;
// Whenever the filter changes, always go back to the first page
}
updateFilter1(event) {
const value = event.target.value.toLowerCase();
this.contactList = [...this.temp3]; // and here you have to initialize it with your data
this.temp = [...this.contactList];
// filter our data
const temp = this.contactList.filter(function (d) {
return d.name.toLowerCase().indexOf(value) !== -1 || !value;
});
// update the rows
this.contactList = temp;
// Whenever the filter changes, always go back to the first page
}
/**
* Send message
*/
sendMessage() {
if (this.newMessage !== null && this.newMessage !== '') {
this.contactChat.push({
message: [this.newMessage],
sender: 0,
senderImage: '',
time: '3:35AM',
});
this.newMessage = null;
}
}
/**
* Message send on Enter
*
* @param value New message
*/
onEnter(value: string) {
this.newMessage = value;
if (this.newMessage !== null && this.newMessage !== '') {
this.contactChat.push({
message: [this.newMessage],
sender: 0,
senderImage: '',
time: '3:35AM'
});
this.newMessage = null;
}
}
/**
* Display chat when click on contact
*
* @param friendId Friend id
*/
showChat(friendId, number) {
this.contactChat = [];
if (number === 1) {
for (let i = 0; i < this.chatsList.length; i++) {
if (friendId !== this.chatsList[i].friendId) {
this.chatsList[i].isSelected = false;
}
if (friendId === this.chatsList[i].friendId) {
this.chatsList[i].isSelected = true;
}
}
for (let i = 0; i < this.contactList.length; i++) {
this.contactList[i].isSelected = false;
}
for (const friend of this.chatsList) {
if (friend.friendId === friendId) {
this.contactChat = this.chatArray[friendId - 1].ChatHistory;
this.headerChat = this.chatArray[friendId - 1].chatHeader;
break;
}
}
} else if (number === 2) {
for (let i = 0; i < this.contactList.length; i++) {
if (friendId !== this.contactList[i].friendId) {
this.contactList[i].isSelected = false;
}
if (friendId === this.contactList[i].friendId) {
this.contactList[i].isSelected = true;
}
}
for (let i = 0; i < this.chatsList.length; i++) {
this.chatsList[i].isSelected = false;
}
this.contactChat = [];
this.headerChat = this.headerArray[friendId - 1].contactHeader;
}
}
/**
* Overlay add/remove fuction in responsive
*
* @param event Overlay click event
*/
contentOverlay(event) {
const toggleIcon = document.getElementById('chat-overlay1');
const toggle = document.getElementById('chat-area d-none');
if (event.currentTarget.className === 'chatSidebar ng-star-inserted') {
this.renderer.addClass(toggleIcon, 'd-none');
this.renderer.removeClass(toggle, 'd-none');
}
}
/**
* Warning add/remove class
*
* @param event click event
*/
chatFavorite(event) {
const chatIcon = document.getElementById('chat-icon');
if (event.currentTarget.className === 'chat-icon-favorite') {
this.renderer.addClass(chatIcon, 'warning');
} else if (event.currentTarget.className === 'chat-icon-favorite warning') {
this.renderer.removeClass(chatIcon, 'warning');
}
}
showContact(friendId) {
this.contactChat = [];
for (let i = 0; i < this.contactList.length; i++) {
if (friendId !== this.contactList[i].friendId) {
this.contactList[i].isSelected = false;
}
if (friendId === this.contactList[i].friendId) {
this.contactList[i].isSelected = true;
}
}
}
/**
* Show add/remove class at open profile
*
* @param event Overlay click event
*/
showProfile(event) {
const toggleIcon = document.getElementById('user-profile');
const toggle = document.getElementById('overlayChat');
if (event.currentTarget.className === 'chat-sidebar-profile-toggle') {
this.renderer.addClass(toggleIcon, 'show');
this.renderer.addClass(toggle, 'show');
} else if (event.currentTarget.className === 'chat-profile-close') {
this.renderer.removeClass(toggleIcon, 'show');
this.renderer.removeClass(toggle, 'show');
}
}
/**
* Show add/remove function in responsive
*
* @param event Overlay click event
*/
showSidebar(event) {
if (window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH) {
const toggleIcon = document.getElementById('sidebar-card');
const toggle = document.getElementById('overlayChat');
const toggleChat = document.getElementById('sidebar-left');
if (event.currentTarget.className === 'ficon feather ft-message-square chat-sidebar-toggle chat-start-icon font-large-3 p-3 mb-1' ||
'ficon feather ft-align-justify font-large-1 cursor-pointer') {
this.renderer.addClass(toggle, 'show');
this.renderer.addClass(toggleIcon, 'show');
}
if (window.innerWidth < AppConstants.MOBILE_RESPONSIVE_WIDTH) {
this.renderer.removeClass(toggleChat, 'sidebar-fixed');
}
}
}
/**
* Show add/remove function in responsive
*
* @param event Overlay click event
*/
Sidebar(event) {
const toggleChat = document.getElementById('sidebar-card');
const toggleIcon = document.getElementById('chat-profile');
const toggle = document.getElementById('overlayChat');
if (event.currentTarget.className === 'chat-sidebar-close' || 'chat-overlay show') {
this.renderer.removeClass(toggle, 'show');
this.renderer.removeClass(toggleChat, 'show');
this.renderer.removeClass(toggleIcon, 'show');
}
}
/**
* Show add/remove function
*
* @param event Overlay click event
*/
ShowChatProfile(event) {
const toggleIcon = document.getElementById('chat-profile');
const toggle = document.getElementById('overlayChat');
if (event.currentTarget.className === 'avatar chat-profile-toggle m-0 mr-1') {
this.renderer.addClass(toggleIcon, 'show');
this.renderer.addClass(toggle, 'show');
}
}
/**
* Show add/remove function
*
* @param event Overlay click event
*/
ChatProfile(event) {
const toggleIcon = document.getElementById('chat-profile');
const toggle = document.getElementById('overlayChat');
if (event.currentTarget.className === 'chat-profile-close') {
this.renderer.removeClass(toggleIcon, 'show');
this.renderer.removeClass(toggle, 'show');
}
}
}

View File

@@ -0,0 +1,89 @@
<div class="app-content content">
<div class="sidebar-left sidebar-fixed" fxFlex="auto" [perfectScrollbar]="config" id="sidebar-left">
<div class="sidebar">
<div class="sidebar-content card">
<div class="card-body chat-fixed-search">
<fieldset class="form-group position-relative has-icon-left m-0">
<input type="text" class="form-control" id="iconLeft" placeholder="Search user"
(keyup)='updateFilter($event)'>
<div class="form-control-position">
<i class="feather ft-search"></i>
</div>
</fieldset>
</div>
<div id="users-list" class="list-group position-relative">
<div class="users-list-padding media-list">
<a [routerLink]="" class="media _media" *ngFor="let chats of contactList"
(click)="showChat(chats.friendId)" id="_media" [ngClass]="{'active':chats.isSelected === true, '':chats.isSelected === false}">
<div class="media-left pr-1">
<span class="avatar avatar-md avatar-{{chats.isactive}}"><img class="media-object rounded-circle"
[src]="chats.image" alt="avatar"><i></i></span></div>
<i></i>
<div class="imagename media-body w-100">
<h6 class="list-group-item-heading">{{chats.name}}<span
class="font-small-3 float-right info">{{chats.time}}</span>
</h6>
<p class="list-group-item-text text-muted mb-0">
<i class="feather ft-check primary font-small-2"></i>{{chats.showMessage}}
<span class="float-right primary">
<i class="font-medium-1 icon-pin blue-grey lighten-3" *ngIf="chats.showicon"></i>
</span>
<span class="float-right primary">
<i class="font-medium-1 icon-volume-off blue-grey lighten-3 mr-1" *ngIf="chats.isicon "></i>
<span class="badge badge-pill badge-danger">{{chats.badge}}</span>
</span>
</p>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
<div class="content-right">
<div class="content-wrapper">
<div class="content-header"></div>
<div class="content-body">
<div class="content-overlay" id='content-overlay' (click)="contentOverlay($event)"></div>
<section class="chat-app-window" #content>
<div class="sidebar-toggle d-block d-lg-none" (click)="sidebar($event)"><i class="feather ft-menu font-large-1"></i></div>
<div class="badge badge-secondary mb-1">Chat History</div>
<div class="chats" #messages>
<div class="chat" [ngClass]="{'chat-right': messages.sender == 0 , 'chat-left': messages.sender == 1 }"
*ngFor="let messages of contactChat">
<div class="chat-avatar">
<a [routerLink]="" class="avatar">
<span class="avatar-online"><img [src]="messages.senderImage" /></span>
</a>
</div>
<div class="chat-body">
<div class="chat-content">
<p>{{messages.message}}</p>
</div>
</div>
</div>
</div>
</section>
<section class="chat-app-form">
<form class="chat-app-input d-flex">
<fieldset class="form-group position-relative has-icon-left col-10 m-0">
<div class="form-control-position">
<i class="icon-emoticon-smile"></i>
</div>
<input type="text" class="form-control" [(ngModel)]="newMessage" name="newmessage" id="iconLeft4"
placeholder="Type your message" #box (keyup.enter)="onEnter(box.value)">
<div class="form-control-position control-position-right">
<i class="feather ft-image"></i>
</div>
</fieldset>
<fieldset class="form-group position-relative has-icon-left col-2 m-0">
<button type="button" class="btn btn-primary" (click)="sendMessage()" keyboardShouldPersistTaps={true}><i
class="la la-paper-plane-o d-lg-none"></i><span class="d-none d-lg-block">Send</span></button>
</fieldset>
</form>
</section>
</div>
</div>
</div>
</div>
<!-- ////////////////////////////////////////////////////////////////////////////-->

View File

@@ -0,0 +1,374 @@
.custom-file {
width: 440px;
margin-left: 15px;
}
.dropdown {
position: relative !important;
margin-left: 0px !important;
}
.dropdown-toggle::after {
content: none !important;
}
.favoriteChange:hover {
background: url("../../../../assets/images/raty/star-on.png");
}
:host ::ng-deep .datatable-icon-right:before {
font-family: 'icofont';
font-style: normal;
}
:host ::ng-deep .datatable-icon-skip:before {
font-family: 'icofont';
font-style: normal;
}
:host ::ng-deep .datatable-icon-left:before {
font-family: 'icofont';
font-style: normal;
}
:host ::ng-deep .datatable-icon-left:before {
content: "\2039";
font-size: x-large;
}
:host ::ng-deep .datatable-icon-prev:before {
content: "\00AB";
font-size: x-large;
}
:host ::ng-deep .datatable-icon-right:before {
content: "\203A";
font-size: x-large;
}
:host ::ng-deep .datatable-icon-skip:before {
content: "\00BB";
font-size: x-large;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-left,
.ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-right,
.ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-prev {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-right,
.ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-right {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-skip {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-prev {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host ::ng-deep .datatable-footer .datatable-pager ul li:not(.disabled).active a,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] ul[_ngcontent-c11] li[_ngcontent-c11]:not(.disabled):hover a[_ngcontent-c11] {
background-color: #d4d2e7;
font-weight: bold;
font-size: larger;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager a {
height: 32px;
min-width: 34px;
line-height: 22px;
padding: 0;
border-radius: 3px;
margin: 0 3px;
text-align: center;
vertical-align: top;
padding-top: 3px;
text-decoration: none;
vertical-align: bottom;
color: #7c8091;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-left,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-prev[_ngcontent-c11] {
font-size: 14px;
line-height: 9px;
padding: 0px 08px;
background-color: #ffffff;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-left,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-right,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-skip,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-prev,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager ul li:not(.disabled):hover a {
background-color: #545454;
font-weight: bold;
color: white;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager ul li:not(.disabled).active a,
.ngx-datatable.bootstrap .datatable-footer .datatable-pager ul li:not(.disabled):hover a {
background-color: #545454;
font-weight: bold;
color: white;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #727e8e;
color: #ededed;
margin-top: -1px;
overflow: inherit;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header .datatable-header-cell .datatable-header-cell-label {
font-weight: bold;
line-height: 24px;
font-size: medium;
color: #6b6f82;
}
:host ::ng-deep .cotnblck img {
vertical-align: middle
}
@media only screen and (max-width: 767px) {
:horizontal.app-contacts .sidebar-left.show {
margin-left: 0rem !important;
}
}
:host ::ng-deep .heading-elements .gap_contact {
margin-right: 0.2rem;
}
:host ::ng-deep .image-name-space {
margin-right: 8px;
}
:host ::ng-deep .datatable-row-center,
:host ::ng-deep .datatable-header-inner,
:host ::ng-deep .datatable-row-wrapper,
:host ::ng-deep .datatable-body-row.datatable-row-even,
:host ::ng-deep .datatable-scroll,
:host ::ng-deep .datatable-body-row.datatable-row-odd,
:host ::ng-deep .datatable-footer,
:host ::ng-deep .datatable-footer-inner {
width: 100% !important;
}
:host ::ng-deep .datatable-body-cell-label,
:host ::ng-deep .datatable-header-cell {
padding: 0.6rem;
}
:host ::ng-deep .datatable-body-row {
padding: 0 !important
}
:host ::ng-deep .mrless {
margin-right: 0.4rem !important
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
font-weight: bold;
height: unset !important;
overflow: inherit;
}
:host ::ng-deep .ngx-datatable.bootstrap {
font-size: 14px;
}
:host ::ng-deep .datatable-header-cell {
font-size: 13px
}
@media(max-width:767px) {
:host ::ng-deep .page-count,
:host ::ng-deep .datatable-pager {
flex: 1 1 100% !important
}
}
:host ::ng-deep .my-custom-cell {
padding: 0.1rem 1.4rem !important;
}
:host ::ng-deep .ngx-datatable .datatable-body-cell,
.ngx-datatable .datatable-header-cell {
line-height: 3.625;
}
:host ::ng-deep .avatar i {
position: absolute;
right: -2px;
bottom: 5px;
width: 10px;
height: 10px;
border: 2px solid white;
border-radius: 100%;
}
:host ::ng-deep .icon {
right: 0px;
left: 26px;
bottom: -1px !important;
width: 10px;
height: 10px;
border: 0px !important;
border: 2px solid white !important;
}
@media only screen and (max-width: 767px) {
.custom-file {
margin-left: 15px !important;
margin-right: 15px !important;
width: 282px !important;
}
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body .datatable-body-row.datatable-row-even {
background-color: rgba(0, 0, 0, 0);
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body .datatable-body-row {
border-top: none !important;
border-bottom: 1px solid #e3ebf3;
}
.avatar {
margin-right: 15px;
}
.dropdown-toggle::after {
font-family: 'LineAwesome';
font-size: .8rem;
position: relative;
top: 0;
right: 0;
margin: 0 .3em 0 0;
padding: 0 2px 0 6px;
content: '\f110' !important;
vertical-align: 0;
border: none !important;
}
.pr-1,
.px-1 {
padding-right: 0rem !important;
}
:host ::ng-deep .ngx-datatable .datatable-body .datatable-body-row>div {
color: #6b6f82 !important;
}
:host ::ng-deep .close:not(:disabled):not(.disabled):hover,
.close:not(:disabled):not(.disabled):focus {
outline: none !important;
}
.datatable-header-cell-template-wrap {
padding-top: 1rem !important;
}
._center {
padding-top: 1rem !important;
}
:host ::ng-deep .ngx-datatable {
display: -webkit-box;
}
:host ::ng-deep .empty-row {
padding-left: 1rem !important;
}
:host ::ng-deep .dropdown .dropdown-menu .space,
:host ::ng-deep .dropup .dropdown-menu .space {
padding: 10px 20px !important;
height: 38px;
line-height: 1.625;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body .datatable-body-row .datatable-body-cell {
padding: 0rem;
overflow-y: visible !important;
overflow-x: visible !important;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager {
padding: 0px 25px;
}
:host ::ng-deep .contacts-table{
padding-top: 30px;
padding-bottom: 35px;
}
:host ::ng-deep .ngx-datatable .datatable-footer .datatable-pager {
text-align: left !important;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body .datatable-body-row.active {
background-color: #FFF !important;
}
:host ::ng-deep .content-right {
width: calc(100% - -30px) !important;
}
::ng-deep ngb-modal-backdrop {
z-index: 1050 !important;
}

View File

@@ -0,0 +1,309 @@
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1"></div>
<div class="content-detached content-right">
<div class="content-body">
<div class="content-overlay" id='content-overlay' (click)="contentOverlay($event)"></div>
<section class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="bug-list-search">
<div class="bug-list-search-content">
<div class="sidebar-toggle d-block d-lg-none" (click)="sidebar($event)"><i
class="feather ft-menu font-large-1"></i></div>
<form action="">
<div class="position-relative">
<input type="text" id="search-contacts" class="form-control" placeholder="Search contacts..."
(keyup)='updateFilter($event)'>
<div class="form-control-position">
<i class="la la-search text-size-base text-muted la-rotate-270"></i>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="row">
<div class="col-12">
<div class="card">
<div class="card-head">
<div class="card-header">
<h4 class="card-title">All Contacts</h4>
<div class="heading-elements mt-0">
<button class="btn btn-primary btn-sm gap_contact"
(click)="addTableDataModal(addTableDataModalContent)">
<i class="d-md-none d-block feather ft-plus white"></i>
<span class="d-md-block d-none">Add Contacts</span></button>
<span ngbDropdown class="d-inline-block dropdown gap_contact" [placement]="placement">
<button id="btnSearchDrop1" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="true" class="btn btn-warning dropdown-toggle dropdown-menu-right btn-sm"
ngbDropdownToggle><i class="feather ft-download-cloud white"></i></button>
<div ngbDropdownMenu aria-labelledby="dropdownBasic1" class="mt-1">
<button class="dropdown-item"><i class="feather ft-upload"></i> Import</button>
<button class="dropdown-item"><i class="feather ft-download"></i> Export</button>
<button class="dropdown-item"><i class="feather ft-shuffle"></i> Find Duplicate</button>
</div>
</span>
<button class="btn btn-default btn-sm"><i class="feather ft-settings white"></i></button>
</div>
</div>
</div>
<div class="card-content">
<div class="card-body">
<!-- Task List table -->
<div class="row">
<div class="col-sm-12">
<button type="button" class="btn btn-danger" (click)="deleteCheckedRow()">Delete
All</button>
<span class="pull-right">
Search :
<input type='search'
style='padding:8px;margin:15px auto;width:200px;height: calc(1.875rem + 2px);border-radius: 0.21rem;border: 1px solid #babfc7;'
(keyup)='updateFilter($event)' /></span>
</div>
</div>
<ngx-datatable #table class="bootstrap row contacts-table" [rows]="rows" [columnMode]="'force'" [headerHeight]="50"
[footerHeight]="50" [rowHeight]="70" [limit]="5" [selected]="selected" [selectionType]="'checkbox'"
(select)='onSelectContact($event)' fxFlex="auto" [perfectScrollbar]="config">
<ngx-datatable-column [flexGrow]="1" [minWidth]="30" [maxWidth]="50">
<ng-template ngx-datatable-header-template let-value="value" let-allRowsSelected="allRowsSelected"
let-selectFn="selectFn">
<span class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="selectAll" [checked]="allRowsSelected"
(change)="selectFn(!allRowsSelected)" />
<label class="custom-control-label" for="selectAll"></label>
</span>
</ng-template>
<ng-template ngx-datatable-cell-template let-value="value" let-row="row" let-rowIndex="rowIndex"
let-onCheckboxChangeFn="onCheckboxChangeFn" let-isSelected="isSelected">
<div class="custom-control custom-checkbox _center">
<input type="checkbox" class="custom-control-input" id="select{{rowIndex}}"
[checked]="isSelected" (change)="onCheckboxChangeFn($event)" />
<label class="custom-control-label" for="select{{rowIndex}}"></label>
</div>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="Name" [flexGrow]="1" [minWidth]="140">
<ng-template ngx-datatable-cell-template let-row="row">
<span class="avatar avatar-sm avatar-{{row.isActive}} rounded-circle">
<img [src]="row.image"><i></i></span>{{row.name}}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="Email" [flexGrow]="1" [minWidth]="140">
<ng-template ngx-datatable-cell-template let-row="row">
<a [routerLink]="">{{row.email}}</a>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="Phone" [flexGrow]="1" [minWidth]="140"></ngx-datatable-column>
<ngx-datatable-column name="Favorite" [flexGrow]="1" [minWidth]="90" [cellClass]="'my-custom-cell'">
<ng-template ngx-datatable-cell-template let-row="row">
<img src="../../../assets/images/raty/star-off.png" class="favoriteChange"
*ngIf="!row.isFavorite" (click)="favoriteChange(row)">
<img src="../../../assets/images/raty/star-on.png" class="favoriteChange" *ngIf="row.isFavorite"
(click)="favoriteChange(row)">
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="Actions" [flexGrow]="1" [minWidth]="100">
<ng-template ngx-datatable-cell-template let-row="row">
<a [routerLink]="" class="primary edit mr-1 mrless"
(click)="editTableDataModal(editTableDataModalContent, row)"><i class="la la-pencil"></i>
</a>
<a class="danger delete mr-1 mrless"><i class="la la-trash-o" (click)="deleteRow(row)"></i></a>
<span class="dropdown" ngbDropdown placement="left">
<a [routerLink]="" id="btnSearchDrop27" ngbDropdownToggle id="dropdownBasic1"
class="mrless"><i class="la la-ellipsis-v"></i></a>
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
<a [routerLink]="" class="dropdown-item edit space"
(click)="editTableDataModal(editTableDataModalContent, row)"><i
class="feather ft-edit-2"></i>Edit</a>
<a [routerLink]="" class="dropdown-item delete space" (click)="deleteRow(row)"><i
class="feather ft-trash-2"></i> Delete</a>
<a [routerLink]="" class="dropdown-item space"><i class="feather ft-plus-circle primary"></i>
Projects</a>
<a [routerLink]="" class="dropdown-item space"><i class="feather ft-plus-circle info"></i>
Team</a>
<a [routerLink]="" class="dropdown-item space"><i class="feather ft-plus-circle warning"></i>
Clients</a>
<a [routerLink]="" class="dropdown-item space"><i class="feather ft-plus-circle success"></i>
Friends</a>
</div>
</span>
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
<div class="sidebar-detached sidebar-left" id="sidebar-left" fxFlex="auto" [perfectScrollbar]="config">
<div class="sidebar">
<div class="bug-list-sidebar-content">
<!-- Predefined Views -->
<div class="card">
<div class="card-head">
<div class="media p-1">
<div class="media-left pr-1"><span class="avatar avatar-sm avatar-online rounded-circle"><img
src="../../../assets/images/portrait/small/avatar-s-1.png" alt="avatar"><i
class="icon"></i></span></div>
<div class="media-body media-middle">
<h5 class="media-heading">Margaret Govan</h5>
</div>
</div>
</div>
<!-- contacts view -->
<div class="card-body border-top-blue-grey border-top-lighten-5">
<div class="list-group">
<a [routerLink]="" class="list-group-item active active">All Contacts</a>
<a [routerLink]="" class="list-group-item list-group-item-action">Recently contacted</a>
<a [routerLink]="" class="list-group-item list-group-item-action">Favorite contacts</a>
</div>
</div>
<!-- Groups-->
<div class="card-body">
<p class="lead">Groups</p>
<ul class="list-group">
<li class="list-group-item">
<span class="badge badge-primary badge-pill float-right">14</span> <a [routerLink]="" class="info">
Project</a>
</li>
<li class="list-group-item">
<span class="badge badge-info badge-pill float-right">22</span> <a [routerLink]="" class="info">
Team</a>
</li>
<li class="list-group-item">
<span class="badge badge-warning badge-pill float-right">10</span> <a [routerLink]="" class="info">
Clients</a>
</li>
<li class="list-group-item">
<span class="badge badge-success badge-pill float-right">5</span> <a [routerLink]="" class="info">
Friends</a>
</li>
</ul>
</div>
<!--/ Groups-->
<!--More-->
<div class="card-body ">
<p class="lead">More</p>
<ul class="list-group">
<a [routerLink]="" class="list-group-item info">Import</a>
<a [routerLink]="" class="list-group-item info">Export</a>
<a [routerLink]="" class="list-group-item info">Print</a>
<a [routerLink]="" class="list-group-item info">Restore contacts</a>
<a [routerLink]="" class="list-group-item info">Find duplicate</a>
</ul>
</div>
<!--/More-->
</div>
<!--/ Predefined Views -->
</div>
</div>
</div>
</div>
</div>
<!-- ////////////////////////////////////////////////////////////////////////////-->
<ng-template #editTableDataModalContent let-c="close" let-d="dismiss">
<form (ngSubmit)="onUpdate(editForm,selectedContact.id)" #editForm="ngForm">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Edit Contact</h5>
<button type="button" class="close" aria-label="Close" (click)="d('Cross click')">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group col-12">
<input type="text" [(ngModel)]="selectedContact.name" #editname="ngModel" name="name" id="name"
class="name form-control" placeholder="Name"
[ngClass]="{ 'is-invalid': editForm.submitted && editname.invalid }" required>
<div *ngIf="editForm.submitted && editname.invalid" class="invalid-feedback">
<div *ngIf="editname.errors.required">Name is required</div>
</div>
</div>
<div class="form-group col-12">
<input type="text" [(ngModel)]="selectedContact.email" #editemail="ngModel" name="email" id="email"
class="email form-control" placeholder="Email"
[ngClass]="{ 'is-invalid':editForm.submitted && editemail.invalid }" required email>
<div *ngIf="editForm.submitted && editemail.invalid" class="invalid-feedback">
<div *ngIf="editemail.errors.required">Email is required</div>
<div *ngIf="editemail.errors.email">Email must be a valid email address</div>
</div>
</div>
<div class="form-group col-12">
<input type="text" [(ngModel)]="selectedContact.phone" #editphone="ngModel" name="phone" id="phone"
class="phone form-control" placeholder="Phone Number" (keyup)="onFormat()" maxlength="14">
</div>
</div>
<div class="modal-footer">
<div class="form-group position-relative has-icon-left mb-0">
<button type="submit" id="edit-contact-item" class="btn btn-info edit-contact-item" data-dismiss="modal"><i
class="la la-paper-plane-o d-lg-none"></i> <span class="d-none d-lg-block">Edit</span></button>
</div>
</div>
</form>
</ng-template>
<ng-template #addTableDataModalContent let-c="close" let-d="dismiss">
<form (ngSubmit)="addNewContact(addForm)" #addForm="ngForm">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel1">Add New Contact</h5>
<button type="button" class="close" aria-label="Close" (click)="d('Cross click')">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group col-12">
<input type="text" [(ngModel)]="contactName" name="name" id="contact-name" class="contact-name form-control"
placeholder="Name" #contactname="ngModel"
[ngClass]="{ 'is-invalid': addForm.submitted && contactname.invalid }" required>
<div *ngIf="addForm.submitted && contactname.invalid" class="invalid-feedback">
<div *ngIf="contactname.errors.required">Name is required</div>
</div>
</div>
<div class="form-group col-12">
<input type="text" [(ngModel)]="contactEmail" name="email" id="contact-email" class="contact-email form-control"
placeholder="Email" #contactemail="ngModel"
[ngClass]="{ 'is-invalid':addForm.submitted && contactemail.invalid }" required email>
<div *ngIf="addForm.submitted && contactemail.invalid" class="invalid-feedback">
<div *ngIf="contactemail.errors.required">Email is required</div>
<div *ngIf="contactemail.errors.email">Email must be a valid email address</div>
</div>
</div>
<div class="form-group col-12">
<input type="text" [(ngModel)]="contactPhone" name="contactPhone" #contactphone="ngModel" id="contact-phone"
class="contact-phone form-control" placeholder="Phone Number" (keyup)="onFormat()" maxlength="14">
</div>
<div class="form-group col-12">
<span class="custom-control custom-checkbox">
<input type="checkbox" [(ngModel)]="contactFavorite" name="favorite" (change)="addFavoriteImage($event)"
id="favorite" class="contact-fav input-chk custom-control-input">
<label class="custom-control-label" for="favorite">Favorite</label>
</span>
</div>
<div class="custom-file form-group col-12">
<input type="file" class="custom-file-input" accept='contactImage/*' (change)="preview($event)" id="customFile">
<label class="custom-file-label">Choose Image</label>
</div>
</div>
<div class="modal-footer">
<div class="form-group position-relative has-icon-left mb-0">
<button type="submit" id="add-contact-item" class="btn btn-info add-contact-item"><i
class="la la-paper-plane-o d-lg-none"></i> <span class="d-none d-lg-block">Add
New</span></button>
</div>
</div>
</form>
</ng-template>

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ContactsComponent } from './contacts.component';
describe('ContactsComponent', () => {
let component: ContactsComponent;
let fixture: ComponentFixture<ContactsComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ ContactsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ContactsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,350 @@
import { Component, OnInit, ViewChild, EventEmitter, Output, Renderer2 } from '@angular/core';
import { NgForm } from '@angular/forms';
import { DatatableComponent } from '@swimlane/ngx-datatable';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
class Contact {
constructor(
public id: number,
public name: string,
public email: string,
public phone: string,
public image: any,
public isFavorite: boolean,
public isActive: string
) { }
}
@Component({
selector: 'app-contacts',
templateUrl: './contacts.component.html',
styleUrls: ['./contacts.component.css']
})
export class ContactsComponent implements OnInit {
columns: any = [];
contactName: any;
contactEmail: any;
contactPhone: any;
contactImage: any;
contactFavorite: boolean;
contactactive: string;
rows: any[] = [];
name = 'Angular';
public imagePath;
imgURL: any;
selectedContact: any;
contactFlag: boolean;
addContact: any;
placement = 'bottom-right';
imagepathdefault: any;
addModal = null;
editModal = null;
value: any;
loadingIndicator: true;
selected = [];
temp = [];
temp2 = this.rows;
public config: PerfectScrollbarConfigInterface = { };
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective) directiveRef?: PerfectScrollbarDirective;
@Output() closeModalEvent = new EventEmitter<boolean>();
@ViewChild(DatatableComponent, { static: true }) table: DatatableComponent;
/**
* Constructor
*
* @param NgbModal modal;
* @param Renderer2 _renderer
*/
constructor(
private modal: NgbModal,
private _renderer: Renderer2
) { }
/**
* OnInit
*/
ngOnInit() {
this.rows.push(new Contact(1, 'Scott Marsh', 'scott@gmail.com', '(954)-654-5641',
'../../../assets/images/portrait/small/avatar-s-5.png', false, 'online'));
this.rows.push(new Contact(2, 'Russell Bry', 'russell@gmail.com', '(235)-654-5642',
'../../../assets/images/portrait/small/avatar-s-3.png', false, 'busy'));
this.rows.push(new Contact(3, 'james john', 'john@gmail.com', '(125)-654-5643',
'../../../assets/images/portrait/small/avatar-s-1.png', true, 'away'));
this.rows.push(new Contact(4, 'Cynth Tuck', 'tuck@gmail.com', '(974)-654-5644',
'../../../assets/images/portrait/small/avatar-s-4.png', false, 'busy'));
this.rows.push(new Contact(5, 'Margi Govan', 'govan@gmail.com', '(954)-654-5645',
'../../../assets/images/portrait/small/avatar-s-6.png', true, 'online'));
this.rows.push(new Contact(6, 'Eugene Wood', 'wood@gmail.com', '(987)-654-5646',
'../../../assets/images/portrait/small/avatar-s-9.png', false, 'busy'));
this.rows.push(new Contact(7, 'Eric Marshall', 'eric@gmail.com', '(545)-654-5647',
'../../../assets/images/portrait/small/avatar-s-7.png', false, 'online'));
}
/**
* Add new contact
*
* @param addTableDataModalContent Id of the add contact modal;
*/
addTableDataModal(addTableDataModalContent) {
this.addModal = this.modal.open(addTableDataModalContent, {
windowClass: 'animated fadeInDown'
});
this.contactFlag = true;
}
/**
* Edit selected contact row.
*
* @param editTableDataModalContent Id of the edit contact model.
* @param row The row which needs to be edited.
*/
editTableDataModal(editTableDataModalContent, row) {
this.selectedContact = Object.assign({}, row);
this.editModal = this.modal.open(editTableDataModalContent, {
windowClass: 'animated fadeInDown'
});
this.contactFlag = false;
}
/**
* Selected contact
*
* @param selected Selected contact;
*/
onSelectContact({ selected }) {
this.selected.splice(0, this.selected.length);
this.selected.push(...selected);
}
/**
* Search contact from contact table
*
* @param event Convert value uppercase to lowercase;
*/
updateFilter(event) {
const val = event.target.value.toLowerCase();
this.rows = [...this.temp2];
this.temp = [...this.rows];
const temp = this.rows.filter(function (d) {
return d.name.toLowerCase().indexOf(val) !== -1 || !val;
});
this.rows = temp;
this.table.offset = 0;
}
/**
* Choose contact image
*
* @param event Select contact image;
*/
preview(event) {
const reader = new FileReader();
reader.onload = (e: any) => {
this.contactImage = e.target.result;
};
reader.readAsDataURL(event.target.files[0]);
}
/**
* Delete contact row
* @param row Selected row for delete contact
*/
deleteRow(row) {
let index = 0;
const temp = [...this.rows];
for (const tempRow of temp) {
if (tempRow.id === row.id) {
temp.splice(index, 1);
break;
}
index++;
}
this.rows = temp;
}
/**
* Update contact details
*
* @param editForm Edit form for values check
* @param id Id match to the selected row Id
*/
onUpdate(editForm: NgForm, id) {
for (const row of this.rows) {
if (row.id === id && editForm.valid === true) {
row.name = this.selectedContact['name'];
row.email = this.selectedContact['email'];
row.phone = this.selectedContact['phone'];
this.editModal.close(editForm.resetForm);
break;
}
}
}
/**
* Contact changed to favorite or non-favorite
*
* @param row Row of the favorite contact
*/
favoriteChange(row) {
if (row.isFavorite) {
row.isFavorite = row.isFavorite ? false : true;
} else {
row.isFavorite = true;
}
}
/**
* Delete selected contact
*/
deleteCheckedRow() {
let index = 0;
const removedIndex = [];
const temp = [...this.rows];
for (const row of temp) {
for (const selectedRow of this.selected) {
if (row.id === selectedRow.id) {
removedIndex.push(index);
}
}
index++;
}
for (let i = removedIndex.length - 1; i >= 0; i--) {
temp.splice(removedIndex[i], 1);
}
this.rows = temp;
this.selected = [];
}
/**
* favorite set when add contact
*
* @param event favorite set on click event
*/
addFavoriteImage(event) {
if (event.target.checked === true) {
this.contactFavorite = true;
} else {
this.contactFavorite = false;
}
}
/**
* New contact add to the table
*
* @param addForm Add contact form
*/
addNewContact(addForm: NgForm) {
if (this.contactImage == null) {
this.contactImage = '../../../assets/images/portrait/small/default.png';
} else {
this.contactImage = this.contactImage;
}
if (this.contactactive === undefined) {
this.contactactive = 'away';
} else {
this.contactactive = this.contactactive;
}
/**
* Add contact if valid addform value
*/
if (addForm.valid === true) {
this.rows.push(
new Contact(
this.rows.length + 1,
this.contactName,
this.contactEmail,
this.contactPhone,
this.contactImage,
this.contactFavorite,
this.contactactive
)
);
this.rows = [...this.rows];
addForm.reset();
this.addModal.close(addForm.resetForm);
}
}
/**
* Set the phone number format
*/
onFormat() {
if (this.contactFlag === true) {
this.value = this.contactPhone;
} else if (this.contactFlag === false) {
this.value = this.selectedContact['phone'];
}
let country, city, number;
switch (this.value.length) {
case 6:
country = 1;
city = this.value.slice(0, 3);
number = this.value.slice(3);
break;
case 7:
country = this.value[0];
city = this.value.slice(1, 4);
number = this.value.slice(4);
break;
case 8:
country = this.value.slice(0, 3);
city = this.value.slice(3, 5);
number = this.value.slice(5);
break;
default:
return this.value;
}
if (country === 1) {
country = '';
}
number = number.slice(0, 3) + '-' + number.slice(3);
const no = '(' + city + ')' + '-' + number;
if (this.contactFlag === true) {
this.contactPhone = no;
} else if (this.contactFlag === false) {
this.selectedContact['phone'] = no;
}
}
/**
* Sidebar open/close in responsive
*
* @param event Sidebar open/close
*/
sidebar(event) {
const toggleIcon = document.getElementById('sidebar-left');
const toggle = document.getElementById('content-overlay');
if (event.currentTarget.className === 'sidebar-toggle d-block d-lg-none') {
this._renderer.addClass(toggleIcon, 'show');
this._renderer.addClass(toggle, 'show');
}
}
/**
* Overlay add/remove fuction in responsive
*
* @param event Overlay click event
*/
contentOverlay(event) {
const toggleIcon = document.getElementById('sidebar-left');
const toggle = document.getElementById('content-overlay');
if (event.currentTarget.className === 'content-overlay show') {
this._renderer.removeClass(toggleIcon, 'show');
this._renderer.removeClass(toggle, 'show');
}
}
}

View File

@@ -0,0 +1,13 @@
import { ContactsModule } from './contacts.module';
describe('ContactsModule', () => {
let contactsModule: ContactsModule;
beforeEach(() => {
contactsModule = new ContactsModule();
});
it('should create an instance', () => {
expect(contactsModule).toBeTruthy();
});
});

View File

@@ -0,0 +1,29 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ContactsComponent } from './contacts.component';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
@NgModule({
imports: [
CommonModule,
NgxDatatableModule,
BreadcrumbModule,
FormsModule,
NgbModule,
PerfectScrollbarModule,
RouterModule.forChild([
{
path: '',
component: ContactsComponent
}
])
],
declarations: [ContactsComponent],
exports: [RouterModule]
})
export class ContactsModule { }

View File

@@ -0,0 +1,169 @@
:host ::ng-deep .mr-50, .mx-50 {
margin-right: .5rem!important;
}
:host ::ng-deep .mr-25, .mx-25 {
margin-right: .25rem!important;
}
:host ::ng-deep .pr-50, .px-50 {
padding-right: .5rem!important;
}
:host ::ng-deep .content-right .email-app-list-wrapper .email-app-list .email-user-list .users-list-wrapper li {
border-top: 1px solid #E4E5EC !important;
}
:host ::ng-deep .app-content .content-right {
width: calc(100% - 300px) !important;
background-color: #fff;
}
@media (max-width: 768px){
.app-content .content-right {
width: calc(100% - 0px) !important;
background-color: #fff;
}
}
:host ::ng-deep .ps__thumb-y {
background-color: #aaa;
border-radius: 6px;
position: absolute;
}
:host ::ng-deep .content-right .email-app-details .email-scroll-area {
overflow-x: hidden !important;
}
:host ::ng-deep .d-block {
text-align: left;
}
:host ::ng-deep .d-flex {
display: flex!important;
}
:host ::ng-deep .btn-link {
font-weight: 400;
color:#6b6f82 !important;
text-decoration: none;
}
:host ::ng-deep .email-detail-head .collapse-header .card-header {
background-color: transparent !important;
}
:host ::ng-deep .py-1 {
background-color: #f4f5fa;
}
:host ::ng-deep .ps {
overflow: hidden!important;
}
:host ::ng-deep .content.app-content {
overflow-y: hidden !important;
}
:host ::ng-deep .tagDropdown {
transform: translate3d(-118px, -16px, 0px) !important;
top: 8px;
}
@media (max-width: 768px){
.tagDropdown {
transform: translate3d(-98px, -64px, 0px) !important;
top: 8px;
}
}
:host ::ng-deep .listDropdown {
transform: translate3d(-123px, 30px, 0px) !important;
}
@media (max-width: 768px){
.listDropdown {
transform: translate3d(-88px, -65px, 0px) !important;
top: 8px;
}
}
:host ::ng-deep .taglistDropdown {
transform: translate3d(-123px, -8px, 0px) !important;
}
@media (max-width: 768px){
.taglistDropdown {
transform: translate3d(-124px, -65px, 0px) !important;
top: 8px;
}
}
:host ::ng-deep .dropdown .dropdown-menu .dropdown-item {
padding: 10px 17px !important;
}
:host ::ng-deep .bg-1{
background-color: #666ee8;
}
:host ::ng-deep .badge {
display: inline-block;
padding: .35em .4em;
font-size: 80%;
text-align: center;
vertical-align: baseline;
border-radius: .25rem;
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
}
:host ::ng-deep .badge-pill {
padding-right: .6em;
padding-left: .6em;
border-radius: 10rem;
}
:host ::ng-deep .show>.inboxDropdown {
transform: translate3d(-118px, 30px, 0px) !important;
}
@media (max-width: 768px){
.show>.inboxDropdown {
transform: translate3d(-106px, -65px, 0px) !important;
}
}
:host ::ng-deep .app-content .sidebar .email-app-sidebar {
width: 300px !important;
}
:host ::ng-deep .emailtoolbar {
float: right;
margin-bottom: 12px;
display: initial;
}
:host ::ng-deep .app-content .quill-wrapper .snow-container .send-btn {
height: 38px;
}
:host ::ng-deep .ql-editor {
overflow-y: initial !important;
padding: 0px 0px !important;
}
:host ::ng-deep .gradient-mint {
background-image: linear-gradient(45deg,#28d094,#28d094)!important;
width: 10px !important;
height: 10px !important;
}
:host ::ng-deep .gradient-primary{
background-image: linear-gradient(45deg,#666ee8,#666ee8)!important;
width: 10px !important;
height: 10px !important;
}
:host ::ng-deep .gradient-warning {
background-image: linear-gradient(45deg,#ff9149,#ff9149)!important;
width: 10px !important;
height: 10px !important;
}
:host ::ng-deep .gradient-danger {
background-image: linear-gradient(45deg,#ff4961,#ff4961)!important;
width: 10px !important;
height: 10px !important;
}
:host ::ng-deep .gradient-info {
background-image: linear-gradient(45deg,#1e9ff2,#1e9ff2)!important;
width: 10px !important;
height: 10px !important;
}
:host ::ng-deep .list-group .list-group-messages :hover {
color: #0c84d1 !important;
}
:host ::ng-deep .mr-75, .mx-75 {
margin-right: .75rem!important;
}
.list-inline-item:not(:last-child) {
margin-right: 0.7rem !important;
}
@media (max-width: 768px){
.list-inline-item:not(:last-child) {
margin-right: 0.25rem !important;
}
}

View File

@@ -0,0 +1,527 @@
<div class="app-content content">
<div class="sidebar-left" id="sidebar-left">
<div class="sidebar">
<div class="sidebar-content email-app-sidebar d-flex">
<!-- sidebar close icon -->
<span class="sidebar-close-icon" (click)="showSidebar($event) ">
<i class="ficon feather ft-x"></i>
</span>
<!-- sidebar close icon -->
<div class="email-app-menu">
<div class="form-group form-group-compose">
<!-- compose button -->
<button type="button" class="btn btn-danger btn-glow btn-block my-2 compose-btn" id="compose-btn"
(click)="showComposeSidebar($event)">
<i class="ficon feather ficon feather ft-plus"></i>
Compose
</button>
</div>
<div class="sidebar-menu-list" fxFlex="auto" [perfectScrollbar]="config">
<!-- sidebar menu -->
<div class="list-group list-group-messages" *ngFor="let email of emailMenuList">
<a class="list-group-item" id="inbox-menu" (click)="showEmailMenu(email.Id, emailMenuList)"
[ngClass]="{'active':email.isSelected === true, '':email.isSelected === false}">
<div class="d-inline mr-25">
<i class="{{email.icon}}"></i>
</div>
{{email.name}}
<span class="{{email.budgeClass}}">{{email.budge}}</span>
</a>
</div>
<!-- sidebar menu end-->
<!-- sidebar label start -->
<label class="sidebar-label">Labels</label>
<div class="list-group list-group-labels " *ngFor="let email of emailLable">
<a [routerLink]="" class="list-group-item d-flex justify-content-between align-items-center"
(click)="showEmailMenu(email.Id, emailLable)"
[ngClass]="{'active':email.isSelected === true, '':email.isSelected === false}">
{{email.name}}
<span class="{{email.bulletClass}} d-inline-block rounded-circle "></span>
</a>
</div>
<!-- sidebar label end -->
</div>
</div>
</div>
<!-- User new mail right area -->
<div class="compose-new-mail-sidebar" id="compose-sidebar" fxFlex="auto" [perfectScrollbar]="config">
<div class="card mb-0 shadow-none quill-wrapper p-0">
<div class="card-header">
<h3 class="card-title" id="emailCompose">New Message</h3>
<button type="button" class="close close-icon" id="showCompose" (click)="showCompose($event)">
<i class="ficon feather ft-x"></i>
</button>
</div>
<!-- form start -->
<form action="" id="compose-form">
<div class="card-content">
<div class="card-body pt-0">
<div class="form-group pb-50">
<label for="emailfrom">from</label>
<input type="text" id="emailfrom" class="form-control" placeholder="user@example.com" disabled>
</div>
<div class="form-label-group mb-1">
<input type="email" id="emailTo" class="form-control" placeholder="To" required>
</div>
<div class="form-label-group mb-1">
<input type="text" id="emailSubject" class="form-control" placeholder="Subject">
</div>
<div class="form-label-group mb-1">
<input type="text" id="emailCC" class="form-control" placeholder="CC">
</div>
<div class="form-label-group mb-1">
<input type="text" id="emailBCC" class="form-control" placeholder="BCC">
</div>
<!-- Compose mail Quill editor -->
<div class="snow-container border rounded p-50 ">
<section class="default-editor">
<div class="row">
<div class="col-12">
<div class="snow-container border rounded p-50">
<quill-editor [styles]="{height: '80px'}" [modules]="quillConfig" (onFocus)="focus()"
(onBlur)="blur()" ></quill-editor>
<!-- <div class="toolbar1">
<button class="ql-bold">Bold</button>
<button class="ql-italic">Italic</button>
<button class="ql-underline">Underline</button>
<button class="ql-strike">Strike</button>
</div> -->
</div>
</div>
</div>
</section>
</div>
<div class="form-group mt-2">
<div class="custom-file">
<input type="file" class="custom-file-input" id="emailAttach">
<label class="custom-file-label" for="emailAttach">Attach file</label>
</div>
</div>
</div>
</div>
<div class="card-footer border-0 d-flex justify-content-end pt-0">
<button type="reset" class="btn btn-secondary cancel-btn mr-1" (click)="showCompose($event)">
<i class='ficon feather ft-x mr-25'></i>
<span class="d-sm-inline d-none">Cancel</span>
</button>
<button type="submit" class="btn-send btn btn-danger btn-glow">
<i class='ficon feather ft-play mr-25'></i> <span class="d-sm-inline d-none">Send</span>
</button>
</div>
</form>
<!-- form start end-->
</div>
</div>
<!--/ User Chat profile right area -->
</div>
</div>
<div class="content-right">
<div class="content-header row">
</div>
<div class="content-overlay"></div>
<div class="content-wrapper">
<div class="content-body">
<!-- email app overlay -->
<div class="app-content-overlay" id="app-content-overlay" (click)="showCompose($event)"
(click)="showSidebar($event)"></div>
<div class="email-app-area">
<!-- Email list Area -->
<div class="email-app-list-wrapper">
<div class="email-app-list">
<div class="email-action">
<!-- action left start here -->
<div class="action-left d-flex align-items-center">
<div class="custom-control custom-checkbox selectAll mr-50">
<input type="checkbox" class="custom-control-input" id="selectAll" [(ngModel)]="selectAll"
(click)="selectAllEmails();">
<label class="custom-control-label" for="selectAll"></label>
</div>
<!-- delete unread dropdown -->
<ul class="list-inline m-0 d-flex">
<li class="list-inline-item mail-delete">
<button type="button" class="btn btn-icon action-icon" (click)="deleteCheckedRow()">
<i class="ficon feather ft-trash-2"></i>
</button>
</li>
<li class="list-inline-item mail-unread">
<button type="button" class="btn btn-icon action-icon">
<i class="ficon feather ft-mail"></i>
</button>
</li>
<li class="list-inline-item">
<div class="dropdown">
<div ngbDropdown [open]="false" [autoClose]="true" class="d-inline-block">
<button type="button" class="dropdown-toggle btn btn-icon action-icon" id="folder"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" id="dropdownMenuButton"
dropdown-menu dropdown-menu-right show data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false" role="menu" ngbDropdownToggle>
<i class="ficon feather ft-folder mr-0"></i>
</button>
<div ngbDropdownMenu="dropdownMenuButton" class="dropdown-menu dropdown-menu-right inboxDropdown" >
<a class="dropdown-item" [routerLink]=""><i class="ficon feather ft-edit"></i>Draft</a>
<a class="dropdown-item" [routerLink]=""><i class="ficon feather ft-info"></i>Spam</a>
<a class="dropdown-item" [routerLink]=""><i class="ficon feather ft-trash-2"></i>Trash</a>
</div>
</div>
</div>
</li>
<li class="list-inline-item">
<div class="dropdown">
<div ngbDropdown [open]="false" [autoClose]="true" class="d-inline-block">
<button type="button" class="btn btn-icon dropdown-toggle action-icon" id="tag"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" id="dropdownMenuButton"
ropdown-menu dropdown-menu-right show data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false" role="menu" ngbDropdownToggle>
<i class="ficon feather ft-tag mr-0"></i>
</button>
<div aria-labelledby="tag">
<div ngbDropdownMenu="dropdownMenuButton" class="tagDropdown" >
<a [routerLink]="" class="dropdown-item align-items-center">
<span class="bullet bullet-sm gradient-mint d-inline-block rounded-circle "></span>
<span>Product</span>
</a>
<a [routerLink]="" class="dropdown-item align-items-center">
<span class="bullet bullet-sm gradient-primary d-inline-block rounded-circle "></span>
<span>Work</span>
</a>
<a [routerLink]="" class="dropdown-item align-items-center">
<span class="bullet bullet-sm gradient-warning d-inline-block rounded-circle "></span>
<span>Misc</span>
</a>
<a [routerLink]="" class="dropdown-item align-items-center">
<span class="bullet bullet-sm gradient-danger d-inline-block rounded-circle "></span>
<span>Family</span>
</a>
<a [routerLink]="" class="dropdown-item align-items-center">
<span class="bullet bullet-sm gradient-info d-inline-block rounded-circle "></span>
<span> Design</span>
</a>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
<!-- action left end here -->
<!-- action right start here -->
<div class="action-right d-flex flex-grow-1 align-items-center justify-content-around">
<!-- search bar -->
<div class="email-fixed-search flex-grow-1">
<div class="sidebar-toggle d-block d-lg-none" (click)="showSidebar($event)">
<i class="ficon feather ft-align-justify"></i>
</div>
<fieldset class="form-group position-relative has-icon-left m-0">
<input type="text" class="form-control" id="email-search" (keyup)="search($event)"
placeholder="Search email">
<div class="form-control-position">
<i class="ficon feather ft-search"></i>
</div>
</fieldset>
</div>
<!-- pagination and page count -->
<span class="d-none d-sm-block">1-10 of 653</span>
<button class="btn btn-icon email-pagination-prev d-none d-sm-block">
<i class="ficon feather ft-chevron-left"></i>
</button>
<button class="btn btn-icon email-pagination-next d-none d-sm-block">
<i class="ficon feather ft-chevron-right"></i>
</button>
</div>
</div>
<!-- / action right -->
<!-- email user list start -->
<div class="email-user-list list-group" [perfectScrollbar]="config">
<ul class="users-list-wrapper media-list">
<li class="{{contact.mediaClass}}" *ngFor="let contact of emailList; let i = index">
<div class="user-action">
<div class="checkbox-con mr-25">
<div class="custom-control custom-checkbox">
<input type="checkbox" [(ngModel)]="contact.isSelected" class="custom-control-input"
id="checkboxsmall{{i}}">
<label class="custom-control-label" for="checkboxsmall{{i}}"></label>
</div>
</div>
<span class="{{contact.starClass}}" [attr.id]="'emailstar-icon' + contact.emailId" (click)="emailFavorite($event,contact.emailId)">
<i class="{{contact.starIcon}}"></i>
</span>
</div>
<div class="pr-50">
<div class="avatar">
<img [src]="contact.image" alt="avtar img holder">
</div>
</div>
<div class="media-body" (click)="showEmail($event)">
<div class="user-details">
<div class="mail-items">
<span class="list-group-item-text text-truncate">{{contact.title}}</span>
</div>
<div class="mail-meta-item">
<span class="float-right">
<span class="mail-date">{{contact.time}}</span>
</span>
</div>
</div>
<div class="mail-message">
<p class="list-group-item-text truncate mb-0">
{{contact.message}}
</p>
<div class="mail-meta-item">
<span class="float-right">
<i class="ficon feather ft-paperclip mr-50" *ngIf="contact.showicon"></i>
<span class="bullet bullet-sm {{contact.bullet}} d-inline-block rounded-circle"></span>
</span>
</div>
</div>
</div>
</li>
</ul>
<!-- email user list end -->
<!-- no result when nothing to show on list -->
<div class="no-results">
<i class="ficon feather ft-info font-large-2"></i>
<h5>No Items Found</h5>
</div>
</div>
</div>
</div>
<!--/ Email list Area -->
<!-- Detailed Email View -->
<div class="email-app-details" id="app-details">
<!-- email detail view header -->
<div class="email-detail-header">
<div class="email-header-left d-flex align-items-center mb-1">
<span class="go-back mr-50">
<i class="ficon feather ft-chevron-left font-medium-4 align-middle" (click)="showEmail($event)"></i>
</span>
<h5 class="email-detail-title font-weight-normal mb-0">
Advertising Internet Online
<span class="badge badge-light-danger badge-pill ml-1 bg-1">PRODUCT</span>
</h5>
</div>
<div class="email-header-right mb-1 ml-2 pl-1">
<ul class="list-inline m-0">
<li class="list-inline-item">
<button class="btn btn-icon action-icon">
<i class="ficon feather ft-trash-2"></i>
</button>
</li>
<li class="list-inline-item">
<button class="btn btn-icon action-icon">
<i class="ficon feather ft-mail"></i>
</button>
</li>
<li class="list-inline-item">
<div class="dropdown">
<div ngbDropdown [open]="false" [autoClose]="true" class="d-inline-block">
<button type="button" class="dropdown-toggle btn btn-icon action-icon" id="folder"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" id="dropdownMenuButton"
dropdown-menu dropdown-menu-right show data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false" role="menu" ngbDropdownToggle>
<i class="ficon feather ft-folder mr-0"></i>
</button>
<div ngbDropdownMenu="dropdownMenuButton" class="dropdown-menu dropdown-menu-right listDropdown" >
<a class="dropdown-item" [routerLink]=""><i class="ficon feather ft-edit"></i>Draft</a>
<a class="dropdown-item" [routerLink]=""><i class="ficon feather ft-info"></i>Spam</a>
<a class="dropdown-item" [routerLink]=""><i class="ficon feather ft-trash-2"></i>Trash</a>
</div>
</div>
</div>
</li>
<li class="list-inline-item">
<div class="dropdown">
<div ngbDropdown [open]="false" [autoClose]="true" class="d-inline-block">
<button type="button" class="btn btn-icon dropdown-toggle action-icon" id="tag"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" id="dropdownMenuButton"
ropdown-menu dropdown-menu-right show data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false" role="menu" ngbDropdownToggle>
<i class="ficon feather ft-tag mr-0"></i>
</button>
<div aria-labelledby="tag">
<div ngbDropdownMenu="dropdownMenuButton" class="taglistDropdown">
<a [routerLink]="" class="dropdown-item align-items-center">
<span class="bullet bullet-sm gradient-mint d-inline-block rounded-circle "></span>
<span>Product</span>
</a>
<a [routerLink]="" class="dropdown-item align-items-center">
<span class="bullet bullet-sm gradient-primary d-inline-block rounded-circle "></span>
<span>Work</span>
</a>
<a [routerLink]="" class="dropdown-item align-items-center">
<span class="bullet bullet-sm gradient-warning d-inline-block rounded-circle "></span>
<span>Misc</span>
</a>
<a [routerLink]="" class="dropdown-item align-items-center">
<span class="bullet bullet-sm gradient-danger d-inline-block rounded-circle "></span>
<span>Family</span>
</a>
<a [routerLink]="" class="dropdown-item align-items-center">
<span class="bullet bullet-sm gradient-info d-inline-block rounded-circle "></span>
<span> Design</span>
</a>
</div>
</div>
</div>
</div>
</li>
<li class="list-inline-item">
<span class="no-of-list d-none d-sm-block ml-1">1-10 of 653</span>
</li>
<li class="list-inline-item">
<button class="btn btn-icon email-pagination-prev action-icon">
<i class='ficon feather ft-chevron-left'></i>
</button>
</li>
<li class="list-inline-item">
<button class="btn btn-icon email-pagination-next action-icon">
<i class='ficon feather ft-chevron-right'></i>
</button>
</li>
</ul>
</div>
</div>
<!-- email detail view header end-->
<div class="email-scroll-area" fxFlex="auto" [perfectScrollbar]="config">
<!-- email details -->
<div class="row">
<div class="col-12">
<div class="collapsible email-detail-head">
<div class="card collapse-header" role="tablist" *ngFor="let email of emailDisplayList"
[attr.id]="'emailThread'+ email.emailId" (click)="showMassage($event, email.emailId)">
<div [attr.id]="'headingCollapse5'+email.emailId"
class="card-header d-flex justify-content-between align-items-center" data-toggle="collapse"
role="tab" [attr.data-target]="'collapse5'+email.emailId"
[attr.aria-expanded]="email.isCollapsed" aria-controls="collapse5">
<div class="collapse-title media">
<div class="pr-1">
<div class="avatar mr-75">
<img [src]="email.image" alt="avtar img holder" width="30" height="30">
</div>
</div>
<div class="media-body mt-25">
<span class="text-primary">{{email.username}}</span>
<span class="d-sm-inline d-none"> &lt;{{email.email}};</span>
<small class="text-muted d-block">{{email.title}}</small>
</div>
</div>
<div class="information d-sm-flex d-none align-items-center">
<i class="ficon feather ft-paperclip mr-50"></i>
<small class="text-muted mr-50">{{email.date}}</small>
<span class="favorite" [attr.id]="'email-icon' + email.emailId" (click)="emailFavorite($event,email.emailId)" (click)="$event.stopPropagation();">
<i class="ficon feather ft-star mr-25"></i>
</span>
<div class="dropdown">
<div ngbDropdown [open]="false" [autoClose]="true" class="d-inline-block">
<a class="dropdown-toggle " id="folder" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false" id="dropdownMenuButton" dropdown-menu dropdown-menu-right show
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="menu"
ngbDropdownToggle (click)="$event.stopPropagation();">
<i class='ficon feather ft-more-vertical mr-0'></i>
</a>
<div ngbDropdownMenu="dropdownMenuButton" class="dropdown-menu dropdown-menu-right ">
<a class="dropdown-item" [routerLink]="">Add to another project</a>
<a class="dropdown-item" [routerLink]="">Create follow up task</a>
<a class="dropdown-item" [routerLink]="">Print</a>
</div>
</div>
</div>
<!-- <div class="dropdown">
<a [routerLink]="" class="dropdown-toggle" id="fisrt-open-submenu" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class='ficon feather ft-more-vertical mr-0'></i>
</a>
</div> -->
</div>
</div>
<div [attr.id]="'collapse5'+email.emailId" role="tabpanel"
[attr.aria-labelledby]="'headingCollapse5'+ email.emailId" class="collapse">
<div class="card-content">
<div class="card-body py-1">
<p class="text-bold-500">{{email.message}}</p>
<p>
{{email.descrition}}
</p>
<p>
{{email.descrition_detail}}
</p>
<p class="mb-0"> {{email.sender}}</p>
<p class="text-bold-500"> {{email.sender_name}}</p>
</div>
<div class="card-footer pt-0 border-top">
<label class="sidebar-label">Attached Files</label>
<ul class="list-unstyled mb-0">
<li class="cursor-pointer pb-25">
<img [src]="email.image_icon1" height="30" alt="psd.png">
<small class="text-muted ml-1 attchement-text"> {{email.file_name1}}</small>
</li>
<li class="cursor-pointer">
<img [src]="email.image_icon2" height="30" alt="sketch.png">
<small class="text-muted ml-1 attchement-text"> {{email.file_name2}}</small>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- email details end-->
<div class="row px-2 mb-4">
<div class="col-12 px-0">
<div class="card shadow-none border rounded">
<div class="card-content">
<div class="card-body quill-wrapper emailquillConfig">
<div class="snow-container">
<quill-editor [styles]="{height: '80px'}" [modules]="quillConfig" (onFocus)="focus()"
(onBlur)="blur()" >
<span>Reply to Lois Jimenez</span></quill-editor>
<!-- <quill-editor [styles]="{height: '100px'}" placeholder="Enter Text"
[modules]="emailquillConfig" (onFocus)="focus()" (onBlur)="blur()"></quill-editor> -->
</div>
<div class="emailtoolbar">
<button class="btn btn-primary send-btn">
<i class='ficon feather ft-play mr-25'></i>
<span class="d-none d-sm-inline"> Send</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!--/ Detailed Email View -->
</div>
</div>
</div>
</div>
</div>
<!-- END: Content-->

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { EmailComponent } from './email.component';
describe('EmailComponent', () => {
let component: EmailComponent;
let fixture: ComponentFixture<EmailComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ EmailComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EmailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,562 @@
import { Component, OnInit, ViewChild, Renderer2 } from '@angular/core';
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
import { ApplicationApiService } from '../../../_services/application-api.service';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { QuillInitializeServiceService } from '../../../_services/quill-initialize-service.service';
class Email {
constructor(
public emailId: number,
public mediaClass: string,
public starClass: string,
public starIcon: string,
public image: any,
public time: string,
public title: string,
public message: string,
public showicon: boolean,
public bullet: string,
) { }
}
class EmailHistory {
constructor(
public emailId: number,
public username: string,
public email: string,
public image: any,
public date: any,
public title: string,
public message: string,
public descrition: string,
public descrition_detail: string,
public sender: string,
public sender_name: string,
public iconClass: string,
public image_icon1: string,
public file_name1: string,
public image_icon2: string,
public file_name2: string
) { }
}
class EmailMenu {
constructor(
public Id: string,
public name: string,
public icon: string,
public budge: string,
public budgeClass: string,
public budgeIcon: boolean,
public isSelected: false
) { }
}
class EmailLable {
constructor(
public Id: string,
public name: string,
public isSelected: boolean,
public bulletClass: string,
) { }
}
@Component({
selector: 'app-email',
templateUrl: './email.component.html',
styleUrls: ['./email.component.css'],
})
export class EmailComponent implements OnInit {
public config: PerfectScrollbarConfigInterface = { wheelPropagation: true };
@ViewChild(PerfectScrollbarComponent)
componentRef?: PerfectScrollbarComponent;
directiveRef?: PerfectScrollbarDirective;
@ViewChild(PerfectScrollbarDirective, { static: true })
isHidden = false;
isShown = true;
emailList: any[] = [];
emailDisplayList: any[] = [];
emailMenuList: any[] = [];
email: EmailHistory[];
emailLable: EmailLable[];
emailArray: any;
temp = [];
temp2 = this.emailList;
isSelected: boolean;
isCollapsed = false;
selectAll = false;
selected: [];
blured = false;
focused = false;
hide = false;
htmlText = 'Type Something';
form: FormGroup;
atValues = [
{ id: 1, value: 'Fredrik Sundqvist', link: 'https://google.com' },
{ id: 2, value: 'Patrik Sjölin' }
];
hashValues = [
{ id: 3, value: 'Fredrik Sundqvist 2' },
{ id: 4, value: 'Patrik Sjölin 2' }
];
quillConfig = {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'],
]
},
autoLink: true,
keyboard: {
bindings: {
enter: {
key: 13,
handler: (range, context) => {
console.log('enter');
return true;
}
}
}
}
};
emailquillConfig = {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'],
]
},
autoLink: true
};
/**
* Constructor
*
* @param ApplicationApiService emailApiService
* @param Renderer2 renderer
*/
constructor(
private emailApiService: ApplicationApiService,
private renderer: Renderer2,
private QuillInitializeServiceServicec: QuillInitializeServiceService,
fb: FormBuilder
) {
this.form = fb.group({
editor: ['']
});
}
/**
* OnInit
*/
ngOnInit() {
this.emailApiService.getEmailData().subscribe(Response => {
this.emailArray = Response;
this.emailDisplayList = Response.EmailHistory;
this.emailMenuList = Response.EmailMenu;
this.emailLable = Response.EmailLable;
this.email = this.emailArray.EmailHistory[1];
this.emailList.push(
new Email(
1,
'media mail-read',
'favorite warning',
'ficon feather ft-star',
'../../../assets/images/portrait/small/avatar-s-1.png',
'4.14 AM',
'Open source project public release 👍',
'Hey John, bah kivu decrete epanorthotic unnotched Argyroneta nonius veratrine preimaginary ',
false,
'gradient-mint',
)
);
this.emailList.push(
new Email(
2,
'media mail-read',
'favorite',
'ficon feather ft-star',
'../../../assets/images/portrait/small/avatar-s-2.png',
'2.15 AM',
'Ecommerce website Paypal integration 😃',
' We will start the new application development soon once this will be completed. ',
false,
'gradient-danger',
)
);
this.emailList.push(
new Email(
3,
'media',
'favorite warning',
'ficon feather ft-star',
'../../../assets/images/portrait/small/avatar-s-3.png',
'11.18AM',
'How To Set Intentions That Energize You',
' I will provide you more details after this Saturday. Hope that will be fine for you.. ',
true,
'gradient-mint',
)
);
this.emailList.push(
new Email(
4,
'media',
'favorite',
'ficon feather ft-star',
'../../../assets/images/portrait/small/avatar-s-4.png',
'Yesterday',
'Harness The Power Of Words In Your Life',
'When the equation, first to ability the forwards, the a but travelling, outlines sentinels bad expand to goodness....',
true,
'gradient-warning',
)
);
this.emailList.push(
new Email(
5,
'media mail-read',
'favorite',
'ficon feather ft-star',
'../../../assets/images/portrait/small/avatar-s-5.png',
'24 Feb',
'Helen Keller A Teller And A Seller',
'Thanks for your feedback ! Here`s a new layout for a new Modern Admin theme.',
true,
'gradient-warning',
)
);
this.emailList.push(
new Email(
6,
'media mail-read',
'favorite warning',
'ficon feather ft-star',
'../../../assets/images/portrait/small/avatar-s-6.png',
'15 March',
'Use Your Reset Button To Change Your Vibration 🎉',
'Hey John, bah kivu decrete epanorthotic unnotched Argyroneta nonius veratrine preimaginary',
false,
'gradient-info',
)
);
this.emailList.push(
new Email(
7,
'media',
'favorite',
'ficon feather ft-star',
'../../../assets/images/portrait/small/avatar-s-7.png',
'12-07-2019',
'Will connect you',
'Hi Kelly!',
false,
'gradient-mint',
)
);
this.emailList.push(
new Email(
8,
'media mail-read',
'favorite',
'ficon feather ft-star',
'../../../assets/images/portrait/small/avatar-s-8.png',
'03-29-2019',
'Harness The Power Of Words In Your Life',
'Hope your like it, or feel free to comment, feedback or rebound !',
false,
'gradient-danger'
)
);
this.emailList.push(
new Email(
9,
'media ',
'favorite warning',
'ficon feather ft-star',
'../../../assets/images/portrait/small/avatar-s-9.png',
'19 Jun',
'Hypnosis 12 Steps To Acquire Mind Power',
'Monstrous with geared from far and these, morals, phase rome; Class. Called get amidst of geared from next...',
false,
'gradient-info'
)
);
this.emailList.push(
new Email(
10,
'media ',
'favorite warning',
'ficon feather ft-star',
'../../../assets/images/portrait/small/avatar-s-10.png',
'21 Mar',
' Know Yourself Your Inner Power ',
' Hope your like it, or feel free to comment, feedback or rebound.',
false,
'gradient-warning'
)
);
});
this.form
.controls
.editor
.valueChanges.pipe(
debounceTime(400),
distinctUntilChanged()
)
.subscribe((data) => {
});
}
/**
* Search email
*
* @param event Convert value uppercase to lowercase;
*/
updateFilter(event) {
const value = event.target.value.toLowerCase();
this.emailList = [...this.temp2]; // and here you have to initialize it with your data
this.temp = [...this.emailList];
// filter our data
const temp = this.emailList.filter(function (d) {
return d.name.toLowerCase().indexOf(value) !== -1 || !value;
});
// update the rows
this.emailList = temp;
// Whenever the filter changes, always go back to the first page
}
/**
* Overlay add/remove fuction in responsive
*
* @param event Overlay click event
*/
contentOverlay(event) {
const toggleIcon = document.getElementById('email-app-menu');
const toggle = document.getElementById('content-overlay');
if (event.currentTarget.className === 'content-overlay show') {
this.renderer.removeClass(toggleIcon, 'show');
this.renderer.removeClass(toggle, 'show');
}
}
/**
* Add overlay when open sidebar
*
* @param event Content overlay
*/
contentRightSidebar(event) {
const toggle = document.getElementById('content-right');
if (event.currentTarget.className === 'media _media border-0 ng-star-inserted active') {
this.renderer.addClass(toggle, 'show');
}
}
/**
* Remove overlay when close sidebar
*
* @param event Content overlay
*/
contentRight(event) {
const toggle = document.getElementById('content-right');
if (event.currentTarget.className === 'btn btn-primary go-back') {
this.renderer.removeClass(toggle, 'show');
}
}
/**
* Open Media-body
*
* @param event Mail Read
*/
showEmail(event) {
const toggleIcon = document.getElementById('app-details');
if (event.currentTarget.className === 'media-body') {
this.renderer.addClass(toggleIcon, 'show');
} else if (event.currentTarget.className === 'ficon feather ft-chevron-left font-medium-4 align-middle') {
this.renderer.removeClass(toggleIcon, 'show');
}
}
/**
*
* @'param' event
* @'param' emailId
*/
showMassage(event, emailId) {
for (let i = 1; i <= this.emailDisplayList.length; i++) {
if (emailId === i) {
const toggleIcon = document.getElementById('headingCollapse5' + emailId);
const toggle = document.getElementById('collapse5' + emailId);
const toggleHeader = document.getElementById('emailThread' + emailId);
if (event.currentTarget.className === 'card collapse-header ng-star-inserted') {
this.renderer.addClass(toggle, 'show');
this.renderer.addClass(toggleHeader, 'open');
this.renderer.removeClass(toggleIcon, 'collapsed');
this.emailDisplayList[i - 1].isCollapsed = true;
} else if (event.currentTarget.className === 'card collapse-header ng-star-inserted open') {
this.renderer.removeClass(toggle, 'show');
this.renderer.removeClass(toggleHeader, 'open');
this.renderer.addClass(toggleIcon, 'collapsed');
this.emailDisplayList[i - 1].isCollapsed = false;
}
}
}
}
/**
* Add overlay when open sidebar
*
* @param event Content overlay
*/
showComposeSidebar(event) {
const toggleIcon = document.getElementById('compose-sidebar');
const toggleSidebar = document.getElementById('sidebar-left');
const toggleOverlay = document.getElementById('app-content-overlay');
if (event.currentTarget.className === 'btn btn-danger btn-glow btn-block my-2 compose-btn') {
this.renderer.addClass(toggleIcon, 'show');
this.renderer.removeClass(toggleSidebar, 'show');
this.renderer.addClass(toggleOverlay, 'show');
} else if (event.currentTarget.className === 'btn btn-danger btn-glow btn-block my-2 compose-btn show') {
this.renderer.removeClass(toggleIcon, 'show');
}
}
/**
* Remove overlay when open sidebar
*
* @param event Content overlay
*/
showCompose(event) {
const toggleIcon = document.getElementById('compose-sidebar');
const toggleOverlay = document.getElementById('app-content-overlay');
if (event.currentTarget.className === 'close close-icon' || 'app-content-overlay') {
this.renderer.removeClass(toggleIcon, 'show');
this.renderer.removeClass(toggleOverlay, 'show');
}
}
/**
* Add overlay when open sidebar
*
* @param event Content overlay
*/
showSidebar(event) {
const toggleIcon = document.getElementById('sidebar-left');
const toggle = document.getElementById('app-content-overlay');
if (event.currentTarget.className === 'sidebar-toggle d-block d-lg-none') {
this.renderer.addClass(toggleIcon, 'show');
this.renderer.addClass(toggle, 'show');
} else if (event.currentTarget.className === 'sidebar-close-icon' || 'app-content-overlay') {
this.renderer.removeClass(toggleIcon, 'show');
this.renderer.removeClass(toggle, 'show');
}
}
/**
* Filter Email
*
* @param term search term
*/
search(term) {
const searchTerm = term.currentTarget.value;
if (searchTerm !== '') {
this.emailList = this.emailList.filter(result => {
if (result && searchTerm) {
if (result.title.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1 ||
result.message.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1) {
return true;
}
return false;
}
});
} else {
this.emailList = this.temp2;
}
}
selectAllEmails() {
for (let i = 0; i < this.emailList.length; i++) {
if (this.selectAll) {
this.emailList[i].isSelected = false;
} else {
this.emailList[i].isSelected = true;
}
}
}
deleteCheckedRow() {
let index = 0;
const removedIndex = [];
const temp = [...this.emailList];
for (const row of temp) {
if (row.isSelected === true) {
removedIndex.push(index);
}
index++;
}
for (let i = removedIndex.length - 1; i >= 0; i--) {
temp.splice(removedIndex[i], 1);
}
this.emailList = temp;
this.selectAll = false;
}
showEmailMenu(Id, emailMenu) {
for (let j = 0; j < emailMenu.length; j++) {
for (let i = 0; i < this.emailMenuList.length; i++) {
for (let k = 0; k < this.emailLable.length; k++) {
if (emailMenu[j].name === this.emailMenuList[i].name) {
if (Id !== this.emailMenuList[i].Id) {
this.emailMenuList[i].isSelected = false;
}
if (Id === this.emailMenuList[i].Id) {
this.emailMenuList[i].isSelected = true;
this.emailLable[k].isSelected = false;
}
} else if (emailMenu[j].name === this.emailLable[k].name) {
if (Id !== this.emailLable[k].Id) {
this.emailLable[k].isSelected = false;
}
if (Id === this.emailLable[k].Id) {
this.emailLable[k].isSelected = true;
this.emailMenuList[i].isSelected = false;
}
}
}
}
}
for (const friend of this.emailMenuList) {
if (friend.Id === Id) {
break;
}
}
}
focus() {
this.focused = true;
this.blured = false;
}
blur() {
this.focused = false;
this.blured = true;
}
setControl() {
this.form.setControl('editor', new FormControl('test - new Control'));
}
/**
* Filter Email
*
* @ param event warning Class
* @ param emailId
*/
emailFavorite(event, emailId) {
for (let i = 1; i <= this.emailDisplayList.length; i++) {
if (emailId === i) {
const emailIcon = document.getElementById('email-icon' + emailId);
const emailstarIcon = document.getElementById('emailstar-icon' + emailId);
if (event.currentTarget.className === 'favorite') {
this.renderer.addClass(emailIcon, 'warning');
this.renderer.addClass(emailstarIcon, 'warning');
} else if (event.currentTarget.className === 'favorite warning') {
this.renderer.removeClass(emailIcon, 'warning');
this.renderer.removeClass(emailstarIcon, 'warning');
}
}
}
}
}

View File

@@ -0,0 +1,13 @@
import { EmailModule } from './email.module';
describe('EmailModule', () => {
let emailModule: EmailModule;
beforeEach(() => {
emailModule = new EmailModule();
});
it('should create an instance', () => {
expect(emailModule).toBeTruthy();
});
});

View File

@@ -0,0 +1,34 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { EmailComponent } from './email.component';
import { RouterModule } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { QuillModule } from 'ngx-quill';
import { CustomFormsModule } from 'ngx-custom-validators';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
import { ArchwizardModule } from 'angular-archwizard';
import { BlockUIModule } from 'ng-block-ui';
@NgModule({
imports: [
CommonModule,
NgbModule,
FormsModule,
QuillModule.forRoot(),
CustomFormsModule,
PerfectScrollbarModule,
ArchwizardModule,
BreadcrumbModule,
RouterModule.forChild([
{
path: '',
component: EmailComponent
}
])
],
declarations: [EmailComponent]
})
export class EmailModule { }

View File

@@ -0,0 +1,31 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { KanbanComponent } from './kanban/kanban.component';
import { RouterModule } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NgSelectModule } from '@ng-select/ng-select';
import { QuillModule } from 'ngx-quill';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { DndListModule } from 'ngx-drag-and-drop-lists';
@NgModule({
declarations: [KanbanComponent],
imports: [
CommonModule,
NgbModule,
FormsModule,
NgSelectModule,
QuillModule.forRoot(),
DndListModule,
ReactiveFormsModule,
PerfectScrollbarModule,
RouterModule.forChild([
{
path: '',
component: KanbanComponent
}
])
]
})
export class KanbanModule { }

View File

@@ -0,0 +1,496 @@
.mr-25, .mx-25 {
margin-right: .25rem!important;
}
.mr-50, .mx-50 {
margin-right: .5rem!important;
}
.dropdown .dropdown-menu
{
transform: translate3d(-130px, 24px, 0px) !important;
}
:host ::ng-deep .ng-select .ng-select-container {
color: #fff;
background-color: #666ee8 !important;
}
:host ::ng-deep .ng-arrow {
top: -2px;
border-color: transparent transparent #fff !important;
}
:host ::ng-deep .ng-arrow-wrapper {
top: -2px;
border-color: transparent transparent #fff !important;
border-width: 0 5px 5px !important;
}
:host ::ng-deep .ng-select .ng-select-container {
height: calc(1.25em + 1.5rem + 2px)!important;
padding: .75rem 1rem;
font-size: 1rem;
line-height: 1.25;
}
:host ::ng-deep .ng-select {
position: relative;
display: block;
box-sizing: border-box;
}
:host ::ng-deep .ml-25, .mx-25 {
margin-left: .25rem!important;
}
:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option {
box-sizing: border-box;
cursor: pointer;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-height: 1.2em;
padding: 0px 5px 1px;
}
:host ::ng-deep .text {
/* display: block;
width: 100%; */
height: calc(1.25em + 1.5rem + 2px);
padding: .75rem 1rem;
font-size: 1rem;
line-height: 1.25;
/* color: #4e5154; */
background-color: #fff;
background-clip: padding-box;
border: 1px solid #babfc7;
border-radius: .25rem;
/* transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; */
}
:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items .ng-option .bg-primary {
background-color: #666ee8!important;
}
ng-reflect-ng-item-label{
background-color: #ff4961!important;
}
:host ::ng-deep .bg-danger {
background-color: #ff4961!important;
}
:host ::ng-deep .justify-scontent-between {
justify-content: space-between!important;
}
/* datepicker css */
:host ::ng-deep .btn-light:not(:disabled):not(.disabled):active {
color: unset !important;
background-color: unset !important;
border-color: #d3d9df !important;
}
:host ::ng-deep .btn-light:hover:not(.disabled):active {
background-color: #e2e6ea !important;
border-color: #dae0e5 !important;
}
:host ::ng-deep .btn-light {
color: unset !important;
background-color: unset !important;
border-color: unset !important;
}
:host ::ng-deep .bg-primary {
background-color: #007bff !important;
}
:host ::ng-deep .text-white {
color: #fff !important;
}
:host ::ng-deep .custom-day {
text-align: center;
padding: .185rem .25rem;
display: inline-block;
height: 2rem;
width: 2rem;
}
:host ::ng-deep .custom-day:active {
color: #6d7183 !important;
background-color: #fff !important;
border-block-color: rgb(2, 117, 216) !important;
}
.bg-light {
background-color: #f8f9fa !important;
}
:host ::ng-deep .hidden {
display: block !important;
}
.ngb-dp-weekday {
color: #17a2b8;
}
.ngb-dp-week-number,
.ngb-dp-weekday {
line-height: 2rem;
text-align: center;
font-style: italic;
}
.ngb-datepicker-month-view {
pointer-events: auto;
}
.small {
font-size: 80%;
font-weight: 400;
}
.ngb-dp-day {
cursor: pointer !important;
}
.ngb-dp-month {
pointer-events: none;
}
.btn-light:hover {
color: #212529 !important;
background-color: #e2e6ea !important;
border-color: #dae0e5 !important;
}
.ngb-datepicker-month-view {
pointer-events: auto;
}
.ngb-dp-header {
border-bottom: 0;
border-radius: .25rem .25rem 0 0;
padding-top: .25rem;
}
.ngb-dp-day,
.ngb-dp-week-number,
.ngb-dp-weekday {
width: 2rem;
height: 2rem;
}
.custom-day {
text-align: center;
padding: 0.185rem 0.25rem;
display: inline-block;
height: 2rem;
width: 2rem;
}
.custom-day.focused {
background-color: #e6e6e6;
}
.custom-day.range,
.custom-day:hover {
background-color: rgb(2, 117, 216);
color: white;
}
.custom-day.faded {
background-color: rgba(2, 117, 216, 0.5);
}
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}
.custom-day {
text-align: center;
padding: 0.185rem 0.25rem;
border-radius: 0.25rem;
display: inline-block;
width: 2rem;
}
.custom-day:hover, .custom-day.focused {
background-color: #e6e6e6;
}
.weekend {
background-color: #f0ad4e;
border-radius: 1rem;
color: white;
}
.hidden {
display: none;
}
:host ::ng-deep .ft-calendar{
font-family: feather!important;
speak: none;
font-style: normal;
font-weight: 400;
font-size: large;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
:host ::ng-deep .input-group-text {
display: flex;
align-items: center;
padding: unset !important;
margin-bottom: unset !important;
font-size: unset !important;
font-weight: unset !important;
line-height: unset !important;
color:unset !important;
text-align: unset !important;
white-space: unset !important;
background-color: unset !important;
border: unset !important;
border-radius: unset !important;
}
.ml-75, .mx-75 {
margin-left: .75rem!important;
}
.mx-50 {
margin-left: .5rem!important;
}
.sidebar {
width : 270px !important;
}
.align-middle {
margin-left: 3px;
}
.mr-50, .mx-50 {
margin-right: .5rem!important;
}
:host ::ng-deep .ft-plus{
margin-right: 3px !important;
}
control:disabled, .form-control[readonly] {
background-color: #ffffff;
margin-left: -12px;
}
/* Kanban Board Application css */
/*------------------------------*/
.kanban-container {
width : 100% !important;
}
.kanban-container .kanban-board {
border-radius : 0.25rem;
padding : 1rem 0rem;
margin : 0 1.8rem 1rem 0 !important;
width : 18.67rem !important;
background-color : #E7EDF3;
}
.kanban-container .kanban-board .kanban-board-header {
/* kanban-header */
font-size : 1.2rem;
font-family : 'Quicksand', Georgia, 'Times New Roman', Times, serif;
color : #6B6F82;
padding : 0 0.93rem;
display : -webkit-box;
display : -webkit-flex;
display : -ms-flexbox;
display : flex;
-webkit-box-pack : justify;
-webkit-justify-content : space-between;
-ms-flex-pack : justify;
justify-content : space-between;
}
.kanban-container .kanban-board .kanban-board-header .dropdown {
float : right;
}
.kanban-container .kanban-board .kanban-board-header .dropdown .dropdown-toggle:after {
display : none;
}
.kanban-container .kanban-board .kanban-board-header .kanban-title-board {
/* kanban title */
font-weight : normal;
cursor : text;
padding : 0 0.5rem;
width : 200px;
}
.kanban-container .kanban-board .kanban-board-header .kanban-title-board:hover, .kanban-container .kanban-board .kanban-board-header .kanban-title-board:focus {
background-color : #6B6F82;
color : #FFFFFF;
border-radius : 0.25rem;
outline : none;
text-overflow : clip;
}
.kanban-container .kanban-board .kanban-board-header .kanban-title-button {
/* kanban title button */
position : absolute;
bottom : 0;
padding : 0.467rem 0rem;
display : block;
color : #6B6F82;
font-weight : 700;
font-size : 0.8rem;
}
.kanban-container .kanban-board .kanban-drag {
padding : 13px;
min-height : auto;
}
.kanban-container .kanban-board .kanban-item {
/* kanban item */
padding : 0.53rem 0.8rem;
border-radius : 0.25rem;
margin-bottom : 1rem;
box-shadow : -4px 4px 6px 0 rgba(55, 70, 95, 0.12);
position : relative;
overflow-wrap: break-word;
}
.kanban-container .kanban-board .kanban-item:before {
content : '';
width : 3px;
height : 100%;
position : absolute;
left : 0;
top : 0;
border-radius : 0.5rem;
}
.kanban-container .kanban-board .kanban-item:hover {
cursor : default;
}
.kanban-container .kanban-board .kanban-item:last-child {
margin-bottom : 0.5rem;
}
.kanban-container .kanban-board .kanban-item .kanban-image img {
border-radius : 0.25rem;
}
.kanban-overlay {
/* kanban overlay */
top : 0;
left : 0;
right : 0;
bottom : 0;
position : absolute;
z-index : 999;
visibility : hidden;
opacity : 0;
}
.kanban-overlay.show {
visibility : visible;
-webkit-transition : all 0.3s ease;
transition : all 0.3s ease;
opacity : 1;
background-color : rgba(0, 0, 0, 0.2);
}
.badge-circle {
display : -webkit-box;
display : -webkit-flex;
display : -ms-flexbox;
display : flex;
-webkit-box-align : center;
-webkit-align-items : center;
-ms-flex-align : center;
align-items : center;
-webkit-box-pack : center;
-webkit-justify-content : center;
-ms-flex-pack : center;
justify-content : center;
background-color : #E6EAEE;
color : #475F7B;
border-radius : 50%;
height : 30px;
width : 30px;
}
.avatar img {
border : 2px solid #FFFFFF;
}
.kanban-sidebar {
/* kanban sidebar */
box-shadow : -8px 0 18px 0 rgba(25, 42, 70, 0.13);
height : 100vh;
width : 23.8rem;
background-color : #FFFFFF;
position : fixed;
-webkit-transform : translateX(110%);
-ms-transform : translateX(110%);
transform : translateX(110%);
-webkit-transition : all 0.3s ease;
transition : all 0.3s ease;
z-index : 1050;
right : 2rem;
left : auto;
bottom : 0;
top : -1px;
opacity : 0;
overflow : hidden;
}
.kanban-sidebar .card-header .close-icon {
color : #6B6F82;
opacity : 1 !important;
}
.kanban-sidebar .card-header .close-icon:focus {
outline : none;
}
.kanban-sidebar.show {
opacity : 1;
-webkit-transform : translateX(9%) translateY(1px);
-ms-transform : translateX(9%) translateY(1px);
transform : translateX(9%) translateY(1px);
}
.kanban-sidebar .edit-kanban-item {
height : 100vh;
}
.kanban-sidebar .edit-kanban-item .card-content {
height : calc(100% - 9rem);
}
.kanban-sidebar .edit-kanban-item .card-content .form-group > label {
color : #BAC0C7;
margin-bottom : 0.67rem;
}
.kanban-sidebar .edit-kanban-item .card-content .form-group select {
border-radius : 0.25rem;
display : block;
}
.kanban-sidebar .edit-kanban-item .card-content .custom-file .custom-file-label:after {
background-color : transparent;
}
.kanban-sidebar .edit-kanban-item .card-footer .btn i {
top : 0;
}
.kanban-sidebar .edit-kanban-item .picker {
position : relative;
}
.kanban-sidebar .quill-wrapper .snow-container .ql-snow, .kanban-sidebar .quill-wrapper .snow-container .ql-toolbar {
border : none;
}
.kanban-sidebar .quill-wrapper .snow-container .ql-toolbar .btn {
width : auto;
line-height : 0.9;
padding : 0.467rem 1.2rem;
}
.kanban-sidebar .quill-wrapper .snow-container .ql-toolbar .btn:hover {
color : #FFFFFF;
}
.kanban-sidebar .quill-wrapper .snow-container .ql-tooltip {
left : 0 !important;
}
.kanban-sidebar .quill-wrapper .snow-container .ql-tooltip input[type=text] {
width : 100px;
}
.kanban-sidebar .quill-wrapper .ql-editor.ql-blank::before {
left : 0.3rem;
}
.kanban-sidebar .quill-wrapper .ql-editor {
min-height : 7.93rem;
padding : 0;
}
.kanban-title-button {
background-color : transparent;
box-shadow : none;
}
@media (max-width: 420px) {
.kanban-sidebar {
width : 19rem;
right : 1.6rem;
}
.kanban-sidebar .quill-wrapper .snow-container .ql-tooltip input[type=text] {
width : 70px;
}
}

View File

@@ -0,0 +1,204 @@
<div class="app-content content">
<div class="content-overlay"></div>
<div class="content-wrapper">
<div class="content-header row">
</div>
<div class="content-body">
<!-- Basic Kanban App -->
<div class="kanban-overlay" id="content-overlay" (click)="showSidebar($event)"></div>
<section id="kanban-wrapper">
<div class="row">
<div class="col-12">
<button type="button" class="btn btn-primary mb-1" id="add-kanban" (click)="addKanbanBoard()">
<i class='ficon feather ft-plus-square mr-50'></i> Add New Board
</button>
<div id="kanban-app"></div>
</div>
</div>
<div class="kanban-sidebar" id="kanban_sidebar">
<div class="card shadow-none quill-wrapper">
<div class="card-header d-flex justify-scontent-between align-items-center border-bottom px-2 py-1">
<h3 class="card-title">UI Design</h3>
<button type="button" class="close close-icon">
<i class="ficon feather ft-x" (click)="showSidebar($event)"></i>
</button>
</div>
<!-- form start -->
<form [formGroup]="kanban" class="edit-kanban-item">
<div class="card-content position-relative" [perfectScrollbar]="config">
<div class="card-body">
<div class="form-group">
<label>Card Title</label>
<input type="text" formControlName="title" class="form-control edit-kanban-item-title"
placeholder="kanban Title">
</div>
<div class="form-group">
<label>Due Date</label>
<!-- <input type="text" formControlName="date" class="form-control edit-kanban-item-date"
placeholder="21 August, 2019"> -->
<div class="input-group">
<div class="input-group-text mr-50">
</div>
<input class="form-control" placeholder="yyyy-mm-dd" formControlName="date" name="date"
ngbDatepicker #d2="ngbDatepicker" (click)="d2.toggle()">
</div>
</div>
<div class="row form-group">
<div class="col-6">
<label>Label </label>
<select class="form-control text-white " bindLabel="name" formControlName="selectedLabel"
(change)="getSelectedKanbanText($event)" id="selectLable">
<option class="bg-primary">Primary</option>
<option class="bg-danger">Danger</option>
<option class="bg-success">Success</option>
<option class="bg-info">Info</option>
<option class="bg-warning">Warning</option>
<option class="bg-secondary">Secondary</option>
</select>
</div>
<div class="col-6">
<div class="form-group">
<label>Member</label>
<div class="d-flex align-items-center">
<div class="avatar m-0 mr-1">
<img src="../../../assets/images/portrait/small/avatar-s-20.png" height="36" width="36"
alt="avtar img holder">
</div>
<div class="badge-circle">
<i class="ficon feather ft-plus"></i>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label>Attachment</label>
<div class="custom-file">
<input type="file" class="custom-file-input" id="emailAttach">
<label class="custom-file-label" for="emailAttach">Attach file</label>
</div>
</div>
<!-- Compose mail Quill editor -->
<div class="form-group">
<label>Comment</label>
<div class="snow-container border rounded p-1">
<div class="editor">
<quill-editor calss="kanbanQuill" formControlName="description"
[styles]="{height: '110px', border: '0px solid #ccc' }" [modules]="kanbanquillConfig"
(onFocus)="focus()" (onBlur)="blur()" placeholder="Write a Comment... "></quill-editor>
</div>
<div class="d-flex justify-content-end">
<div class="compose-quill-toolbar ql-toolbar ql-snow kanbantoolbar">
<span class="ql-formats mr-0">
<button class="ql-bold">Bold</button>
<button class="ql-italic">Italic</button>
<button class="ql-underline">Underline</button>
<button class="ql-link"></button>
<button class="ql-image"></button>
<button class="btn btn-sm btn-primary btn-comment ml-25">Comment</button>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer d-flex justify-content-end">
<button type="reset" class="btn btn-danger delete-kanban-item mr-1" (click)="deleteKanban($event)">
<i class='ficon feather ft-trash-2 mr-50'></i>
<span>Delete</span>
</button>
<button type="submit" class="btn btn-primary glow update-kanban-item"
(click)="updateKanbanItem($event)">
<i class='ficon feather ft-play mr-50'></i>
<span>Save</span>
</button>
</div>
</form>
<!-- form start end-->
</div>
</div>
<!--/ User Chat profile right area -->
<div class="kanban-container">
<div data-id="kanban-board-1" data-order="1" class="kanban-board"
style="width: 250px; margin-left: 15px; margin-right: 15px;" *ngFor="let kanbanList of kanbanList">
<header class="kanban-board-header">
<div type="text" class="kanban-title-board truncate" contenteditable="true" [innerHTML]="kanbanList.name"
(input)="contentNew=$event.target.textContent" (click)="showSidebar($event)"
(focusout)="validateProfile(contentNew,kanbanList)"></div>
<button class="kanban-title-button btn btn-default btn-xs" (click)="addKanbanItem(kanbanList)">+ Add
New Item</button>
<div ngbDropdown>
<i class="ficon feather ft-more-vertical" id="dropdownBasic1" ngbDropdownToggle></i>
<div ngbDropdownMenu>
<a class="dropdown-item" [routerLink]=""><i class="ficon feather ft-link mr-50"></i>Copy Link</a>
<a class="dropdown-item kanban-delete" [routerLink]="" (click)="deleteKanbanList(kanbanList)"><i
class="ficon feather ft-trash-2 mr-50"></i>Delete</a>
</div>
</div>
</header>
<main class="kanban-drag">
<div>
<!-- <div *ngFor="let kanban of kanbanList.tickets" class="kanban"> -->
<div>
<div [dndList] [dndModel]="kanbanList.tickets">
<div class="kanban-item" (click)="showSidebar($event)" (click)="editItem(kanban,kanbanList.tickets)"
*ngFor="let kanban of kanbanList.tickets"
[dndType]="'kanban'"
(dndMoved)="removeItem(kanban, kanbanList)"
[dndDraggable] [dndObject]="kanban">
{{kanban.name}}
<div class="kanban-image mb-1" [hidden]="!kanban.showImage"><img class="img-fluid"
[src]="kanban.bg_image" alt="kanban-image"></div>
<div class="kanban-footer d-flex justify-content-between mt-1">
<div class="kanban-footer-left d-flex">
<div class="kanban-due-date mr-50"><i
[ngClass]="{'ficon feather ft-clock font-size-small mr-25': kanban.date}"></i><span
class="font-size-small">{{kanban.date| date: 'MMM d' }}</span></div>
<div class="kanban-comment mr-50"><i
[ngClass]="{'ficon feather ft-message-square font-size-small mr-25': kanban.comment}"></i><span
class="font-size-small">{{kanban.comment}}</span></div>
<div class="kanban-attachment"><i
[ngClass]="{'ficon feather ft-link font-size-small mr-25':kanban.attachment}"></i><span
class="font-size-small">{{kanban.attachment}}</span></div>
</div>
<div class="kanban-footer-right">
<div class="kanban-users">
<ul class="list-unstyled users-list cursor-pointer m-0 d-flex align-items-center">
<li class="avatar pull-up my-0" *ngFor="let imageUrl of kanban.image"><img
class="media-object" [src]="imageUrl" alt="Avatar" height="18" width="18"></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<footer></footer>
<!-- </div> -->
</div>
<form class="itemform not-draggable" [hidden]="!kanbanList.showNewItem">
<div class="form-group">
<textarea class="form-control add-new-item" [(ngModel)]="addTitle" rows="2" autofocus="" required=""
[ngModelOptions]="{standalone: true}"></textarea>
</div>
<div class="form-group"><button type="submit" class="btn btn-primary btn-sm mr-50"
(click)="submitItem(kanbanList)">Submit</button><button type="button" id="CancelBtn"
class="btn btn-sm btn-danger" (click)="cancleKanban(kanbanList)">Cancel</button></div>
</form>
</main>
<div>
</div>
</div>
</div>
<!--/ User Chat profile right area -->
</section>
<!--/ Sample Project kanban -->
</div>
</div>
</div>
<!-- END: Content-->

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { KanbanComponent } from './kanban.component';
describe('KanbanComponent', () => {
let component: KanbanComponent;
let fixture: ComponentFixture<KanbanComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ KanbanComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(KanbanComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,365 @@
import { Component, Renderer2, OnInit, AfterViewInit } from "@angular/core";
import { PerfectScrollbarConfigInterface } from "ngx-perfect-scrollbar";
import { FormGroup, FormControl, FormBuilder } from "@angular/forms";
import { QuillInitializeServiceService } from "../../../../_services/quill-initialize-service.service";
import "quill-mention";
declare var require: any;
const data = require("../../../../../assets/data/application/kanban.json");
@Component({
selector: "app-kanban",
templateUrl: "./kanban.component.html",
styleUrls: ["./kanban.component.css"],
})
export class KanbanComponent implements OnInit, AfterViewInit {
public config: PerfectScrollbarConfigInterface = { wheelPropagation: true };
selectKanbanClass: any;
kanbanList: any[] = [];
kanbanValue: any;
selectKanbanArray: any[] = [];
kanban: FormGroup;
showImage: boolean;
showNewItem: boolean;
selectedLabel: any;
addTitle: string;
header: string;
blured = false;
focused = false;
atValues = [
{ id: 1, value: "Fredrik Sundqvist", link: "https://google.com" },
{ id: 2, value: "Patrik Sjölin" },
];
hashValues = [
{ id: 3, value: "Fredrik Sundqvist 2" },
{ id: 4, value: "Patrik Sjölin 2" },
];
list = [
{ id: 1, name: 'item1', children: [] },
{ id: 2, name: 'item2', children: [] },
{ id: 3, name: 'item3', children: [] },
];
kanbanquillConfig = {
toolbar: ".kanbantoolbar",
autoLink: true,
keyboard: {
bindings: {
enter: {
key: 13,
handler: (range, context) => {
console.log("enter");
return true;
},
},
},
},
};
constructor(
private _renderer: Renderer2,
private formBuilder: FormBuilder,
private QuillInitializeServiceServicec: QuillInitializeServiceService
) { }
ngOnInit(): void {
this.showNewItem = false;
this.selectKanbanClass = "bg-primary";
this.kanban = this.formBuilder.group({
title: new FormControl(['']),
date: new FormControl(['']),
selectedLabel: new FormControl(['']),
description: new FormControl([''])
});
this.kanbanList = JSON.parse(localStorage.getItem("kanban"));
if (this.kanbanList == null || this.kanbanList.length == 0) {
this.kanbanList = data;
} else { }
localStorage.setItem("kanban", JSON.stringify(this.kanbanList));
}
ngAfterViewInit(): void {
const items = localStorage.getItem("kanban");
if (items) {
this.kanbanList = JSON.parse(items);
}
}
draggable = {
// note that data is handled with JSON.stringify/JSON.parse
// only set simple data or POJO's as methods will be lost
data: "myDragData",
effectAllowed: "all",
disable: false,
handle: false
};
onDragStart(event: DragEvent) {
console.log("drag started", JSON.stringify(event, null, 2));
}
onDragEnd(event: DragEvent) {
console.log("drag ended", JSON.stringify(event, null, 2));
}
onDraggableCopied(event: DragEvent) {
console.log("draggable copied", JSON.stringify(event, null, 2));
}
onDraggableLinked(event: DragEvent) {
console.log("draggable linked", JSON.stringify(event, null, 2));
}
onDraggableMoved(event: DragEvent) {
console.log("draggable moved", JSON.stringify(event, null, 2));
}
onDragCanceled(event: DragEvent) {
console.log("drag cancelled", JSON.stringify(event, null, 2));
}
onDragover(event: DragEvent) {
console.log("dragover", JSON.stringify(event, null, 2));
}
showSidebar(event) {
const toggleIcon = document.getElementById("kanban_sidebar");
const toggle = document.getElementById("content-overlay");
if (event.currentTarget.className === "kanban-item") {
this._renderer.addClass(toggleIcon, "show");
this._renderer.addClass(toggle, "show");
} else if (
event.currentTarget.className === "ficon feather ft-x" ||
"kanban-overlay"
) {
this._renderer.removeClass(toggleIcon, "show");
this._renderer.removeClass(toggle, "show");
}
}
editItem(value, kanban) {
const date1 = value.date;
const split = date1.split('/');
let dateObj = {
"year": Number(split[2]),
"month": Number([split[0]]),
"day": Number(split[1])
}
this.kanban.setValue({
title: value.name,
date: dateObj,
selectedLabel: value.selectedLabel,
description: value.description,
})
this.kanbanValue = value
this.selectKanbanArray = kanban
if (value.selectedLabel == 'Primary') {
const toggleIcon = document.getElementById('selectLable');
this._renderer.removeClass(toggleIcon, 'bg-sucess');
this._renderer.removeClass(toggleIcon, 'bg-danger');
this._renderer.removeClass(toggleIcon, 'bg-info');
this._renderer.removeClass(toggleIcon, 'bg-warning');
this._renderer.removeClass(toggleIcon, 'bg-secondary');
this._renderer.addClass(toggleIcon, 'bg-primary');
} else if (value.selectedLabel == 'Danger') {
const toggleIcon = document.getElementById('selectLable');
this._renderer.removeClass(toggleIcon, 'bg-primary');
this._renderer.removeClass(toggleIcon, 'bg-sucess');
this._renderer.removeClass(toggleIcon, 'bg-info');
this._renderer.removeClass(toggleIcon, 'bg-warning');
this._renderer.removeClass(toggleIcon, 'bg-secondary');
this._renderer.addClass(toggleIcon, 'bg-danger');
}
else if (value.selectedLabel == 'Success') {
const toggleIcon = document.getElementById('selectLable');
this._renderer.removeClass(toggleIcon, 'bg-primary');
this._renderer.removeClass(toggleIcon, 'bg-danger');
this._renderer.removeClass(toggleIcon, 'bg-info');
this._renderer.removeClass(toggleIcon, 'bg-warning');
this._renderer.removeClass(toggleIcon, 'bg-secondary');
this._renderer.addClass(toggleIcon, 'bg-success');
}
else if (value.selectedLabel == 'Info') {
const toggleIcon = document.getElementById('selectLable');
this._renderer.removeClass(toggleIcon, 'bg-primary');
this._renderer.removeClass(toggleIcon, 'bg-danger');
this._renderer.removeClass(toggleIcon, 'bg-success');
this._renderer.removeClass(toggleIcon, 'bg-warning');
this._renderer.removeClass(toggleIcon, 'bg-secondary');
this._renderer.addClass(toggleIcon, 'bg-info');
}
else if (value.selectedLabel == 'Warning') {
const toggleIcon = document.getElementById('selectLable');
this._renderer.removeClass(toggleIcon, 'bg-primary');
this._renderer.removeClass(toggleIcon, 'bg-danger');
this._renderer.removeClass(toggleIcon, 'bg-success');
this._renderer.removeClass(toggleIcon, 'bg-info');
this._renderer.removeClass(toggleIcon, 'bg-secondary');
this._renderer.addClass(toggleIcon, 'bg-warning');
}
else if (value.selectedLabel == 'Secondary') {
const toggleIcon = document.getElementById('selectLable');
this._renderer.removeClass(toggleIcon, 'bg-primary');
this._renderer.removeClass(toggleIcon, 'bg-danger');
this._renderer.removeClass(toggleIcon, 'bg-success');
this._renderer.removeClass(toggleIcon, 'bg-warning');
this._renderer.removeClass(toggleIcon, 'bg-info');
this._renderer.addClass(toggleIcon, 'bg-secondary');
}
}
deleteKanban(event) {
this.kanbanValue;
for (let i = 0; i < this.kanbanList.length; i++) {
if (this.selectKanbanArray.length == this.kanbanList[i].tickets.length) {
for (var j = 0; j < this.selectKanbanArray.length; j++)
if (JSON.stringify(this.selectKanbanArray) === JSON.stringify(this.kanbanList[i].tickets)) {
for (var k = 0; k < this.kanbanList[i].tickets.length; k++) {
if (this.kanbanValue.name == this.kanbanList[i].tickets[k].name) {
this.kanbanList[i].tickets.splice(k, 1);
}
}
}
}
}
const toggleIcon = document.getElementById("kanban_sidebar");
const toggle = document.getElementById("content-overlay");
if (
event.currentTarget.className === "btn btn-danger delete-kanban-item mr-1"
) {
this._renderer.removeClass(toggleIcon, "show");
this._renderer.removeClass(toggle, "show");
}
}
addKanbanBoard() {
let defaultobject = {
name: "Default Title",
tickets: [],
type: "",
kanbanId: this.kanbanList.length + 1,
showNewItem: false
};
this.kanbanList.push(defaultobject);
}
public kanbanArray: any;
submitItem(kanbanArray) {
let dateObj = new Date();
var date = (dateObj.getMonth() + 1) + '/' + dateObj.getDate() + '/' + dateObj.getFullYear();
let object = {
'name': this.addTitle,
'date': date,
'selectedLabel': "Primary",
'description': this.addTitle
}
for (let i = 0; i < this.kanbanList.length; i++) {
if (kanbanArray.kanbanId == this.kanbanList[i].kanbanId && kanbanArray.tickets.length == this.kanbanList[i].tickets.length && JSON.stringify(kanbanArray.tickets) === JSON.stringify(this.kanbanList[i].tickets)) {
this.kanbanList[i].tickets.push(object),
this.kanbanList[i].showNewItem = false;
}
}
this.addTitle = null;
}
addKanbanItem(kanabanArray) {
this.addTitle = null;
for (let i = 0; i < this.kanbanList.length; i++) {
if (kanabanArray.kanbanId == this.kanbanList[i].kanbanId) {
this.kanbanList[i].showNewItem = true;
}
}
}
updateKanbanItem(event) {
let dateObj = this.kanban.value.date;
var date = dateObj.month + '/' + dateObj.day + '/' + dateObj.year
this.kanbanValue;
for (let i = 0; i < this.kanbanList.length; i++) {
if (this.selectKanbanArray.length == this.kanbanList[i].tickets.length) {
for (
var j = 0;
j < this.selectKanbanArray.length;
j++ // assert each element equal
)
JSON.stringify(this.selectKanbanArray) === JSON.stringify(this.kanbanList[i].kanabanArray);
for (var k = 0; k < this.kanbanList[i].tickets.length; k++) {
if (this.kanbanValue.name == this.kanbanList[i].tickets[k].name) {
(this.kanbanList[i].tickets[k].name = this.kanban.value.title),
(this.kanbanList[i].tickets[k].date = date),
(this.kanbanList[i].tickets[k].selectedLabel = this.kanban.value.selectedLabel),
(this.kanbanList[i].tickets[k].description = this.kanban.value.description);
}
}
this.kanbanList[i].tickets;
}
}
const toggleIcon = document.getElementById("kanban_sidebar");
const toggle = document.getElementById("content-overlay");
if (
event.currentTarget.className ===
"btn btn-primary glow update-kanban-item"
) {
this._renderer.removeClass(toggleIcon, "show");
this._renderer.removeClass(toggle, "show");
}
}
public removeItem(kanban: any, kanbanList): void {
for (let i = 0; i < this.kanbanList.length; i++) {
if (kanbanList.kanbanId == this.kanbanList[i].kanbanId) {
for (var k = 0; k < this.kanbanList[i].tickets.length; k++) {
if (kanban.name == this.kanbanList[i].tickets[k].name) {
kanbanList.tickets.splice(kanbanList.tickets.indexOf(kanban), 1);
this.kanbanList[i].tickets == kanbanList.tickets;
break;
}
}
}
}
}
cancleKanban(kanbanList) {
kanbanList.showNewItem = false;
}
deleteKanbanList(kanbanList) {
for (let i = 0; i < this.kanbanList.length; i++) {
if (JSON.stringify(kanbanList) === JSON.stringify(this.kanbanList[i])) {
this.kanbanList.splice(i, 1);
}
}
}
updateHeader(kanbanList) {
for (let i = 0; i < this.kanbanList.length; i++) {
if (JSON.stringify(kanbanList) === JSON.stringify(this.kanbanList[i])) {
this.kanbanList[i].name = this.header
}
}
}
focus() {
this.focused = true;
this.blured = false;
}
blur() {
this.focused = false;
this.blured = true;
}
validateProfile(content, kanbanList) {
this.header = content;
console.log(content);
setTimeout(() => {
this.updateHeader(kanbanList);
}, 2500);
}
getSelectedKanbanText(event: Event) {
let temp = event.target['options'][event.target['options'].selectedIndex].className;
const toggleIcon = document.getElementById('selectLable');
this._renderer.removeClass(toggleIcon, this.selectKanbanClass);
this._renderer.addClass(toggleIcon, temp);
this.selectKanbanClass = temp;
temp = null;
}
}

View File

@@ -0,0 +1,106 @@
import Delta from 'quill-delta';
import Autolinker from 'autolinker';
const defaults = {
globalRegularExpression: /https?:\/\/[\S]+/g,
urlRegularExpression: /(https?:\/\/[\S]+)/
}
export default class QuillAutoLink {
autolinker = new Autolinker();
quill;
options;
constructor (quill, options) {
this.quill = quill;
options = options || {};
this.options = {...defaults, ...options};
this.registerTypeListener();
this.registerPasteListener();
}
registerPasteListener () {
this.quill.clipboard.addMatcher(Node.TEXT_NODE, (node, delta) => {
if (typeof node.data !== 'string') {
return;
}
const matches = node.data.match(this.options.globalRegularExpression)
if (matches && matches.length > 0) {
const newDelta = new Delta();
let str = node.data;
matches.forEach(match => {
const split = str.split(match);
const beforeLink = split.shift();
newDelta.insert(beforeLink);
newDelta.insert(match, {link: match});
str = split.join(match);
})
newDelta.insert(str);
delta.ops = newDelta.ops;
}
return delta;
})
}
registerTypeListener () {
this.quill.on('text-change', (delta) => {
let ops = delta.ops
// Only return true, if last operation includes whitespace inserts
// Equivalent to listening for enter, tab or space
if (!ops || ops.length < 1 || ops.length > 2) {
return
}
let lastOp = ops[ops.length - 1]
if (!lastOp.insert || typeof lastOp.insert !== 'string' || !lastOp.insert.match(/\s/)) {
return
}
this.checkTextForUrl()
})
}
checkTextForUrl () {
let sel = this.quill.getSelection();
if (!sel) {
return;
}
let [leaf] = this.quill.getLeaf(sel.index);
if (!leaf.text) {
return;
}
if(leaf.parent != undefined && leaf.parent.domNode != undefined && leaf.parent.domNode.tagName.toLowerCase() == "a"){
return;
}
var temp = leaf.text.substring(0,leaf.text.length - 1);
var to_check_str = temp.substring(temp.lastIndexOf(' '));
this.checkIfHasLink(sel.index, to_check_str);
}
textToUrl (index,text, url) {
const ops = new Delta()
.retain(index)
.delete(text.length)
.insert(text,{link: url});
this.quill.updateContents(ops);
}
checkIfHasLink = (currentIndex: number, input: string) =>{
var hasLink = false;
var linkedText = Autolinker.link( input, {
replaceFn : ( match ) => {
switch(match.getType()){
// case 'url' :
// //console.log( "url: ", match.getUrl() );
// var index = (currentIndex - match.matchedText.length) - 1;
// this.textToUrl(index,match.matchedText,match.getUrl());
// return true; // let Autolinker perform its normal anchor tag replacement
// case 'email' :
// var email = match.getEmail();
// console.log( "email: ", email );
// return true;
// case 'phone' :
// console.log( "Phone Number: ", match.getNumber() );
}
}
} );
return hasLink;
}
}

View File

@@ -0,0 +1,42 @@
import { NgModule } from '@angular/core';
import { CommonModule, DatePipe } from '@angular/common';
import { TodoappComponent } from './todoapp.component';
import { RouterModule } from '@angular/router';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { PerfectScrollbarModule, PerfectScrollbarConfigInterface } from 'ngx-perfect-scrollbar';
import { AngularFireModule } from '@angular/fire/compat';
import { environment } from 'src/environments/environment.prod';
import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
import { TodoService } from 'src/app/_api/todo/todo.service';
import { ToastrModule } from 'ngx-toastr';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NgSelectModule } from '@ng-select/ng-select';
import { QuillModule } from 'ngx-quill';
import { ImagePreloadDirective } from '../../../_directives/image.preload.directive';
@NgModule({
declarations: [TodoappComponent, ImagePreloadDirective],
providers: [TodoService],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
PerfectScrollbarModule,
FormsModule,
NgbModule,
NgSelectModule,
QuillModule.forRoot(),
ToastrModule.forRoot(),
AngularFireModule.initializeApp(environment.firebase),
AngularFirestoreModule.enablePersistence(),
RouterModule.forChild([
{
path: '',
component: TodoappComponent
}
])
],
exports: [ImagePreloadDirective]
})
export class TodoAppModule { }

View File

@@ -0,0 +1,304 @@
:host ::ng-deep .todo-app-menu {
width: 100% !important;
padding: .5rem 0;
}
:host ::ng-deep .ml-25 {
margin-left: .25rem!important;
}
:host ::ng-deep .todo-sidebar .todo-app-menu .sidebar-menu-list .filter-label {
font-family: Quicksand,Georgia,"Times New Roman",Times,serif;
letter-spacing: 1px;
color: #bac0c7;
}
:host ::ng-deep .border {
border: 1px solid #dde1e6 !important;
}
:host ::ng-deep .ql-container.ql-snow {
border: 0px solid #ccc;
}
:host ::ng-deep .ql-toolbar.ql-snow {
border: 0px solid #ccc;
}
:host ::ng-deep .btn-primary {
height: fit-content;
margin-right: 7px;
}
:host ::ng-deep .new-taskDropdown::after {
content: "" !important;
}
:host ::ng-deep .show > .dropdownnew-task {
left: -166px !important;
}
:host ::ng-deep .show > .dropdown-sort {
left: -48px !important;
}
@media (max-width: 991.98px){
.app-content .content-right {
width: 100%!important;
}
}
:host ::ng-deep .py-75 {
padding-top: .75rem!important;
}
:host ::ng-deep .py-75 {
padding-bottom: .75rem!important;
}
:host ::ng-deep .ImageUpload {
width: 10%;
height: 10%;
}
:host ::ng-deep .add-todo{
margin-left: 10px;
}
:host ::ng-deep .todo-new-task-sidebar .avatar i {
right : 18px;
bottom : 18px;
}
:host ::ng-deep .ng-dropdown-panel .ng-dropdown-panel-items {
width: fit-content !important;
}
:host ::ng-deep .ng-select {
width: 130px;
}
@media (max-width: 349.98px) {
.sidebar .todo-sidebar {
width : 230px;
}
}
@media (max-width: 575.98px) {
.todo-new-task-sidebar {
width : 88%;
}
}
:host ::ng-deep .gradient-mint {
background-image: linear-gradient(45deg,#28d094,#28d094)!important;
width: 10px !important;
height: 10px !important;
}
:host ::ng-deep .gradient-primary{
background-image: linear-gradient(45deg,#666ee8,#666ee8)!important;
width: 10px !important;
height: 10px !important;
}
:host ::ng-deep .gradient-warning {
background-image: linear-gradient(45deg,#ff9149,#ff9149)!important;
width: 10px !important;
height: 10px !important;
}
:host ::ng-deep .gradient-danger {
background-image: linear-gradient(45deg,#ff4961,#ff4961)!important;
width: 10px !important;
height: 10px !important;
}
:host ::ng-deep .gradient-info {
background-image: linear-gradient(45deg,#1e9ff2,#1e9ff2)!important;
width: 10px !important;
height: 10px !important;
}
/* date picker css */
:host ::ng-deep .btn-light:not(:disabled):not(.disabled):active {
color: unset !important;
background-color: unset !important;
border-color: #d3d9df !important;
}
:host ::ng-deep .btn-light:hover:not(.disabled):active {
background-color: #e2e6ea !important;
border-color: #dae0e5 !important;
}
:host ::ng-deep .btn-light {
color: unset !important;
background-color: unset !important;
border-color: unset !important;
}
:host ::ng-deep .bg-primary {
background-color: #007bff !important;
}
:host ::ng-deep .text-white {
color: #fff !important;
}
:host ::ng-deep .custom-day {
text-align: center;
padding: .185rem .25rem;
display: inline-block;
height: 2rem;
width: 2rem;
}
:host ::ng-deep .custom-day:active {
color: #6d7183 !important;
background-color: #fff !important;
border-block-color: rgb(2, 117, 216) !important;
}
.bg-light {
background-color: #f8f9fa !important;
}
:host ::ng-deep .hidden {
display: block !important;
}
.ngb-dp-weekday {
color: #17a2b8;
}
.ngb-dp-week-number,
.ngb-dp-weekday {
line-height: 2rem;
text-align: center;
font-style: italic;
}
.ngb-datepicker-month-view {
pointer-events: auto;
}
.small {
font-size: 80%;
font-weight: 400;
}
.ngb-dp-day {
cursor: pointer !important;
}
.ngb-dp-month {
pointer-events: none;
}
.btn-light:hover {
color: #212529 !important;
background-color: #e2e6ea !important;
border-color: #dae0e5 !important;
}
.ngb-datepicker-month-view {
pointer-events: auto;
}
.ngb-dp-header {
border-bottom: 0;
border-radius: .25rem .25rem 0 0;
padding-top: .25rem;
}
.ngb-dp-day,
.ngb-dp-week-number,
.ngb-dp-weekday {
width: 2rem;
height: 2rem;
}
.custom-day {
text-align: center;
padding: 0.185rem 0.25rem;
display: inline-block;
height: 2rem;
width: 2rem;
}
.custom-day.focused {
background-color: #e6e6e6;
}
.custom-day.range,
.custom-day:hover {
background-color: rgb(2, 117, 216);
color: white;
}
.custom-day.faded {
background-color: rgba(2, 117, 216, 0.5);
}
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}
.custom-day {
text-align: center;
padding: 0.185rem 0.25rem;
border-radius: 0.25rem;
display: inline-block;
width: 2rem;
}
.custom-day:hover, .custom-day.focused {
background-color: #e6e6e6;
}
.weekend {
background-color: #f0ad4e;
border-radius: 1rem;
color: white;
}
.hidden {
display: none;
}
:host ::ng-deep .ft-calendar{
font-family: feather!important;
speak: none;
font-style: normal;
font-weight: 400;
font-size: large;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
:host ::ng-deep .input-group-text {
display: flex;
align-items: center;
padding: unset !important;
margin-bottom: unset !important;
font-size: unset !important;
font-weight: unset !important;
line-height: unset !important;
color:unset !important;
text-align: unset !important;
white-space: unset !important;
background-color: unset !important;
border: unset !important;
border-radius: unset !important;
}
.ml-75, .mx-75 {
margin-left: .75rem!important;
}
.mx-50 {
margin-left: .5rem!important;
}
.sidebar {
width : 270px !important;
}
.align-middle {
margin-left: 3px;
}
.mr-50, .mx-50 {
margin-right: .5rem!important;
}
:host ::ng-deep .ft-plus{
margin-right: 3px !important;
}
control:disabled, .form-control[readonly] {
background-color: #ffffff;
margin-left: -12px;
}
:host ::ng-deep .ngb-dp-header {
background-color: var(--light) !important;
}
:host ::ng-deep .ngb-dp-weekdays {
background-color: var(--light);
}
:host ::ng-deep .ngb-dp-month-name {
background-color: var(--light);
}

View File

@@ -0,0 +1,318 @@
<div class="app-content content">
<div class="sidebar-left" id="sidebar-left">
<div class="sidebar">
<div class="todo-sidebar d-flex">
<span class="sidebar-close-icon" (click)="sidebar($event)">
<i class="ficon feather ft-x"></i>
</span>
<!-- todo app menu -->
<div class="todo-app-menu">
<div class="form-group text-center add-task">
<!-- new task button -->
<button type="button" class="btn btn-danger btn-glow add-task-btn btn-block my-1"
(click)="sidebartask($event)" (click)="open()">
<i class="ficon feather ft-plus"></i>
<span>New Task</span>
</button>
</div>
<!-- sidebar list start -->
<div class="sidebar-menu-list" fxFlex="auto" [perfectScrollbar]="config">
<div class="list-group">
<a href="#" class="list-group-item border-0 ">
<span class="fonticon-wrap mr-50">
<i class="ficon feather ft-align-justify"></i>
</span>
<span> All</span>
</a>
</div>
<label class="filter-label mt-2 mb-1 pt-25">Filters</label>
<div class="list-group" *ngFor="let todo of todoFilterList">
<a [routerLink]="" class="list-group-item border-0" (click)="showTodoMenu(todo.Id, todoFilterList)"
[ngClass]="{'active':todo.isSelected === true, '':todo.isSelected === false}">
<span class="fonticon-wrap mr-50">
<i class="{{todo.lableIcon}}"></i>
</span>
<span>{{todo.lableName}}</span>
</a>
</div>
<label class="filter-label mt-2 mb-1 pt-25">Labels</label>
<div class="list-group" *ngFor="let todo of todoLableList">
<a [routerLink]="" class="list-group-item border-0 d-flex align-items-center justify-content-between"
(click)="showTodoMenu(todo.Id, todoLableList)"
[ngClass]="{'active':todo.isSelected === true, '':todo.isSelected === false}">
<span>{{todo.lableName}}</span>
<span class="{{todo.bulletClass}} d-inline-block rounded-circle "></span>
</a>
</div>
</div>
<!-- sidebar list end -->
</div>
</div>
<!-- todo new task sidebar -->
<div class="todo-new-task-sidebar" id="todo-new-task" fxFlex="auto" [perfectScrollbar]="config">
<div class="card shadow-none p-0 m-0">
<div class="card-header border-bottom py-75">
<div class="task-header d-flex justify-content-between align-items-center">
<h5 class="new-task-title mb-0" *ngIf="todoId === null">New Task</h5>
<button class="mark-complete-btn btn btn-primary btn-sm" *ngIf="todoId !== null">
<i class="ficon feather ft-check align-middle"></i>
<span class="mark-complete align-middle">Mark Complete</span>
</button>
<span class="dropdown mr-1">
<i class='ficon feather ft-paperclip cursor-pointer mr-50'></i>
<span ngbDropdown [open]="false" [autoClose]="true" class="d-inline-block">
<a class="dropdown-toggle new-taskDropdown" id="folder" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false" id="dropdownMenuButton" dropdown-menu dropdown-menu-right show
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" role="menu" ngbDropdownToggle>
<i class='ficon feather ft-more-vertical'></i>
</a>
<div ngbDropdownMenu="dropdownMenuButton" class="dropdown-menu dropdown-menu-right dropdownnew-task">
<a class="dropdown-item" [routerLink]="">Add to another project</a>
<a class="dropdown-item" [routerLink]="">Create follow up task</a>
<a class="dropdown-item" [routerLink]="">Print</a>
</div>
</span>
</span>
</div>
<button type="button" class="close close-icon" (click)="sidebartask($event)">
<i class="ficon feather ft-x"></i>
</button>
</div>
<!-- form start -->
<form [formGroup]="todo" id="compose-form" class="mt-1" (ngSubmit)="onSubmit($event)">
<div class="card-content">
<div class="card-body py-0 border-bottom">
<div class="form-group">
<!-- text area for task title -->
<textarea formControlName="title" name="title" class="form-control task-title" cols="1" rows="2"
placeholder="Write a Task Name" required>
</textarea>
</div>
<!-- Modal -->
<div class="assigned d-flex justify-content-between">
<div class="form-group d-flex align-items-center mr-1">
<div class="avatar avatar-image">
<img *ngIf="todoId === null"
[src]="selectedUserImage?selectedUserImage:'../../../../assets/images/portrait/small/default.png'"
class="avatar-user-image " id="avatar-user" alt="#" width="38" height="38">
<img *ngIf="todoId !== null"
[src]="selectedAssignee?selectedAssignee.image:'../../../../assets/images/portrait/small/default.png'"
class="avatar-user-image " id="avatar-user" alt="#" width="38" height="38">
<div class="avatar-content d-none" id="avatar-content">
<i class='ficon feather ft-user font-medium-4'></i>
</div>
</div>
<!-- select2 for user name -->
<div class="select-box mr-1">
<ng-select [items]="contact" bindLabel="name" formControlName="assignedTo"
[(ngModel)]="selectedAssignee" (change)="getSelectedTODOTypeImage($event)">
</ng-select>
</div>
</div>
<div class="form-group d-flex align-items-center position-relative">
<!-- date picker -->
<div class="input-group">
<div class="input-group-text mr-50" (click)="d2.toggle()">
<i class="ficon feather ft-calendar" style="cursor: pointer;"></i>
</div>
<input class="form-control" placeholder="yyyy-mm-dd" formControlName="assignDate"
name="assignDate" ngbDatepicker #d2="ngbDatepicker">
</div>
</div>
</div>
</div>
<div class="card-body border-bottom task-description">
<!-- Quill editor for task description -->
<div class="snow-container border rounded p-50">
<div class="compose-editor mx-75 ql-container ql-snow"></div>
<quill-editor [styles]="{height: '90px'}" [modules]="newTodoquillConfig" (onFocus)="focus()"
(onBlur)="blur()" formControlName="description"></quill-editor>
</div>
<div class="tag d-flex justify-content-between align-items-center pt-1">
<div class="flex-grow-1 d-flex align-items-center">
<i class="ficon feather ft-tag align-middle mr-25"></i>
<select class="custom-select form-control" id="todo-select" placeholder="Select Tag"
formControlName="type" name="type" (change)="getSelectedTODOTypeText($event)">
<option value="" selected>Select Tag</option>
<option value="warning">Project</option>
<option value="secondary">Product</option>
<option value="primary">Bug</option>
<option value="success">API</option>
<option value="danger">UI</option>
</select>
<!-- <ng-select [items]="multipleSelectArray" [multiple]="true" bindLabel="item_text"
formControlName="type" name="type" (change)="getSelectedTODOTypeText($event)">
</ng-select> -->
</div>
<div class="ml-25">
<i class="ficon feather ft-plus-circle cursor-pointer add-tags"></i>
</div>
</div>
</div>
<div class="card-body pb-1">
<div class="d-flex align-items-center mb-1">
<div class="avatar mr-75">
<img *ngIf="!selectedItem && loggedInUser.photoURL" src="{{currentUserImage}}" width="38"
height="38">
<img *ngIf="selectedItem && selectedItem.creator && selectedItem.creator.image"
src="{{selectedItem.creator.image}}" width="38" height="38">
<img *ngIf="(!selectedItem && !loggedInUser.photoURL) || (selectedItem && !selectedItem.creator)"
src="../../../../assets/images/portrait/small/avatar-s-19.png" width="38" height="38">
</div>
<div *ngIf="!selectedItem && currentUserName" class="avatar-content">
{{currentUserName}} creating this task
</div>
<div *ngIf="selectedItem && selectedItem.creator" class="avatar-content">
{{selectedItem.creator.name}} created this task
</div>
<div *ngIf="!currentUserName && (!selectedItem || !selectedItem.creator)" class="avatar-content">
John Doe creating this task
</div>
</div>
<h4 style="font-family:bold;">Comments:</h4>
<div class="d-flex align-items-center mb-1" *ngFor="let todo of todoComments">
<div class="avatar avatar-image">
<img [src]="todo.userid?todo.userid:'../../../../assets/images/portrait/small/default.png'"
class="avatar-user-image " id="avatar-user" alt="#" width="38" height="38">
</div>
<div class="avatar-content">
{{todo.comment}}
</div>
<small class="ml-75 text-muted">{{todo.created_at_date | date: 'dd/MMM HH:mm'}}</small>
</div>
<!-- quill editor for comment -->
<div class="snow-container border rounded p-50 ">
<div class="comment-editor mx-75 ql-container ql-snow"></div>
<div class="editor">
<quill-editor [styles]="{height: '90px'}" #quill="ngModel" [modules]="TodoquillConfig"
(onFocus)="focus()" (onBlur)="blur()" [(ngModel)]="todoCommentsField"
[ngModelOptions]="{standalone: true}"></quill-editor>
</div>
<div class="d-flex justify-content-end">
<button type="button" *ngIf="todoId !== null" class="btn btn-sm btn-primary comment-btn"
(click)="submitComment(selectedItem.id, todoCommentsField)">
<span>Comment</span>
</button>
</div>
</div>
<div class="mt-1 d-flex justify-content-end">
<button type="submit" class="btn btn-danger add-todo" *ngIf="todoId === null">Add Task</button>
<button type="button" class="btn btn-danger update-todo"
(click)="onUpdate(selectedItem.id, todo.value, $event)" *ngIf="todoId !== null">Save
Changes</button>
</div>
</div>
</div>
</form>
<!-- form start end-->
</div>
</div>
</div>
</div>
<div class="content-right">
<div class="content-overlay"></div>
<div class="content-wrapper">
<div class="content-header row">
</div>
<div class="content-body">
<div class="app-content-overlay" id="content-overlay" (click)="sidebartask($event)"></div>
<div class="todo-app-area">
<div class="todo-app-list-wrapper">
<div class="todo-app-list">
<div class="todo-fixed-search d-flex justify-content-between align-items-center">
<div class="sidebar-toggle d-block d-lg-none" (click)="sidebar($event)">
<i class="ficon feather ft-align-justify"></i>
</div>
<fieldset class="form-group position-relative has-icon-left m-0 flex-grow-1 pl-2">
<input type="text" class="form-control todo-search" id="todo-search" (keyup)="search($event)"
placeholder="Search Task">
<div class="form-control-position">
<i class="ficon feather ft-search"></i>
</div>
</fieldset>
<div class="todo-sort dropdown mr-1">
<div ngbDropdown [open]="false" [autoClose]="true" class="d-inline-block">
<button type="button" class="btn dropdown-toggle sorting" id="folder" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" id="dropdownMenuButton" dropdown-menu
dropdown-menu-right show data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
role="menu" ngbDropdownToggle>
<i class="ficon feather ft-filter"></i>
<span>Sort</span>
</button>
<div ngbDropdownMenu="dropdownMenuButton" class="dropdown-menu dropdown-menu-right dropdown-sort">
<a class="dropdown-item" [routerLink]="">Ascending</a>
<a class="dropdown-item" [routerLink]="">Descending</a>
</div>
</div>
</div>
</div>
<div class="todo-task-list list-group" [perfectScrollbar]="config">
<!-- task list start -->
<ul class="todo-task-list-wrapper list-unstyled" id="todo-task-list-drag"
*ngFor="let item of todos let i = index">
<li class="todo-item " [checked]="item.completed" [ngClass]="{'completed': item.completed}"
(click)="sidebartask($event)" (click)="editModal(item,$event)">
<div
class="todo-title-wrapper d-flex justify-content-sm-between justify-content-end align-items-center">
<div class="todo-title-area d-flex">
<i class='ficon feather ft-more-vertical handle'></i>
<div class="custom-control custom-checkbox" (click)="$event.stopPropagation();">
<input type="checkbox" [checked]="item.completed" (change)="completeTODO(item, $event)"
class="custom-control-input" id="checkbox{{i}}">
<label class="custom-control-label" for="checkbox{{i}}"></label>
</div>
<p class="todo-title mx-50 m-0 truncate">{{item.title}}</p>
</div>
<div class="todo-item-action d-flex align-items-center">
<div class="todo-badge-wrapper d-flex">
<span class="badge badge-{{item.type}} badge-pill">{{item.badge}}</span>
</div>
<div class="avatar ml-1" *ngIf="item.assignedTo">
<img src="{{item.assignedTo.image}}"
default="../../../../assets/images/portrait/small/default.png" alt="avatar" height="30"
width="30">
</div>
<a class='todo-item-favorite ml-75' [attr.id]="'todo-icon' + item.id"
(click)="todoFavorite($event,item.id)" (click)="$event.stopPropagation();"><i
class="ficon feather ft-star"></i></a>
<a class='todo-item-delete ml-75' (click)="onDelete(item.id)"
(click)="$event.stopPropagation();"><i class="ficon feather ft-trash-2"></i></a>
</div>
</div>
</li>
</ul>
<!-- task list end -->
<div class="no-results">
<h5>No Items Found</h5>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- END: Content-->

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TodoappComponent } from './todoapp.component';
describe('TodoappComponent', () => {
let component: TodoappComponent;
let fixture: ComponentFixture<TodoappComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ TodoappComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TodoappComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,765 @@
import { Component, OnInit, Renderer2, ViewChild } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { NgbDateStruct, NgbTimeStruct, NgbDate } from '@ng-bootstrap/ng-bootstrap';
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
import { TodoService } from '../../../_api/todo/todo.service';
import { AngularFirestore } from '@angular/fire/compat/firestore';
import { NgForm, FormGroup, FormControl, FormBuilder, Validators, FormArray } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
import { forkJoin } from 'rxjs';
import { QuillEditorComponent } from 'ngx-quill';
import { UserService } from '../../../_api/user/user.service';
import { QuillInitializeServiceService } from '../../../_services/quill-initialize-service.service';
import 'quill-mention';
declare let require: any;
class TodoFilter {
constructor(
public Id: string,
public lableName: string,
public isSelected: boolean
) { }
}
class Comment {
public userid: string;
public comment: string;
public created_at_date: number;
}
@Component({
selector: 'app-todoapp',
templateUrl: './todoapp.component.html',
styleUrls: ['./todoapp.component.css']
})
export class TodoappComponent implements OnInit {
initialData = require('../../../../assets/data/application/todo.json');
LableData = require('../../../../assets/data/application/todo_lable.json');
private demoUserEmail = 'john@pixinvent.com';
todo: FormGroup;
submitted = false;
commentList: Comment[] = [];
date: any;
todoDisplayList: any[] = [];
todoLableList: any[] = [];
todoFilterList: TodoFilter[] = [];
todoId: any;
todoType: 'secondary';
assignedTo: any;
selectedUserId = '';
selectedUserImage: any;
selectedAssignee: any;
assignDate: any;
todoComments: any[] = [];
todoCommentsField: string;
selectedTodoTypeText = '';
selectedTodoTypeValue = '';
isShown = true;
selectedItem: any;
completedTodo = false;
TodoId: any;
id: any;
temp: any;
todosAssigned: any;
loader = true;
blured = false;
focused = false;
hide = false;
hasFocus = false;
d2: any;
model: NgbDateStruct;
createdDate: any;
contact: any;
commentArray: any[] = [];
public isShowCropper = false;
loggedInUser = JSON.parse(localStorage.getItem('currentUser'));
demoUserImage = '../../../assets/images/portrait/small/avatar-s-19.png';
currentUserImage = this.loggedInUser.photoURL;
currentUserName = this.loggedInUser.name;
public config: PerfectScrollbarConfigInterface = {};
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective, { static: true }) directiveRef?: PerfectScrollbarDirective;
@ViewChild('editor', { static: true }) editor: QuillEditorComponent;
todos: any;
atValues = [
{ id: 1, value: 'Fredrik Sundqvist', link: 'https://google.com' },
{ id: 2, value: 'Patrik Sjölin' }
];
hashValues = [
{ id: 3, value: 'Fredrik Sundqvist 2' },
{ id: 4, value: 'Patrik Sjölin 2' }
];
newTodoquillConfig = {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike', 'image'],
]
},
autoLink: true,
mention: {
allowedChars: /^[A-Za-z\sÅÄÖåäö]*$/,
mentionDenotationChars: ['@', '#'],
source: (searchTerm, renderList, mentionChar) => {
let values;
if (mentionChar === '@') {
values = this.atValues;
} else {
values = this.hashValues;
}
if (searchTerm.length === 0) {
renderList(values, searchTerm);
} else {
const matches = [];
for (let i = 0; i < values.length; i++) {
if (values[i].value.toLowerCase().indexOf(searchTerm.toLowerCase())) {
matches.push(values[i]);
renderList(matches, searchTerm);
}
}
}
},
},
keyboard: {
bindings: {
enter: {
key: 13,
handler: (range, context) => {
console.log('enter');
return true;
}
}
}
}
};
TodoquillConfig = {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'],
]
},
autoLink: true,
// mention: {
// allowedChars: /^[A-Za-z\sÅÄÖåäö]*$/,
// mentionDenotationChars: ['@', '#'],
// source: (searchTerm: string, renderList: (arg0: any[], arg1: any) => void, mentionChar: string) => {
// let values;
// if (mentionChar === '@') {
// values = this.atValues;
// } else {
// values = this.hashValues;
// }
// if (searchTerm.length === 0) {
// renderList(values, searchTerm);
// } else {
// const matches = [];
// for (let i = 0; i < values.length; i++) {
// if (values[i].value.toLowerCase().indexOf(searchTerm.toLowerCase())) {
// matches.push(values[i]);
// renderList(matches, searchTerm);
// }
// }
// }
// },
// },
keyboard: {
bindings: {
enter: {
key: 13,
handler: (range, context) => {
console.log('enter');
return true;
}
}
}
}
};
get TodoFormGroup() {
return this.todo.get('todoComments') as FormArray;
}
/**
* Constructor
*
* @param NgbModal modal
* @param FormBuilder formBuilder
* @param Renderer2 _renderer
* @param TodoService firebaseService
* @param AngularFirestore firestore
* @param ToastrService toastr
*/
constructor(private modal: NgbModal,
private formBuilder: FormBuilder,
private _renderer: Renderer2,
private firebaseService: TodoService,
private firestore: AngularFirestore,
private toastr: ToastrService,
private modalService: NgbModal,
private userService: UserService,
private QuillInitializeServiceServicec: QuillInitializeServiceService) {
}
/**
* OnInit
*/
ngOnInit() {
this.loader = true;
this.resetForm();
this.todos = [];
this.currentUserImage = this.loggedInUser.photoURL;
this.currentUserName = this.loggedInUser.displayName;
this.todoLableList = this.LableData.todoLableList;
this.todoFilterList = this.LableData.todoFilterList;
this.userService.getUsers().subscribe(users => {
let contactList = users.map(item => {
return {
...item.payload.doc.data() as {},
id: item.payload.doc['id']
};
});
contactList = contactList.filter(element => {
return this.loggedInUser.uid !== element['uid'] || this.loggedInUser.uid === element['uid'];
});
this.contact = contactList;
});
if (this.loggedInUser.email === this.demoUserEmail) {
// To load default todo for demo account
this.getDemoAccTodos().then(todos => {
if (todos.length === 0) {
this.addDemoAccountTodos().then(result => {
if (result) {
this.loadTodos();
}
});
} else {
this.loadTodos();
}
});
} else {
this.loadTodos();
}
this.todo = this.formBuilder.group({
title: new FormControl(['', Validators.required]),
type: new FormControl(''),
description: new FormControl(''),
createdDate: new FormControl(''),
assignedTo: new FormControl(''),
assignDate: new FormControl(['', Validators.nullValidator]),
todoComments: this.formBuilder.array([
this.formBuilder.group({
comment: '',
created_at_date: '',
userid: ''
})]),
});
}
// Load TODO of user
loadTodos() {
this.firebaseService.getTODOS(this.loggedInUser.uid).subscribe(todos => {
let todo = [];
todo = todos.map(item => {
return {
...item.payload.doc.data() as {},
id: item.payload.doc['id']
};
});
this.firebaseService.getAssignedTODOS(this.loggedInUser.uid).subscribe(assignedTodos => {
let todoAssigned = [];
todoAssigned = assignedTodos.map(item => {
const toDoObj = item.payload.doc.data() as {};
if (toDoObj && toDoObj['uid'] !== this.loggedInUser.uid) {
return {
...item.payload.doc.data() as {},
id: item.payload.doc['id']
};
}
});
todoAssigned = todoAssigned.filter(item => {
return item && item['uid'];
});
this.todos = todo.concat(todoAssigned);
this.temp = this.todos;
this.loader = false;
});
});
}
/**
* Get the add todo Form value
*/
get add() {
return this.todo.controls;
}
/**
* Get the update todo Form value
*/
get update() {
return this.todo.controls;
}
/**
* Reset form value
*
* @param form Form fields with previous value
*/
resetForm(form?: NgForm) {
if (form != null) {
form.resetForm();
}
}
addDemoAccountTodos() {
const dataPromise = new Promise((resolve, reject) => {
const promises = [];
// Add default TODO for demo account
for (let i = 0; i < this.initialData.length; i++) {
const promise = this.firestore.collection('todo').add({
title: this.initialData[i].title,
description: this.initialData[i].description,
badge: this.initialData[i].badge,
type: this.initialData[i].type,
completed: this.initialData[i].completed,
isDeleted: this.initialData[i].isDeleted,
createdDate: new Date(),
uid: this.loggedInUser.uid,
assignedTo: this.initialData[i].assignedTo,
assignDate: this.initialData[i].assignDate,
todoComments: this.initialData[i].todoComments
});
promises.push(promise);
}
forkJoin(promises).subscribe(results => {
resolve(true);
});
});
return dataPromise;
}
/**
* Initial todo display
*/
getDemoAccTodos(): Promise<any> {
const dataPromise = new Promise((resolve, reject) => {
this.firebaseService.getTODOS(this.loggedInUser.uid).subscribe(todos => {
resolve(todos);
});
});
return dataPromise;
}
/**
* Add new todo
*
* Update todo
*
* @param value Form field values
* @param id todo id
*/
onSubmit(event) {
this.submitted = true;
let temp: any[] = [];
this.todo.controls.assignDate.clearValidators();
this.todo.get('assignDate').clearValidators();
this.todo.get('assignDate').updateValueAndValidity();
if (this.assignedTo) {
this.selectedAssignee = this.assignedTo;
}
if (this.todoCommentsField == null) {
temp = null;
} else if (this.todoCommentsField !== null) {
this.todoCommentsField = this.todoCommentsField.replace(/(<p>|<\/p>)/g, '');
temp = [{
comment: this.todoCommentsField,
created_at_date: Date.now(),
userid: this.currentUserImage
}];
}
if (this.todo.invalid) {
return;
} else if (this.todo.valid) {
this.todo.setValue({
uid: this.loggedInUser.uid,
title: this.todo.value.title,
description: this.todo.value.description,
type: this.selectedTodoTypeValue,
completed: false,
isDeleted: false,
createdDate: new Date(),
badge: this.selectedTodoTypeText,
assignedTo: this.todo.value.assignedTo,
assignDate: this.todo.value.assignDate,
todoComments: temp,
});
this.firebaseService.createTodo(this.todo.value).subscribe(res => {
this.toastr.success('Added', 'Todo Created Successfully.', { timeOut: 500, closeButton: true });
}, (err) => {
this.toastr.error('Error', 'Add Todo Error.', { timeOut: 500, closeButton: true });
});
const toggleIcon = document.getElementById('todo-new-task');
const toggle = document.getElementById('content-overlay');
if (event.currentTarget.className === 'mt-1 ng-dirty ng-valid ng-touched' || 'mt-1 ng-dirty ng-touched ng-valid') {
this._renderer.removeClass(toggleIcon, 'show');
this._renderer.removeClass(toggle, 'show');
}
}
}
/**
* Submit Comment
*/
submitComment(id, comments) {
if (comments != null) {
comments = comments.replace(/(<p>|<\/p>)/g, '');
}
if (!comments) {
comments = null;
}
if (this.loggedInUser.email === this.demoUserEmail) {
this.currentUserImage = this.demoUserImage;
}
if (!this.todoComments || this.todoComments.length === 0) {
this.todoComments = [];
}
// TODO Add todo comment from parameters to todoComments first
if (comments != null) {
this.todoComments.push({
comment: comments,
created_at_date: Date.now(),
userid: this.currentUserImage
});
}
if (this.todoId !== null) {
this.todo.setValue({
uid: this.todo.value.uid,
title: this.todo.value.title,
description: this.todo.value.description,
type: this.todo.value.type,
completed: false,
isDeleted: false,
createdDate: this.todo.value.createdDate,
badge: this.todo.value.badge,
assignedTo: this.todo.value.assignedTo,
assignDate: this.todo.value.assignDate,
todoComments: this.todoComments,
});
this.todoCommentsField = null;
comments = null;
this.firebaseService.updateTODO(id, this.todo.value)
.subscribe(res => {
this.toastr.success('Update', 'Todo Comment Updated Successfully.', { timeOut: 500, closeButton: true });
}, (err) => {
this.toastr.error('Error', 'Todo Comment Updated Error', { timeOut: 500, closeButton: true });
});
console.log(this.todo);
}
}
/**
* Update todo
*
* @param value Form field values
* @param id todo id
*/
onUpdate(id, value, event) {
this.submitted = true;
this.todo.controls.assignDate.clearValidators();
this.todo.get('assignDate').clearValidators();
this.todo.get('assignDate').updateValueAndValidity();
if (this.todo.invalid) {
return;
} else if (this.todo.valid) {
this.todo.setValue({
uid: this.loggedInUser.uid,
title: value.title,
description: value.description,
type: this.selectedTodoTypeValue,
completed: value.completed,
isDeleted: false,
createdDate: this.selectedItem.createdDate,
badge: this.selectedTodoTypeText,
assignedTo: value.assignedTo,
assignDate: value.assignDate,
todoComments: this.todoComments
});
this.firebaseService.updateTODO(id, this.todo.value)
.subscribe(res => {
this.toastr.success('Update', 'Todo Updated Successfully.', { timeOut: 500, closeButton: true });
}, (err) => {
this.toastr.error('Error', 'Todo Update Error!', { timeOut: 500, closeButton: true });
});
const toggleIcon = document.getElementById('todo-new-task');
const toggle = document.getElementById('content-overlay');
if (event.currentTarget.className === 'btn btn-danger update-todo ng-star-inserted' || 'btn btn-danger update-todo') {
this._renderer.removeClass(toggleIcon, 'show');
this._renderer.removeClass(toggle, 'show');
}
}
}
/**
* Delete todo
*
* @param id todo id
*/
onDelete(id: string) {
this.firebaseService.deleteTodo(id)
.then(res => {
this.toastr.success('Deleted', 'Todo Deleted Successfully!', { timeOut: 500, closeButton: true });
}, (err) => {
this.toastr.error('Error', 'Todo Delete Error!', { timeOut: 500, closeButton: true });
}
);
}
/**
* filter task
*/
search(term) {
const searchTerm = term.currentTarget.value;
if (searchTerm !== '') {
this.todos = this.todos.filter(result => {
if (result && searchTerm) {
if (result.title.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1 ||
result.description.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1) {
return true;
}
return false;
}
});
} else {
this.todos = this.temp;
}
}
/**
* Open add todo modal
*
* @param content Add todo modal id
*/
open() {
this.selectedItem = null;
this.selectedTodoTypeValue = '';
this.selectedTodoTypeText = '';
this.todoComments = [];
this.todoCommentsField = null;
this.resetForm();
this.selectedUserImage = '';
this.todoId = null;
this.todo = this.formBuilder.group({
uid: this.loggedInUser.uid,
title: '',
description: '',
type: '',
completed: false,
isDeleted: false,
createdDate: new Date(),
badge: '',
assignedTo: '',
assignDate: '',
todoComments: '',
});
}
/**
* Open edit todo modal
*
* @param editContent edit todo modal id
* @param item edit todo modal values
*/
editModal(value, event) {
this.selectedItem = value;
if (this.contact.length > 0) {
for (let index = 0; index < this.contact.length; index++) {
const element = this.contact[index];
if (element.uid === this.selectedItem.uid) {
this.selectedItem['creator'] = element;
break;
}
}
}
this.todoId = this.loggedInUser.uid;
this.TodoId = this.loggedInUser.uid;
this.todo = this.formBuilder.group({
uid: this.loggedInUser.uid,
title: this.selectedItem.title,
description: this.selectedItem.description,
type: this.selectedItem.type,
completed: value.completed,
isDeleted: false,
badge: this.selectedItem.badge,
createdDate: value.createdDate,
assignDate: value.assignDate,
assignedTo: value.assignedTo,
todoComments: value.todoComments,
});
this.todoCommentsField = value.todoComments;
if (value.assignedTo) {
this.selectedAssignee = value.assignedTo;
}
// this.firebaseService.getTODOS(this.loggedInUser.uid).subscribe(todos => {
// this.todos = todos.map(item => {
// return {
// ...item.payload.doc.data() as {},
// id: item.payload.doc.id
// };
// });
// });
for (let i = 0; i < this.todos.length; i++) {
if (value.id === this.todos[i].id) {
this.todoComments = this.todos[i].todoComments;
}
}
const toggleIcon = document.getElementById('todo-new-task');
const toggle = document.getElementById('content-overlay');
const userImage = document.getElementById('avatar-user');
const contentImage = document.getElementById('avatar-content');
if (event.currentTarget.className === 'todo-item ng-star-inserted') {
this._renderer.addClass(toggleIcon, 'show');
this._renderer.addClass(toggle, 'show');
} else if (this.todoId !== null) {
this._renderer.addClass(contentImage, 'd-none');
this._renderer.removeClass(userImage, 'd-none');
}
}
/**
* Get text and value
*
* @param event Dropdown event
*/
getSelectedTODOTypeText(event: Event) {
this.selectedTodoTypeText = event.target['options'][event.target['options'].selectedIndex].text;
this.selectedTodoTypeValue = event.target['options'][event.target['options'].selectedIndex].value;
}
getSelectedTODOTypeImage(event) {
this.selectedUserId = event.id;
this.selectImage();
}
selectImage() {
this.contact.forEach(element => {
if (this.selectedUserId === element.id) {
this.selectedUserImage = element.image;
}
});
}
completeTODO(data) {
if (data.completed) {
data.completed = false;
} else {
data.completed = true;
}
this.todo = this.formBuilder.group({
uid: this.loggedInUser.uid,
title: data.title,
description: data.description,
type: data.type,
completed: data.completed,
isDeleted: data.isDeleted,
createdDate: data.createdDate,
badge: data.badge,
assignDate: data.assignDate,
assignedTo: data.assignedTo,
// todoImage: data.todoImage,
todoComments: data.todoComments,
});
this.firebaseService.updateTODO(data.id, this.todo.value)
.subscribe(res => {
if (this.todo.value.completed === true) {
this.toastr.success('Success', 'Todo Completed.', { timeOut: 500, closeButton: true });
} else {
this.toastr.success('Success', 'Todo Updated.', { timeOut: 500, closeButton: true });
}
}, (err) => {
this.toastr.error('Error', 'Something went wrong!', { timeOut: 500, closeButton: true });
});
}
/**
* Overlay add/remove fuction in responsive
*
* @param event Overlay click event
*/
sidebartask(event) {
const toggleIcon = document.getElementById('todo-new-task');
const toggle = document.getElementById('content-overlay');
const toggleSidebarIcon = document.getElementById('sidebar-left');
const userImage = document.getElementById('avatar-user');
const contentImage = document.getElementById('avatar-content');
if (event.currentTarget.className === 'btn btn-danger btn-glow add-task-btn btn-block my-1') {
this._renderer.addClass(toggleIcon, 'show');
this._renderer.addClass(toggle, 'show');
this._renderer.removeClass(toggleSidebarIcon, 'show');
} else if (event.currentTarget.className.indexOf('todo-item') !== -1) {
this._renderer.addClass(toggleIcon, 'show');
this._renderer.addClass(toggle, 'show');
} else if (event.currentTarget.className === 'close close-icon' || 'app-content-overlay show') {
this._renderer.removeClass(toggleIcon, 'show');
this._renderer.removeClass(toggle, 'show');
this._renderer.removeClass(toggleSidebarIcon, 'show');
}
}
sidebartaskedit(event) {
const toggleIcon = document.getElementById('todo-new-task');
const toggle = document.getElementById('content-overlay');
if (event.currentTarget.className === 'btn btn-danger btn-glow add-task-btn btn-block my-1') {
this._renderer.addClass(toggleIcon, 'show');
this._renderer.addClass(toggle, 'show');
}
}
showTodoMenu(Id, todo) {
for (let j = 0; j < todo.length; j++) {
for (let i = 0; i < this.todoLableList.length; i++) {
for (let k = 0; k < this.todoFilterList.length; k++) {
if (todo[j].lableName === this.todoLableList[i].lableName) {
if (Id !== this.todoLableList[i].Id) {
this.todoLableList[i].isSelected = false;
}
if (Id === this.todoLableList[i].Id) {
this.todoLableList[i].isSelected = true;
this.todoFilterList[k].isSelected = false;
}
} else if (todo[j].lableName === this.todoFilterList[k].lableName) {
if (Id !== this.todoFilterList[k].Id) {
this.todoFilterList[k].isSelected = false;
}
if (Id === this.todoFilterList[k].Id) {
this.todoFilterList[k].isSelected = true;
this.todoLableList[i].isSelected = false;
}
}
}
}
}
}
sidebar(event) {
const toggleIcon = document.getElementById('sidebar-left');
const toggle = document.getElementById('content-overlay');
if (event.currentTarget.className === 'sidebar-toggle d-block d-lg-none') {
this._renderer.addClass(toggleIcon, 'show');
this._renderer.addClass(toggle, 'show');
} else if (event.currentTarget.className === 'sidebar-close-icon') {
this._renderer.removeClass(toggleIcon, 'show');
this._renderer.removeClass(toggle, 'show');
}
}
focus() {
this.focused = true;
this.blured = false;
}
blur() {
this.focused = false;
this.blured = true;
}
todoFavorite(event, todoId) {
const todoIcon = document.getElementById('todo-icon' + todoId);
if (event.currentTarget.className === 'todo-item-favorite ml-75') {
this._renderer.addClass(todoIcon, 'warning');
} else if (event.currentTarget.className === 'todo-item-favorite ml-75 warning') {
this._renderer.removeClass(todoIcon, 'warning');
}
}
}

View File

@@ -0,0 +1,11 @@
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}
:host ::ng-deep .list-group-item {
border: 1px solid #E4E7ED !important;
}
:host ::ng-deep .carousel-item-next:not(.carousel-item-left){
transform: unset !important;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { BootstrapComponent } from './bootstrap.component';
describe('BootstrapComponent', () => {
let component: BootstrapComponent;
let fixture: ComponentFixture<BootstrapComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ BootstrapComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BootstrapComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,110 @@
import { Component, OnInit } from '@angular/core';
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
import { NgbCarouselConfig } from '@ng-bootstrap/ng-bootstrap';
import { NgBlockUI, BlockUI } from 'ng-block-ui';
@Component({
selector: 'app-bootstrap',
templateUrl: './bootstrap.component.html',
styleUrls: ['./bootstrap.component.css']
})
export class BootstrapComponent implements OnInit {
@BlockUI('projectInfo') blockUIProjectInfo: NgBlockUI;
@BlockUI('userProfile') blockUIUserProfile: NgBlockUI;
public breadcrumb: any;
options = {
close: true,
expand: true,
minimize: true,
reload: true
};
contactForm: FormGroup;
projectInfo: FormGroup;
userProfile: FormGroup;
interestedIn = ['design', 'development', 'illustration', 'branding', 'video'];
budget = [
'less than 500$',
'500$ - 1000$',
'1000$ - 2000$',
'more than 20000$'
];
carouselOne = [
'../../../assets/images/carousel/02.jpg',
'../../../assets/images/carousel/03.jpg',
'../../../assets/images/carousel/01.jpg'
];
carouselTwo = [
'../../../assets/images/carousel/08.jpg',
'../../../assets/images/carousel/03.jpg',
'../../../assets/images/carousel/01.jpg'
];
constructor(private formBuilder: FormBuilder, config: NgbCarouselConfig) {
config.interval = 3000;
config.keyboard = false;
}
ngOnInit() {
this.breadcrumb = {
mainlabel: 'Bootstrap Cards',
links: [
{
name: 'Home',
isLink: true,
link: '/dashboard/sales'
},
{
name: 'Cards',
isLink: true,
link: '#'
}
]
};
this.contactForm = this.formBuilder.group({
name: ['', Validators.required],
email: ['', Validators.required],
message: ['', Validators.required]
});
this.projectInfo = this.formBuilder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
phone: ['', Validators.required],
company: ['', Validators.required],
interestedIn: ['', Validators.required],
budget: ['', Validators.required],
aboutProject: ['', Validators.required]
});
this.userProfile = this.formBuilder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
userName: ['', Validators.required],
nickName: ['', Validators.required],
email: ['', Validators.required],
website: ['', Validators.required],
bio: ['', Validators.required]
});
}
reloadProjectInfo() {
this.blockUIProjectInfo.start('Loading..');
setTimeout(() => {
this.blockUIProjectInfo.stop();
}, 2500);
}
reloadUserProfile() {
this.blockUIUserProfile.start('Loading..');
setTimeout(() => {
this.blockUIUserProfile.stop();
}, 2500);
}
}

View File

@@ -0,0 +1,13 @@
import { CardsModule } from './cards.module';
describe('CardsModule', () => {
let cardsModule: CardsModule;
beforeEach(() => {
cardsModule = new CardsModule();
});
it('should create an instance', () => {
expect(cardsModule).toBeTruthy();
});
});

View File

@@ -0,0 +1,33 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { BootstrapComponent } from './bootstrap/bootstrap.component';
import { CardModule } from '../partials/general/card/card.module';
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
import { ReactiveFormsModule } from '@angular/forms';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { BlockTemplateComponent } from 'src/app/_layout/blockui/block-template.component';
import { BlockUIModule } from 'ng-block-ui';
import { MatchHeightModule } from '../partials/general/match-height/match-height.module';
@NgModule({
imports: [
CommonModule,
CardModule,
NgbModule,
MatchHeightModule,
BreadcrumbModule,
ReactiveFormsModule,
BlockUIModule.forRoot({
template: BlockTemplateComponent
}),
RouterModule.forChild([{
path: 'bootstrap',
component: BootstrapComponent
},
])
],
declarations: [BootstrapComponent],
exports: [RouterModule]
})
export class CardsModule { }

View File

@@ -0,0 +1,13 @@
import { ChartjsModule } from './chartjs.module';
describe('ChartjsModule', () => {
let chartjsModule: ChartjsModule;
beforeEach(() => {
chartjsModule = new ChartjsModule();
});
it('should create an instance', () => {
expect(chartjsModule).toBeTruthy();
});
});

View File

@@ -0,0 +1,29 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { NgChartsModule } from 'ng2-charts';
import { ChartsComponent } from './charts/charts.component';
import { CardModule } from '../../partials/general/card/card.module';
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
import { BlockTemplateComponent } from 'src/app/_layout/blockui/block-template.component';
import { BlockUIModule } from 'ng-block-ui';
@NgModule({
imports: [
CommonModule,
BreadcrumbModule,
NgChartsModule,
CardModule,
BlockUIModule.forRoot({
template: BlockTemplateComponent
}),
RouterModule.forChild([
{
path: 'charts',
component: ChartsComponent
}
])
],
declarations: [ChartsComponent]
})
export class ChartjsModule { }

View File

@@ -0,0 +1,636 @@
///////////////////// start linechart ///////////
export const lineChartData: Array<any> = [
{
data: [56, 70, 55, 46, 67, 52, 70], label: 'Series C',
backgroundColor: 'rgb(138,233,204,0.5)',
borderColor: 'rgb(138,233,204,1)',
pointBackgroundColor: 'rgb(138,233,204,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(138,233,204,0.2)',
fill: true,
lineTension: 0.4,
},
{
data: [28, 48, 35, 29, 46, 27, 60], label: 'Series B',
backgroundColor: 'rgb(68,186,239,0.7)',
borderColor: 'rgb(168,186,239,1)',
pointBackgroundColor: 'rgb(168,186,239,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(168,186,239,1)',
fill: true,
lineTension: 0.4,
},
{
data: [0, 20, 11, 19, 10, 22, 9], label: 'Series A',
backgroundColor: 'rgb(1,57,204,2.11)',
borderColor: 'rgb(166,157,204,1)',
pointBackgroundColor: 'rgb(166,157,204,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(166,157,204,1)',
fill: true,
lineTension: 0.4,
}
];
export const lineChartLabels: Array<any> = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
export const lineChartOptions: any = {
animation: {
duration: 1000, // general animation timebar
easing: 'easeOutBack'
},
hover: {
animationDuration: 1000, // duration of animations when hovering an item
},
responsiveAnimationDuration: 1000, // animation duration after a resize
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [{
display: true,
ticks: {
padding: 4
},
gridLines: {
color: '#f3f3f3',
drawTicks: false,
},
title:'Month',
scaleLabel: {
display: true,
text: 'Month',
}
}],
yAxes: [{
display: true,
gridLines: {
color: '#f3f3f3',
drawTicks: false,
},
ticks: {
padding: 4
},
scaleLabel: {
display: true,
labelString: 'Value',
}
}]
},
};
export const lineChartColors: Array<any> = [
{
backgroundColor: 'rgb(138,233,204,0.5)',
borderColor: 'rgb(138,233,204,1)',
pointBackgroundColor: 'rgb(138,233,204,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(138,233,204,0.2)'
},
{
backgroundColor: 'rgb(68,186,239,0.8)',
borderColor: 'rgb(168,186,239,1)',
pointBackgroundColor: 'rgb(168,186,239,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(168,186,239,1)'
},
{
backgroundColor: 'rgb(1,57,204,2.5)',
borderColor: 'rgb(166,157,204,1)',
pointBackgroundColor: 'rgb(166,157,204,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(166,157,204,1)'
}
];
export const lineChartLegend = true;
export const lineChartType = 'line';
///////////////////// Start AreaChart///////////
export const areaChartData: Array<any> = [
{
data: [0, 150, 140, 105, 190, 230, 270], label: 'Series A',
backgroundColor: 'rgb(237,238,240,0.4)',
borderColor: 'transparent',
pointBackgroundColor: '#FFF',
pointBorderColor: 'rgb(237,238,240,0.4)',
pointHoverBackgroundColor: 'rgb(237,238,240,0.4)',
pointRadius: '5',
pointHoverBorderColor: '#FFF',
pointHoverRadius: '5',
pointBorderWidth: '2',
fill: true,
lineTension: 0.4, },
{
data: [0, 90, 120, 240, 140, 250, 190], label: 'Series B',
backgroundColor: 'rgb(133,158,233,0.9)',
borderColor: 'transparent',
pointBackgroundColor: '#FFF',
pointBorderColor: 'rgb(133,158,233,0.9)',
pointHoverBackgroundColor: 'rgb(133,158,233,0.9)',
pointRadius: '5',
pointHoverBorderColor: '#FFF',
pointHoverRadius: '5',
pointBorderWidth: '2' ,
fill: true,
lineTension: 0.4,}
];
export const areaChartLabels: Array<any> = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
export const areaChartOptions: any = {
animation: {
duration: 1000, // general animation time
easing: 'easeOutBack'
},
hover: {
animationDuration: 1000, // duration of animations when hovering an item
},
responsiveAnimationDuration: 1000, // animation duration after a resize
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [{
display: true,
gridLines: {
color: '#f3f3f3',
drawTicks: false,
},
ticks: {
padding: 4
},
scaleLabel: {
display: true,
labelString: 'Month'
}
}],
yAxes: [{
display: true,
gridLines: {
color: '#f3f3f3',
drawTicks: false,
},
ticks: {
padding: 4
},
scaleLabel: {
display: true,
labelString: 'Value'
}
}]
},
};
export const areaChartColors: Array<any> = [
{
backgroundColor: 'rgb(237,238,240,0.4)',
borderColor: 'transparent',
pointBackgroundColor: '#FFF',
pointBorderColor: 'rgb(237,238,240,0.4)',
pointHoverBackgroundColor: 'rgb(237,238,240,0.4)',
pointRadius: '5',
pointHoverBorderColor: '#FFF',
pointHoverRadius: '5',
pointBorderWidth: '2'
},
{
backgroundColor: 'rgb(133,158,233,0.9)',
borderColor: 'transparent',
pointBackgroundColor: '#FFF',
pointBorderColor: 'rgb(133,158,233,0.9)',
pointHoverBackgroundColor: 'rgb(133,158,233,0.9)',
pointRadius: '5',
pointHoverBorderColor: '#FFF',
pointHoverRadius: '5',
pointBorderWidth: '2'
},
];
export const areaChartLegend = true;
export const areaChartType = 'line';
///////////////////// End AreaChart///////////
///////////////////// End ScatterChart///////////
// scatterChart//
export const scatterChartData: Array<any> = [
{
data: [
{
x: 1,
y: -0.01711,
}, {
x: 1.26,
y: -2.708e-2,
}, {
x: 1.58,
y: -4.285e-2,
}, {
x: 2.0,
y: -6.772e-2,
}, {
x: 2.51,
y: -1.068e-1,
}, {
x: 3.16,
y: -1.681e-1,
}, {
x: 3.98,
y: -2.635e-1,
}, {
x: 5.01,
y: -4.106e-1,
}, {
x: 6.31,
y: -6.339e-1,
}, {
x: 7.94,
y: -9.659e-1,
}, {
x: 10.00,
y: -1.445,
}, {
x: 12.6,
y: -2.110,
}, {
x: 15.8,
y: -2.992,
}, {
x: 20.0,
y: -4.102,
}, {
x: 25.1,
y: -5.429,
}, {
x: 31.6,
y: -6.944,
}, {
x: 39.8,
y: -8.607,
}, {
x: 50.1,
y: -1.038e1,
}, {
x: 63.1,
y: -1.223e1,
}, {
x: 79.4,
y: -1.413e1,
}, {
x: 100.00,
y: -1.607e1,
}, {
x: 126,
y: -1.803e1,
}, {
x: 158,
y: -2e1,
}, {
x: 200,
y: -2.199e1,
}, {
x: 251,
y: -2.398e1,
}, {
x: 316,
y: -2.597e1,
}, {
x: 398,
y: -2.797e1,
}, {
x: 501,
y: -2.996e1,
}, {
x: 631,
y: -3.196e1,
}, {
x: 794,
y: -3.396e1,
}, {
x: 1000,
y: -3.596e1,
}
],
label: 'V(node2)',
backgroundColor: 'rgba(81,117,224,.6)',
borderColor: 'transparent',
pointBorderColor: '#5175E0',
pointBackgroundColor: '#FFF',
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
pointRadius: 4,
}
];
export const scatterChartLabels: Array<any> = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
export const scatterChartOptions: any = {
animation: {
duration: 1000, // general animation time
easing: 'easeOutBack'
},
hover: {
animationDuration: 1000, // duration of animations when hovering an item
},
responsiveAnimationDuration: 1000, // animation duration after a resize
responsive: true,
maintainAspectRatio: false,
scales: {
myScale: {
type: 'logarithmic',
position: 'bottom',
gridLines: {
zeroLineColor: 'rgba(0,0,0,.1)',
color: '#f3f3f3',
drawTicks: false,
},
ticks: {
padding: 4
},
scaleLabel: {
labelString: 'Frequency',
display: true,
}
},
yAxes: [{
type: 'linear',
ticks: {
padding: 4,
userCallback: function (tick) {
return tick.toString() + 'dB';
}
},
gridLines: {
zeroLineColor: 'rgba(81,117,224,1)',
color: '#f3f3f3',
drawTicks: false,
},
scaleLabel: {
labelString: 'Voltage',
display: true
}
}]
}
};
export const scatterChartLegend = true;
export const scatterChartType = 'scatter';
///////////////////// Start scatterChart ///////////////
///////////////////// Start Barchart ///////////////
export const barChartOptions: any = {
responsive: true,
scaleShowVerticalLines: false,
maintainAspectRatio: false,
scales: {
xAxes: [{
categoryPercentage: 0.5
}]
}
};
export const barChartLabels: string[] = ['2006', '2007', '2008', '2009', '2010', '2011', '2012'];
export const barChartType = 'bar';
export const barChartLegend = true;
export const barChartData: any[] = [
{
data: [65, 59, 80, 81, 56, 55, 40], label: 'Series A',
backgroundColor: '#28d094',
borderColor: '#28d094',
pointBackgroundColor: '#28d094',
pointBorderColor: '#28d094',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#28d094',
barPercentage: 0.9,
categoryPercentage: 0.5 },
{
data: [28, 48, 40, 59, 86, 27, 90], label: 'Series B',
backgroundColor: '#f98e76',
borderColor: '#f98e76',
pointBackgroundColor: '#f98e76',
pointBorderColor: '#f98e76',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#f98e76',
barPercentage: 0.9,
categoryPercentage: 0.5 }
];
export const barChartColors: Array<any> = [
{
},
{
},
];
///////////////////// End barchart////////////////
///////////////////// Start Doughnut////////////////
export const doughnutChartLabels: string[] = ['January', 'February', 'March', 'April', 'May'];
export const doughnutChartData: any[] = [350, 250, 100, 200, 80];
export const doughnutChartType = 'doughnut';
export const doughnutChartColors: any[] = ['#00a5a8', '#28d094', '#ff4558', '#ff7d4d', '#626e82'];
export const doughnutChartOptions: any = {
animation: false,
responsive: true,
maintainAspectRatio: false
};
///////////////////// End Doughnut////////////////
///////////////////// Start Radar////////////////
export const radarChartLabels: string[] = ['Eating', 'Drinking', 'Sleeping', 'Designing', 'Coding', 'Cycling', 'Running'];
export const radarChartData: any[] = [
{ label: 'Series A',
data: [65, 59, 90, 81, 56, 55, 40],
fill: true,
backgroundColor: 'rgba(245,0,87,.3)',
borderColor: 'rgba(229,229,229,0.7)',
pointBackgroundColor: 'rgba(245,0,87,.3)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(245,0,87)'},
{ label: 'Series B',
data: [28, 48, 40, 19, 96, 27, 100],
fill: true,
backgroundColor: 'rgba(29,233,182,.6)',
borderColor: 'rgba(229,229,229,0.7)',
pointBackgroundColor: 'rgb(29, 233,182)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgb(29, 233,182)' }
];
export const radarChartType = 'radar';
export const radarChartOptions: any = {
animation: false,
responsive: true,
maintainAspectRatio: false
};
///////////////////// End Radar////////////////
///////////////////// start PieChart////////////////
export const pieChartLabels: string[] = ['January', 'February', 'March', 'April', 'May'];
export const pieChartData: any[] = [300, 200, 100, 150, 80];
export const pieChartType = 'pie';
export const pieChartColors: any[] = ['#00a5a8', '#28d094', '#ff4558', '#ff7d4d', '#626e82'];
export const pieChartOptions: any = {
animation: false,
responsive: true,
maintainAspectRatio: false
};
///////////////////// end Pie chart ////////////////
///////////////////// start polar-chart///////////
// PolarArea
export const polarAreaChartLabels: string[] = ['January', 'February', 'March', 'April', 'May'];
export const polarAreaChartData: any[] = [300, 500, 100, 40, 120];
export const polarAreaLegend = true;
export const ploarChartColors: any[] = ['#00a5a8', '#28d094', '#ff4558', '#ff7d4d', '#626e82'];
export const polarChartBorderColor: any = '#fff';
export const polarAreaChartType = 'polarArea';
export const polarChartOptions: any = {
animation: false,
responsive: true,
maintainAspectRatio: false
};
///////////////////// end polar-chart///////////
// lineChartsData//
export const lineChartsData: Array<any> = [
{
data: [65, 59, 80, 81, 56, 55, 40],
label: 'My First dataset',
fill: false,
borderDash: [5, 5],
borderColor: '#9C27B0',
pointBorderColor: '#9C27B0',
pointBackgroundColor: '#FFF',
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
pointRadius: 4,
lineTension: 0.4,
},
{
data: [28, 48, 40, 19, 86, 27, 90], label: 'My Second dataset',
fill: false,
borderDash: [5, 5],
borderColor: '#00A5A8',
pointBorderColor: '#00A5A8',
pointBackgroundColor: '#FFF',
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
pointRadius: 4,
lineTension: 0.4,
},
{
data: [45, 25, 16, 36, 67, 18, 76], label: 'My Third dataset - No bezier',
lineTension: 0,
fill: false,
borderColor: '#FF7D4D',
pointBorderColor: '#FF7D4D',
pointBackgroundColor: '#FFF',
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
pointRadius: 4,
}
];
export const lineChartsLabels: Array<any> = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
export const lineChartsOptions: any = {
animation: {
duration: 1000, // general animation time
},
hover: {
animationDuration: 1000, // duration of animations when hovering an item
mode: 'label'
},
responsiveAnimationDuration: 1000, // animation duration after a resize
responsive: true,
maintainAspectRatio: false,
legend: {
position: 'bottom',
},
scales: {
myScale: [{
display: true,
gridLines: {
color: 'f3f3f3',
drawTicks: false,
},
ticks: {
padding: 4
},
scaleLabel: {
display: true,
labelString: 'Month'
}
}],
yAxes: [{
display: true,
gridLines: {
color: '#f3f3f3',
drawTicks: false,
},
ticks: {
padding: 4
},
scaleLabel: {
display: true,
labelString: 'Value'
}
}]
},
title: {
display: true,
text: 'Chart.js Line Chart - Legend'
}
};
export const lineChartsColors: Array<any> = [
{
fill: false,
borderDash: [5, 5],
borderColor: '#9C27B0',
pointBorderColor: '#9C27B0',
pointBackgroundColor: '#FFF',
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
pointRadius: 4,
},
{
fill: false,
borderDash: [5, 5],
borderColor: '#00A5A8',
pointBorderColor: '#00A5A8',
pointBackgroundColor: '#FFF',
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
pointRadius: 4,
},
{
lineTension: 0,
fill: false,
borderColor: '#FF7D4D',
pointBorderColor: '#FF7D4D',
pointBackgroundColor: '#FFF',
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
pointRadius: 4,
},
];
export const lineChartsLegend = true;
export const lineChartsType = 'line';
// lineChartsData//

View File

@@ -0,0 +1,34 @@
:host ::ng-deep .barchart {
-webkit-animation: chartjs-render-animation 0.001s;
animation: chartjs-render-animation 0.001s;
}
:host ::ng-deep .lineCharts {
-webkit-animation: chartjs-render-animation 0.001s;
animation: chartjs-render-animation 0.001s;
}
:host ::ng-deep .radarChart {
height: 470px !important;
}
:host ::ng-deep .doughnutChart {
text-align: center !important;
}
:host ::ng-deep .pieChart {
text-align: center !important;
}
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}
@media(max-width:767px) {
:host ::ng-deep .chart
{
height:400px !important;
}
}

View File

@@ -0,0 +1,200 @@
<!----- start barchart------->
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
</div>
<div class="content-body">
<!-- Bar Chart -->
<section id="chartjs-bar-charts">
<div class="row">
<div class="col-12" *blockUI="'barCharts'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadBarCharts($event)">
<ng-container mCardHeaderTitle>
Bar charts
</ng-container>
<ng-container mCardBody>
<div class="z">
<canvas class="barchart" height="400" baseChart [datasets]="barChartData" [labels]="barChartLabels"
[options]="barChartOptions" [legend]="barChartLegend" [chartType]="barChartType"></canvas>
</div>
</ng-container>
</m-card>
</div>
</div>
</section>
<!-- End Bar charts-->
<!-- line Chart -->
<section id="chartjs-line-charts">
<div class="row">
<div class="col-12" *blockUI="'lineCharts'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadLineCharts($event)">
<ng-container mCardHeaderTitle>
Line Charts
</ng-container>
<ng-container mCardBody>
<div class="card-block">
<div class="height-400">
<canvas height="400" baseChart class="chart" [datasets]="lineChartsData" [labels]="lineChartsLabels"
[options]="lineChartsOptions" [colors]="lineChartsColors" [legend]="lineChartsLegend"
[type]="lineChartsType"></canvas>
</div>
</div>
</ng-container>
</m-card>
</div>
</div>
</section>
<!-- End line chart-->
<!-- Area Line chart-->
<section id="chartjs-arealine-charts">
<div class="row">
<div class="col-12">
<m-card>
<ng-container mCardHeaderTitle>
Area Line charts
</ng-container>
<ng-container mCardBody>
<div class="card-block">
<div class="height-400">
<canvas height="400" baseChart class="chart" [datasets]="areaChartData" [labels]="areaChartLabels"
[options]="areaChartOptions" [legend]="areaChartLegend"
[type]="areaChartType">
</canvas>
</div>
</div>
</ng-container>
</m-card>
</div>
</div>
</section>
<!-- End Area Line chart------->
<!-- Line Stacked Area Chart -->
<section id="chartjs-line-stacked-charts">
<div class="row">
<div class="col-12">
<m-card>
<ng-container mCardHeaderTitle>
Line Stacked Area Chart
</ng-container>
<ng-container mCardBody>
<!-- <div class="lineStackedArea"> -->
<div class="card-block">
<div class="height-400">
<canvas height="400" baseChart class="chart" [datasets]="lineChartData" [labels]="lineChartLabels"
[options]="lineChartOptions" [legend]="lineChartLegend" [type]="lineChartType">
</canvas>
<!-- </div> -->
</div>
</div>
</ng-container>
</m-card>
</div>
</div>
</section>
<!-- End Line Stacked Area Chart -->
<!-- Scatter Logx Chart -->
<section id="chartjs-scatter-charts">
<div class="row">
<div class="col-12">
<m-card>
<ng-container mCardHeaderTitle>
Scatter Logx Chart
</ng-container>
<ng-container mCardBody>
<div class="card-block">
<div class="height-400">
<canvas height="400" id="scatter-chart" baseChart class="chart" [datasets]="scatterChartData"
[labels]="scatterChartLabels" [options]="scatterChartOptions" [legend]="scatterChartLegend"
[type]="scatterChartType"></canvas>
</div>
</div>
</ng-container>
</m-card>
</div>
</div>
</section>
<!-- End Scatter Logx Chart -->
<!-- Pie Chart -->
<section id="chartjs-pie-charts">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-content collapse show">
<div class="card-body">
<h3>Pie Chart</h3>
<div class="pieChart height-400">
<canvas baseChart width="400" style="display: unset;" [type]="'pie'" [datasets]="pieChartData"
[labels]="pieChartLabels" [options]="pieChartOptions" [plugins]="pieChartPlugins"
[legend]="pieChartLegend">
</canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- End Pie Chart -->
<!-- Doughnut Chart -->
<section id="chartjs-doughnut-charts">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-content collapse show">
<div class="card-body">
<h3>Doughnut Chart</h3>
<div class="doughnutChart height-400">
<canvas baseChart width="400" style="display: unset;" [datasets]="doughnutChartData"
[options]="doughnutChartOptions" [labels]="doughnutChartLabels" [type]="'doughnut'"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- End Doughnut Chart -->
<!-- Polar Chart -->
<section id="chartjs-polar-charts">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-content collapse show">
<div class="card-body">
<h3>Polar Chart</h3>
<div class="polarchart height-400">
<canvas baseChart [datasets]="polarAreaChartData" [labels]="polarAreaChartLabels"
[legend]="polarAreaLegend" [options]="polarChartOptions" [type]="polarAreaChartType"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- End Polar Chart -->
<!-- Radar Chart -->
<section id="chartjs-radar-charts">
<div class="row">
<div class="col-12">
<div class="card radarChart">
<div class="card-content collapse show">
<div class="card-body">
<div class="height-400">
<h3>Radar Chart</h3>
<canvas baseChart [datasets]="radarChartData" [options]="radarChartOptions"
[labels]="radarChartLabels" [type]="radarChartType"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- End Radar Chart -->
</div>
</div>
</div>
<!-- ////////////////////////////////////////////////////////////////////////////-->

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ChartsComponent } from './charts.component';
describe('ChartsComponent', () => {
let component: ChartsComponent;
let fixture: ComponentFixture<ChartsComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ ChartsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ChartsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,165 @@
import { Component, OnInit } from "@angular/core";
import { NgBlockUI, BlockUI } from "ng-block-ui";
import { ChartConfiguration, ChartOptions } from 'chart.js';
import * as chartsData from "./chartjs";
import { title } from "process";
@Component({
selector: "app-charts",
templateUrl: "./charts.component.html",
styleUrls: ["./charts.component.css"],
})
export class ChartsComponent implements OnInit {
@BlockUI("barCharts") blockUIBarCharts: NgBlockUI;
@BlockUI("lineCharts") blockUILineCharts: NgBlockUI;
public breadcrumb: any;
showNew: false;
options = {
close: true,
expand: true,
minimize: true,
reload: true,
};
/**
* barChart
*/
public barChartOptions = chartsData.barChartOptions;
public barChartLabels = chartsData.barChartLabels;
public barChartType = chartsData.barChartType;
public barChartLegend = chartsData.barChartLegend;
public barChartData = chartsData.barChartData;
public barChartColors = chartsData.barChartColors;
/**
* lineChart
*/
public lineChartData = chartsData.lineChartData;
public lineChartLabels = chartsData.lineChartLabels;
public lineChartOptions = chartsData.lineChartOptions;
public lineChartColors = chartsData.lineChartColors;
public lineChartLegend = chartsData.lineChartLegend;
public lineChartType = chartsData.lineChartType;
/**
* areaChart
*/
public areaChartData = chartsData.areaChartData;
public areaChartLabels = chartsData.areaChartLabels;
public areaChartOptions = chartsData.areaChartOptions;
public areaChartColors = chartsData.areaChartColors;
public areaChartLegend = chartsData.areaChartLegend;
public areaChartType = chartsData.areaChartType;
/**
* scatterChartData
*/
public scatterChartData = chartsData.scatterChartData;
public scatterChartLabels = chartsData.scatterChartLabels;
public scatterChartOptions = chartsData.scatterChartOptions;
// public scatterChartColors = chartsData.scatterChartColors;
public scatterChartLegend = chartsData.scatterChartLegend;
public scatterChartType = chartsData.scatterChartType;
/**
* Doughnut
*/
public doughnutChartLabels: string[] = chartsData.doughnutChartLabels;;
public doughnutChartData: ChartConfiguration<'doughnut'>['data']['datasets'] = [
{
data: chartsData.doughnutChartData,
backgroundColor: chartsData.doughnutChartColors,
},
];
public doughnutChartOptions = chartsData.doughnutChartOptions;
/**
* Radar
*/
public radarChartLabels = chartsData.radarChartLabels;
public radarChartData = chartsData.radarChartData;
public radarChartType = chartsData.radarChartType;
public radarChartOptions = chartsData.radarChartOptions;
/**
* Pie
*/
public pieChartOptions: ChartOptions<'pie'> = {
responsive: true,
};
public pieChartLabels = chartsData.pieChartLabels;
public pieChartData = [{
data: chartsData.pieChartData,
backgroundColor: chartsData.pieChartColors,
}];
public pieChartLegend = true;
public pieChartPlugins = [];
public pieChartType = chartsData.pieChartType;
/**
* PolarArea
*/
public polarAreaChartLabels = chartsData.polarAreaChartLabels;
public polarAreaChartData: ChartConfiguration<'polarArea'>['data']['datasets'] = [
{
data: chartsData.polarAreaChartData,
backgroundColor: chartsData.ploarChartColors,
borderColor: chartsData.polarChartBorderColor,
}
];
public polarAreaLegend = chartsData.polarAreaLegend;
public polarAreaChartType = chartsData.polarAreaChartType;
public polarChartOptions = chartsData.polarChartOptions;
/**
* lineChart
*/
public lineChartsData = chartsData.lineChartsData;
public lineChartsLabels = chartsData.lineChartsLabels;
public lineChartsOptions = chartsData.lineChartsOptions;
public lineChartsColors = chartsData.lineChartsColors;
public lineChartsLegend = chartsData.lineChartsLegend;
public lineChartsType = chartsData.lineChartsType;
/**
* OnInit
*/
ngOnInit() {
this.breadcrumb = {
mainlabel: "Chartjs Charts",
links: [
{
name: "Home",
isLink: true,
link: "/dashboard/sales",
},
{
name: "Chartjs",
isLink: true,
link: "#",
},
],
};
}
/**
* Reload card
*/
reloadBarCharts() {
this.blockUIBarCharts.start("Loading..");
setTimeout(() => {
this.blockUIBarCharts.stop();
}, 2500);
}
reloadLineCharts() {
this.blockUILineCharts.start("Loading..");
setTimeout(() => {
this.blockUILineCharts.stop();
}, 2500);
}
}

View File

@@ -0,0 +1,173 @@
:host ::ng-deep .lineArea2 .ct-point-circle {
stroke-width: 2px;
fill: #fff;
stroke: #ff8d60;
}
:host ::ng-deep .dragdrop-container {
min-height: 200px !important;
}
:host ::ng-deep .ct-series-b .ct-line {
stroke: #ff8d60;
stroke-width: 2px;
}
:host ::ng-deep .ct-series-a .ct-line {
stroke: #84cfd1;
stroke-width: 2px;
}
:host ::ng-deep .ct-series-c .ct-line {
stroke: #ff586b;
stroke-width: 2px;
}
:host ::ng-deep .ct-series-a .ct-area {
fill: #0eb8de;
}
:host ::ng-deep .ct-series-a .ct-point {
stroke: #84cfd1;
}
:host ::ng-deep .lineArea2 .ct-series-a .ct-point-circle {
stroke: #84cfd1;
stroke-width: 2px;
}
:host ::ng-deep .lineChart1 .ct-series-a .ct-point {
stroke-width: 0px;
stroke: #84cfd1;
}
:host ::ng-deep .lineChart1 .ct-series-b .ct-point {
stroke-width: 0px;
stroke: #ff8d60;
}
:host ::ng-deep .lineChart1 .ct-series-c .ct-point {
stroke-width: 0px;
stroke: #ff586b;
}
:host ::ng-deep .lineChart3 .ct-series-a .ct-point {
stroke-width: 10px;
stroke: #84cfd1;
}
:host ::ng-deep .lineChart3 .ct-series-b .ct-point {
stroke-width: 10px;
stroke: #ff8d60;
}
:host ::ng-deep .lineChart3 .ct-series-c .ct-point {
stroke-width: 10px;
stroke: #ff586b;
}
:host ::ng-deep .lineArea3 .ct-series-b .ct-point-circle {
stroke-width: 2px;
fill: #fff;
stroke: #ff8d60;
}
:host ::ng-deep .lineArea3 .ct-series-a .ct-point-circle {
stroke-width: 2px;
fill: #fff;
stroke: #84cfd1;
}
:host ::ng-deep .lineChart2 .ct-series-a .ct-point-circle {
stroke: #84cfd1;
stroke-width: 2px;
fill: #fff;
}
:host ::ng-deep .lineChart2 .ct-series-b .ct-point-circle {
stroke: #ff8d60;
stroke-width: 2px;
fill: #fff;
}
:host ::ng-deep .bar-chart .ct-series-b .ct-bar {
stroke: #ff8d60;
}
:host ::ng-deep .bar-chart .ct-series-a .ct-bar {
stroke: #009da0;
}
:host ::ng-deep .distributed-bar-chart .ct-series-a .ct-bar {
stroke: #009da0;
}
:host ::ng-deep .distributed-bar-chart .ct-series-b .ct-bar {
stroke: #ff8d60;
}
:host ::ng-deep .distributed-bar-chart .ct-series-c .ct-bar {
stroke: #ff586b;
}
:host ::ng-deep .distributed-bar-chart .ct-series-d .ct-bar {
stroke: #1cbcd8
}
:host ::ng-deep .distributed-bar-chart .ct-series-e .ct-bar {
stroke: #0cc27e;
}
:host ::ng-deep .distributed-bar-chart .ct-series-f .ct-bar {
stroke: #9c27b0;
}
:host ::ng-deep .distributed-bar-chart .ct-series-f .ct-bar {
stroke: #ffc107;
;
}
:host ::ng-deep .ct-series-a .ct-slice-donut {
stroke: #009da0;
}
:host ::ng-deep .ct-series-b .ct-slice-donut {
stroke: #ff8d60;
}
:host ::ng-deep .ct-series-c .ct-slice-donut {
stroke: #ff586b;
}
:host ::ng-deep .ct-series-d .ct-slice-donut {
stroke: #1cbcd8;
}
:host ::ng-deep .Bi-polar .ct-series-a .ct-area {
fill: #84cfd1;
fill-opacity: 0.6;
}
:host ::ng-deep .Bi-polar .ct-series-b .ct-area {
fill: #ff586b;
fill-opacity: 0.6;
}
:host ::ng-deep .Bi-polar .ct-series-c .ct-area {
fill: #f0c5de;
fill-opacity: 0.6;
}
:host ::ng-deep .svg {
overflow: hidden;
vertical-align: middle;
}
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}

View File

@@ -0,0 +1,292 @@
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
</div>
<div class="content-body">
<!-- chartist line charts section start -->
<!--Line with Area Chart 1 Starts-->
<div class="row text-left">
<div class="col-sm-12" *blockUI="'lineWithAreaChartOne'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadLineWithAreaChartOne($event)">
<ng-container mCardHeaderTitle>
Line with Area Chart(Filled Holes in data)
</ng-container>
<ng-container mCardBody>
<div id="line-area1" class="height-300 lineArea1">
<x-chartist *ngIf="lineArea1" [data]="lineArea1.data" [type]="lineArea1.type" [options]="lineArea1.options"
[responsiveOptions]="lineArea1.responsiveOptions" [events]="lineArea1.events">
</x-chartist>
</div>
</ng-container>
</m-card>
</div>
</div>
<!--Line with Area Chart 1 Ends-->
<!--Line with Area Chart 2 Starts-->
<div class="row text-left">
<div class="col-sm-12" *blockUI="'lineWithAreaChartTwo'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadLineWithAreaChartTwo($event)">
<ng-container mCardHeaderTitle>
Line with Area Chart(Holes in Data)
</ng-container>
<ng-container mCardBody>
<div id="line-area2" class="height-300 lineArea2">
<x-chartist *ngIf="lineArea2" [data]="lineArea2.data" [type]="lineArea2.type" [options]="lineArea2.options"
[responsiveOptions]="lineArea2.responsiveOptions" [events]="lineArea2.events">
</x-chartist>
</div>
</ng-container>
</m-card>
</div>
</div>
<!--Line with Area Chart 2 Ends-->
<!--Line with Area Chart 3 Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Line with Area Chart(Holes in Data)</h4>
</div>
<div class="card-body">
<div class="card-block">
<div id="line-area3" class="height-300 lineArea3">
<x-chartist *ngIf="lineArea3" [data]="lineArea3.data" [type]="lineArea3.type" [options]="lineArea3.options"
[responsiveOptions]="lineArea3.responsiveOptions" [events]="lineArea3.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Line with Area Chart 3 Ends-->
<!--Line with Area Chart 4 Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Simple Line with Area Chart</h4>
</div>
<div class="card-body">
<div class="card-block">
<div id="line-area4" class="height-300">
<x-chartist *ngIf="lineArea4" [data]="lineArea4.data" [type]="lineArea4.type" [options]="lineArea4.options"
[responsiveOptions]="lineArea4.responsiveOptions" [events]="lineArea4.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Line with Area Chart 4 Ends-->
<!--Line Chart 1 Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Simple Line Chart </h4>
</div>
<div class="card-body">
<div class="card-block lineChart1">
<div id="line-chart1" class="height-300 lineChart1 lineChart1Shadow">
<x-chartist *ngIf="lineChart1" [data]="lineChart1.data" [type]="lineChart1.type" [options]="lineChart1.options"
[responsiveOptions]="lineChart1.responsiveOptions" [events]="lineChart1.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Line Chart 1 Ends-->
<!--Line Chart 2 Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Line Chart(Holes in data)</h4>
</div>
<div class="card-body">
<div class="card-block">
<div id="line-chart2" class="height-300 lineChart2">
<x-chartist *ngIf="lineChart2" [data]="lineChart2.data" [type]="lineChart2.type" [options]="lineChart2.options"
[responsiveOptions]="lineChart2.responsiveOptions" [events]="lineChart2.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Line Chart 2 Ends-->
<!--Line Chart 3 Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Line Chart(Filled Holes in data)</h4>
</div>
<div class="card-body">
<div class="card-block lineChart3">
<div id="line-chart3" class="height-300">
<x-chartist *ngIf="lineChart3" [data]="lineChart3.data" [type]="lineChart3.type" [options]="lineChart3.options"
[responsiveOptions]="lineChart3.responsiveOptions" [events]="lineChart3.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Line Chart 3 Ends-->
<!--Scatter Line Chart Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Scatter Line Chart</h4>
</div>
<div class="card-body">
<div class="card-block">
<div id="scatter -line-chart" class="height-300">
<x-chartist *ngIf="scatterlineChart" [data]="scatterlineChart.data" [type]="scatterlineChart.type"
[options]="scatterlineChart.options" [responsiveOptions]="scatterlineChart.responsiveOptions"
[events]="scatterlineChart.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Scatter Line Chart Ends-->
<!--Scatter Chart Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Scatter Chart</h4>
</div>
<div class="card-body">
<div class="card-block">
<div id="scatter-chart2" class="height-300">
<x-chartist *ngIf="scatterChart" [data]="scatterChart.data" [type]="scatterChart.type" [options]="scatterChart.options"
[responsiveOptions]="scatterChart.responsiveOptions" [events]="scatterChart.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Scatter Chart Ends-->
<!--Bi-polar Line Chart Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Bi-polar Line Chart</h4>
</div>
<div class="card-body">
<div class="card-block">
<div id="bi-polar-chart" class="height-300 Bi-polar">
<x-chartist *ngIf="biPolarLineChart" [data]="biPolarLineChart.data" [type]="biPolarLineChart.type"
[options]="biPolarLineChart.options" [responsiveOptions]="biPolarLineChart.responsiveOptions"
[events]="biPolarLineChart.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Bi-polar Line Chart Ends-->
<!--Bar Chart Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Bar Chart</h4>
</div>
<div class="card-body">
<div class="card-block">
<div id="bar-chart" class="height-300 bar-chart">
<x-chartist *ngIf="barChart" [data]="barChart.data" [type]="barChart.type" [options]="barChart.options"
[responsiveOptions]="barChart.responsiveOptions" [events]="barChart.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Bar Chart Ends-->
<!--Distributed Series Bar Chart Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Distributed Series Bar Chart</h4>
</div>
<div class="card-body">
<div class="card-block">
<div id="distributed-bar-chart" class="height-300 distributed-bar-chart">
<x-chartist *ngIf="distributedSeriesBarChart" [data]="distributedSeriesBarChart.data" [type]="distributedSeriesBarChart.type"
[options]="distributedSeriesBarChart.options"
[responsiveOptions]="distributedSeriesBarChart.responsiveOptions"
[events]="distributedSeriesBarChart.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Distributed Series Bar Chart Ends-->
<!--Donut Chart 1 Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Donut Chart</h4>
</div>
<div class="card-body">
<div class="card-block">
<div id="donut-chart1" class="height-300">
<x-chartist *ngIf="donutChart1" [data]="donutChart1.data" [type]="donutChart1.type" [options]="donutChart1.options"
[responsiveOptions]="donutChart1.responsiveOptions" [events]="donutChart1.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Donut Chart 1 Ends-->
<!--Donut Chart 2 Starts-->
<div class="row text-left">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Donut Chart</h4>
</div>
<div class="card-body">
<div class="card-block">
<div id="donut-chart2" class="height-400">
<x-chartist *ngIf="donutChart2" [data]="donutChart2.data" [type]="donutChart2.type" [options]="donutChart2.options"
[responsiveOptions]="donutChart2.responsiveOptions" [events]="donutChart2.events">
</x-chartist>
</div>
</div>
</div>
</div>
</div>
</div>
<!--Donut Chart 2 Ends-->
</div>
</div>
</div>
<!-- ////////////////////////////////////////////////////////////////////////////-->

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { LinechartsComponent } from './linecharts.component';
describe('LinechartsComponent', () => {
let component: LinechartsComponent;
let fixture: ComponentFixture<LinechartsComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ LinechartsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LinechartsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,575 @@
import { Component, OnInit } from '@angular/core';
import * as Chartist from 'chartist';
import { ChartEvent, ChartType } from 'ng-chartist';
import { NgBlockUI, BlockUI } from 'ng-block-ui';
import { ChartApiService } from '../../../../_services/chart.api';
/**
* Interface
*/
export interface Chart {
type: ChartType;
data: Chartist.IChartistData;
options?: any;
responsiveOptions?: any;
events?: ChartEvent;
}
@Component({
selector: 'app-linecharts',
templateUrl: './linecharts.component.html',
styleUrls: ['./linecharts.component.css']
})
export class LinechartsComponent implements OnInit {
@BlockUI('lineWithAreaChartOne') blockUILineWithAreaChartOne: NgBlockUI;
@BlockUI('lineWithAreaChartTwo') blockUILineWithAreaChartTwo: NgBlockUI;
public breadcrumb: any;
data: any;
loadDataURL: string;
lineArea1: any;
lineArea2: any;
lineArea3: any;
lineArea4: any;
donutChart1: any;
donutChart2: any;
scatterChart: any;
scatterlineChart: any;
lineChart1: any;
lineChart2: any;
lineChart3: any;
biPolarLineChart: any;
barChart: any;
distributedSeriesBarChart: any;
options = {
close: true,
expand: true,
minimize: true,
reload: true
};
constructor(private chartApiservice: ChartApiService) {
}
/**
* Get chart data
*/
getlineArea() {
const Chartdata = this.data;
// Line with Area Chart 1 Starts
this.lineArea1 = {
type: 'Line',
data: Chartdata['lineArea1'],
options: {
height: '300px',
low: 0,
showArea: true,
fullWidth: true,
onlyInteger: true,
axisY: {
low: 0,
scaleMinSpace: 50,
},
axisX: {
showGrid: false
},
},
responsiveOptions: [
['screen and (max-width: 640px) and (min-width: 381px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}],
['screen and (max-width: 380px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}]
],
events: {
created(data: any): void {
const defs = data.svg.elem('defs');
defs.elem('linearGradient', {
id: 'gradient',
x1: 0,
y1: 1,
x2: 0,
y2: 0
}).elem('stop', {
offset: 0,
'stop-color': 'rgba(255, 255, 255, 1)'
}).parent().elem('stop', {
offset: 1,
'stop-color': 'rgba(38, 198, 218, 1)'
});
},
},
};
// Line with Area Chart 1 Ends
// Line with Area Chart 2 Starts
this.lineArea2 = {
type: 'Line',
data: Chartdata['lineArea2'],
options: {
height: '300px',
showArea: true,
fullWidth: true,
lineSmooth: Chartist.Interpolation.none(),
axisX: {
showGrid: false,
},
axisY: {
low: 0,
scaleMinSpace: 50,
},
chartPadding: { top: 0, right: 25, bottom: 0, left: 0 },
},
responsiveOptions: [
['screen and (max-width: 640px) and (min-width: 381px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}],
['screen and (max-width: 380px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}]
],
events: {
created(data: any): void {
const defs = data.svg.elem('defs');
defs.elem('linearGradient', {
id: 'gradient1',
x1: 0,
y1: 1,
x2: 0,
y2: 0
}).elem('stop', {
offset: 0.2,
'stop-color': 'rgba(255, 255, 255, 1)'
}).parent().elem('stop', {
offset: 1,
'stop-color': 'rgba(38, 198, 218, 1)'
});
defs.elem('linearGradient', {
id: 'gradient2',
x1: 0,
y1: 1,
x2: 0,
y2: 0
}).elem('stop', {
offset: 0.5,
'stop-color': 'rgba(255, 255, 255, 1)'
}).parent().elem('stop', {
offset: 1,
'stop-color': 'rgba(255,141,96, 1)'
});
},
draw(data: any): void {
const circleRadius = 6;
if (data.type === 'point') {
const circle = new Chartist.Svg('circle', {
cx: data.x,
cy: data.y,
r: circleRadius,
class: 'ct-point-circle'
});
data.element.replace(circle);
}
}
},
};
// Line with Area Chart 2 Ends
// Line with Area Chart 3 Starts
this.lineArea3 = {
type: 'Line',
data: Chartdata['lineArea3'],
options: {
height: '300px',
low: 0,
showArea: true,
fullWidth: true,
onlyInteger: true,
axisY: {
low: 0,
scaleMinSpace: 50,
}
},
responsiveOptions: [
['screen and (max-width: 640px) and (min-width: 381px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}],
['screen and (max-width: 380px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}]
],
events: {
created(data: any): void {
const defs = data.svg.elem('defs');
defs.elem('linearGradient', {
id: 'gradient',
x1: 0,
y1: 1,
x2: 0,
y2: 0
}).elem('stop', {
offset: 0,
'stop-color': 'rgba(255, 255, 255, 1)'
}).parent().elem('stop', {
offset: 1,
'stop-color': 'rgba(38, 198, 218, 1)'
});
},
draw(data: any): void {
const circleRadius = 6;
if (data.type === 'point') {
const circle = new Chartist.Svg('circle', {
cx: data.x,
cy: data.y,
r: circleRadius,
class: 'ct-point-circle'
});
data.element.replace(circle);
}
}
},
};
// Line with Area Chart 3 Ends
// Line with Area Chart 4 Starts
this.lineArea4 = {
type: 'Line',
data: Chartdata['lineArea4'],
options: {
fullwidth: true,
height: '300px',
low: 0,
showArea: true,
fullWidth: true,
},
};
// Line with Area Chart 4 Ends
// Line Chart 1 Starts
this.lineChart1 = {
type: 'Line',
data: Chartdata['line1'],
options: {
fullwidth: true,
height: '300px',
axisX: {
showGrid: false,
},
axisY: {
low: 0,
scaleMinSpace: 50,
},
fullWidth: true,
chartPadding: { top: 0, right: 25, bottom: 0, left: 0 }
},
};
// Line Chart 1 Ends
// Line Chart 2 Starts
this.lineChart2 = {
type: 'Line',
data: Chartdata['line2'],
options: {
fullwidth: true,
height: '300px',
axisX: {
showGrid: false,
},
axisY: {
low: 0,
scaleMinSpace: 50,
},
fullWidth: true,
chartPadding: { top: 0, right: 25, bottom: 0, left: 0 },
},
responsiveOptions: [
[{
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}],
['screen and (max-width: 380px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}]
],
events: {
draw(data: any): void {
const circleRadius = 6;
if (data.type === 'point') {
const circle = new Chartist.Svg('circle', {
cx: data.x,
cy: data.y,
r: circleRadius,
class: 'ct-point-circle'
});
data.element.replace(circle);
}
}
},
};
// Line Chart 2 Ends
// Line Chart 3 Starts
this.lineChart3 = {
type: 'Line',
data: Chartdata['Line3'],
options: {
fullwidth: true,
height: '300px',
axisX: { showGrid: false }, axisY: {
scaleMinSpace: 30,
}, fullWidth: true,
chartPadding: { top: 0, right: 50, bottom: 0, left: 0 },
},
responsiveOptions: [
['screen and (max-width: 640px) and (min-width: 381px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}],
['screen and (max-width: 380px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}]
],
};
// Line Chart 3 Ends
// Scatter Line Chart Starts
this.scatterlineChart = {
type: 'Line',
data: Chartdata['ScatterLine'],
options: {
fullwidth: true,
height: '300px',
axisX: { showGrid: false }, axisY: {
scaleMinSpace: 30,
}, fullWidth: true,
},
responsiveOptions: [
['screen and (max-width: 640px) and (min-width: 381px) and (min-hight: 300px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}],
['screen and (max-width: 380px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}]
],
};
// Scatter Line Chart Ends
// Scatter Chart Starts
this.scatterChart = {
type: 'Line',
data: Chartdata['Scatter'],
options: {
fullwidth: true,
height: '300px',
showLine: false,
axisX: {
labelInterpolationFnc: function (value: number, index: number): string {
return index % 13 === 0 ? `W${value}` : null;
},
showGrid: false
},
axisY: {
scaleMinSpace: 30,
}
},
responsiveOptions: [
[
'screen and (min-width: 640px)',
{
axisX: {
labelInterpolationFnc: function (value: number, index: number): string {
return index % 4 === 0 ? `W${value}` : null;
}
}
}
]
]
};
// Scatter Chart Ends
// Bi-polar Line Chart Starts
this.biPolarLineChart = {
type: 'Line',
data: Chartdata['Bi-PolarLine'],
options: {
fullwidth: true,
height: '350px',
showArea: true,
showLine: false,
showPoint: false,
fullWidth: true,
axisX: {
showGrid: false,
offset: 100,
labelInterpolationFnc: function (value: number, index: number): number {
return index % 2 === 0 ? value : null;
}
},
axisY: {
scaleMinSpace: 30,
}
}
};
// Bi-polar Line Chart Ends
// Bar Chart Starts
this.barChart = {
type: 'Bar',
data: Chartdata['Bar'],
options: {
fullwidth: true,
height: '350px',
seriesBarDistance: 21,
axisX: {
showGrid: false, offset: 100
},
axisY: {
scaleMinSpace: 30,
}
},
};
// Bar Chart Ends
// Distributed Series Bar Chart Starts
this.distributedSeriesBarChart = {
type: 'Bar',
data: Chartdata['DistributedSeries'],
options: {
fullwidth: true,
height: '300px',
showGrid: false,
distributeSeries: true,
axisY: {
scaleMinSpace: 30,
}
},
};
// Distributed Series Bar Chart Ends
// Donut Chart 1 Starts
this.donutChart1 = {
type: 'Pie',
data: Chartdata['donut'],
options: {
fullwidth: true,
height: '400px',
donut: true,
donutWidth: 60,
startAngle: 270,
total: 200,
showLabel: true,
},
};
// Donut Chart 1 Ends
// Donut Chart 2 Starts
this.donutChart2 = {
type: 'Pie',
data: Chartdata['donut'],
options: {
fullwidth: true,
height: '400px',
donut: true,
showLabel: true,
labelDirection: 'implode',
},
};
// Donut Chart 2 Ends
}
/**
* OnInit
*/
ngOnInit() {
this.breadcrumb = {
'mainlabel': 'Chartist Charts',
'links': [
{
'name': 'Home',
'isLink': true,
'link': '/dashboard/sales'
},
{
'name': 'Chartist',
'isLink': true,
'link': '#'
}
]
};
this.chartApiservice.getChartistData().subscribe(Response => {
this.data = Response;
this.getlineArea();
});
}
/**
* Reload card
*/
reloadLineWithAreaChartOne() {
this.blockUILineWithAreaChartOne.start('Loading..');
setTimeout(() => {
this.blockUILineWithAreaChartOne.stop();
}, 2500);
}
/**
* Reload card
*/
reloadLineWithAreaChartTwo() {
this.blockUILineWithAreaChartTwo.start('Loading..');
setTimeout(() => {
this.blockUILineWithAreaChartTwo.stop();
}, 2500);
}
}

View File

@@ -0,0 +1,13 @@
import { NgchartistModule } from './ngchartist.module';
describe('NgchartistModule', () => {
let ngchartistModule: NgchartistModule;
beforeEach(() => {
ngchartistModule = new NgchartistModule();
});
it('should create an instance', () => {
expect(ngchartistModule).toBeTruthy();
});
});

View File

@@ -0,0 +1,30 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CardModule } from '../../partials/general/card/card.module';
import { ChartistModule } from 'ng-chartist';
import { RouterModule } from '@angular/router';
import { LinechartsComponent } from './linecharts/linecharts.component';
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
import { BlockTemplateComponent } from 'src/app/_layout/blockui/block-template.component';
import { BlockUIModule } from 'ng-block-ui';
@NgModule({
imports: [
CommonModule,
CardModule,
BreadcrumbModule,
ChartistModule,
BlockUIModule.forRoot({
template: BlockTemplateComponent
}),
RouterModule.forChild([
{
path: 'linecharts',
component: LinechartsComponent
},
]),
],
declarations: [LinechartsComponent]
})
export class NgchartistModule { }

View File

@@ -0,0 +1,13 @@
import { DashboardModule } from './dashboard.module';
describe('DashboardModule', () => {
let dashboardModule: DashboardModule;
beforeEach(() => {
dashboardModule = new DashboardModule();
});
it('should create an instance', () => {
expect(dashboardModule).toBeTruthy();
});
});

View File

@@ -0,0 +1,51 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { EcommerceComponent } from './ecommerce/ecommerce.component';
import { ChartistModule } from 'ng-chartist';
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
import { FormsModule } from '@angular/forms';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { CardModule } from '../partials/general/card/card.module';
import { NgChartsModule } from 'ng2-charts';
import { SalesComponent } from './sales/sales.component';
import { BlockUIModule } from 'ng-block-ui';
import { BlockTemplateComponent } from '../../_layout/blockui/block-template.component';
import { MatchHeightModule } from '../partials/general/match-height/match-height.module';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { HospitalComponent } from './hospital/hospital.component';
@NgModule({
imports: [
CommonModule,
ChartistModule,
FormsModule,
NgChartsModule,
CardModule,
MatchHeightModule,
NgxDatatableModule,
PerfectScrollbarModule,
NgbModule,
BlockUIModule.forRoot({
template: BlockTemplateComponent
}),
RouterModule.forChild([
{
path: 'ecommerce',
component: EcommerceComponent
},
{
path: 'sales',
component: SalesComponent
},
{
path: 'hospital',
component: HospitalComponent
}
])
],
declarations: [EcommerceComponent, SalesComponent, HospitalComponent],
exports: [RouterModule]
})
export class DashboardModule { }

View File

@@ -0,0 +1,414 @@
.avatar-xs {
width: 24px !important;
margin-right: 5px !important;
}
.btn_set_padding {
padding: 0% !important;
}
.chart_body_padding {
padding: 2rem !important;
}
:host ::ng-deep .scoreLineShadow {
-webkit-filter: drop-shadow(0px 20px 11px rgba(0, 0, 0, 0.5)) !important;
filter: drop-shadow(0px 20px 11px rgba(0, 0, 0, 0.5));
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-a .ct-point-circle {
stroke-width: 5px;
stroke: #ffffff;
fill: #1e9ff2;
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-b .ct-point-circle {
stroke-width: 5px;
stroke: #ffffff;
fill: #58e0cd;
;
}
:host ::ng-deep .media {
display: flex;
align-items: flex-start;
}
:host ::ng-deep .position-relative {
position: relative !important;
}
:host ::ng-deep .ct-series-b .ct-bar,
.ct-series-b .ct-slice-donut {
stroke: #beb6b6;
}
:host ::ng-deep .progress:last-child {
width: 100% !important;
}
:host ::ng-deep .areaChartLegend .ct-series-a .ct-line {
stroke: url(#gradient2);
stroke-width: 5px;
stroke-linecap: round;
}
:host ::ng-deep .areaChartLegend .ct-series-a .ct-area {
fill: #ffffff;
}
:host ::ng-deep .areaChartLegend .ct-series-a .ct-line {
stroke: #3da2ea;
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-a .ct-area {
fill: #4105f9f5;
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-b .ct-area {
fill: #03f7b2fa;
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-b .ct-line {
stroke: #58e0cd;
}
:host ::ng-deep .ecommercesaleslineArea .ct-series-a .ct-line {
stroke: #1e9ff2;
}
:host ::ng-deep .barchart .ct-series-a .ct-bar {
stroke: #ff394f !important;
stroke-width: 7px !important;
}
:host ::ng-deep .pull-up {
-webkit-transition: all 0.25s ease;
-o-transition: all 0.25s ease;
-moz-transition: all 0.25s ease;
transition: all 0.25s ease;
}
:host ::ng-deep .chart-info {
margin-top: 73px !important;
}
.mb-3,
.my-3 {
margin-bottom: -4rem !important;
}
.mb-2,
.my-2 {
margin-bottom: -4.5rem !important;
}
:host ::ng-deep .donut .ct-done .ct-slice-donut {
stroke: #28d094;
stroke-width: 24px !important;
}
:host ::ng-deep .donut .ct-progress .ct-slice-donut {
stroke: #ff4558;
stroke-width: 16px !important;
}
:host ::ng-deep .donut .ct-outstanding .ct-slice-donut {
stroke: #ff7d4d;
stroke-width: 8px !important;
}
:host ::ng-deep .donut .ct-started .ct-slice-donut {
stroke: #666ECC;
stroke-width: 32px !important;
}
:host ::ng-deep .donut .ct-label {
text-anchor: middle;
font-size: 20px;
fill: #868e96;
}
:host ::ng-deep .Barchart {
display: block;
margin-left: -100px;
margin-bottom: -60px;
margin-top: -45px;
}
:host ::ng-deep .Barchart .ct-label {
font-size: 0.75rem;
line-height: 15;
}
.p {
margin-top: 1rem;
margin-bottom: -1.5rem;
font-size: large;
color: #6c757d !important;
}
:host ::ng-deep .text-center .p {
margin-top: 2rem;
margin-bottom: -1.2rem;
}
:host ::ng-deep .height-300 {
height: 250px !important;
}
:host ::ng-deep .gradient-blackberry {
background-image: linear-gradient(45deg, #b9e2fa, #b9e2fa) !important;
margin-left: 48px;
}
:host ::ng-deep .gradient-mint {
background-image: linear-gradient(45deg, #ff9ba6, #ff9ba6);
margin-left: 48px;
}
:host ::ng-deep .gradient-info {
background-image: linear-gradient(45deg, #6ef9d6, #6ef9d6);
margin-left: 48px;
}
:host ::ng-deep .extraPadding7 {
padding: 0.7rem;
}
:host ::ng-deep .avatar-md {
width: 40px;
}
:host ::ng-deep .square {
border-radius: 0% !important;
height: auto;
border: 2px solid #FFF !important;
}
:host ::ng-deep .ps--active-x>.ps__rail-x {
display: none !important;
}
:host ::ng-deep .border-top-0 {
padding: 1.25rem 2rem !important;
}
:host ::ng-deep .btn-danger {
color: white !important;
}
:host ::ng-deep .progress:last-child {
margin-bottom: 0rem;
}
:host ::ng-deep .btn.active {
outline: none;
-webkit-box-shadow: none !important;
box-shadow: none !important;
background-color: #2196F3 !important;
color: white !important;
}
.btn {
cursor: pointer !important;
}
.btn_dropdown {
background-color: white !important;
}
:host ::ng-deep .text_color {
color: #0c84d1;
}
:host ::ng-deep .progress {
box-shadow: 6px 6px 14px -1px rgba(62, 57, 107, .2);
margin-top: 1rem !important;
}
:host ::ng-deep .btn-group {
position: absolute !important;
}
@media only screen and (max-width:767px) {
.btn-group {
position: relative !important;
}
}
:host ::ng-deep .text-muted {
color: #6b6f82 !important;
}
:host ::ng-deep .mb-3,
.my-3 {
margin-bottom: 1.5rem !important;
}
:host ::ng-deep .media {
display: flex;
align-items: flex-start;
}
:host ::ng-deep .height-350 {
height: 250px !important;
margin-left: 18%;
margin-bottom: 55px;
}
:host ::ng-deep .card-text:last-child {
margin-bottom: 0;
height: 430px;
}
:host ::ng-deep .mb-3 {
margin-bottom: 1.1rem !important;
}
:host ::ng-deep .chart-info .p {
margin-top: 0;
margin-bottom: 1rem;
margin-left: 4px;
}
:host ::ng-deep .order-tbl_change th,
.order-tbl_change td {
padding-right: 0.8rem;
}
:host ::ng-deep svg.ct-chart-bar {
width: 100% !important;
padding-top: 5%;
}
:host ::ng-deep #donut-dashboard-chart {
margin-left: auto;
margin-right: auto;
display: flex;
align-items: center;
justify-content: center;
}
:host ::ng-deep .pr_stats {
text-align: center
}
:host ::ng-deep .height-300 {
width: 100%;
}
:host ::ng-deep .alert_basics_charrt {
padding: 0;
}
:host ::ng-deep .card-header .heading-elements a.btn {
color: white !important;
}
:host ::ng-deep .row_padding {
padding: 1.25rem 2rem !important;
}
:host ::ng-deep .border_bottom {
margin-bottom: 0rem !important;
}
:host ::ng-deep .top_space {
padding-top: 5% !important;
}
:host ::ng-deep .border_top {
border-top: none !important;
}
:host ::ng-deep .card-footer {
padding: 2rem !important;
}
:host ::ng-deep .ct-chart-bar .ct-label.ct-horizontal.ct-end {
text-anchor: middle;
font-family: sans-serif;
font-size: 12px;
font-weight: 700;
}
:host ::ng-deep .ct-chart-bar .ct-label.ct-vertical.ct-start {
text-anchor: middle;
font-family: sans-serif;
font-size: 12px;
font-weight: 500;
}
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}
:host ::ng-deep .chartist-tooltip.bar_tooltip {
border-radius: 10px;
padding: 18px;
color: rgb(29, 28, 28);
height: 60px;
width: 80px;
background: rgba(255, 255, 255, 0.9);
border: solid 2px rgba(230, 230, 230, 0.9);
font-family: sans-serif;
font-size: 14px;
text-align: center;
}
:host ::ng-deep .chartist-tooltip.donut_tooltip {
border-radius: 10px;
padding: 2px;
color: rgb(29, 28, 28);
height: 60px;
width: 90px;
background: rgba(255, 255, 255, 0.9);
border: solid 2px rgba(230, 230, 230, 0.9);
font-family: sans-serif;
font-size: 14px;
text-align: center;
top: 16.906px;
}
:host ::ng-deep .chartist-tooltip.tooltip-show {
opacity: 0.6 !important;
}
:host ::ng-deep .chartist-tooltip.bar_tooltip:before {
content: "";
position: absolute;
top: 100%;
left: 50%;
width: 0;
height: 0;
margin-left: -15px;
border: 15px solid transparent;
border-top-color: rgba(255, 255, 255, 0.8);
}
:host ::ng-deep .chartist-tooltip.donut_tooltip:before {
content: "";
position: absolute;
top: 100%;
left: 50%;
width: 0;
height: 0;
margin-left: -15px;
border: 15px solid transparent;
border-top-color: rgba(255, 255, 255, 0.8);
}
:host ::ng-deep .tab-content > .tab-pane,
.pill-content > .pill-pane {
display: block;
height: 0;
overflow-y: hidden;
}
:host ::ng-deep .tab-content > .active,
.pill-content > .active {
height: auto;
}

View File

@@ -0,0 +1,510 @@
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1">
</div>
<div class="content-body">
<!-- eCommerce statistic -->
<div class="row">
<div class="col-xl-3 col-lg-6 col-12">
<div class="card pull-up">
<div class="card-content">
<div class="card-body card_padding">
<div class="media d-flex">
<div class="media-body text-left">
<h3 class="info">850</h3>
<h6>Products Sold</h6>
</div>
<div>
<i class="icon-basket-loaded info font-large-2 float-right"></i>
</div>
</div>
<div class="mb-0 mt-1">
<ngb-progressbar height="7px" width="100%" type="gradient-x-info" [value]="80"></ngb-progressbar>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6 col-12">
<div class="card pull-up">
<div class="card-content">
<div class="card-body card_padding">
<div class="media d-flex">
<div class="media-body text-left">
<h3 class="warning">$748</h3>
<h6>Net Profit</h6>
</div>
<div>
<i class="icon-pie-chart warning font-large-2 float-right"></i>
</div>
</div>
<div class="mb-0 mt-1">
<ngb-progressbar height="7px" width="100%" type="gradient-x-warning" [value]="65">
</ngb-progressbar>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6 col-12">
<div class="card pull-up">
<div class="card-content">
<div class="card-body card_padding">
<div class="media d-flex">
<div class="media-body text-left">
<h3 class="success">146</h3>
<h6>New Customers</h6>
</div>
<div>
<i class="icon-user-follow success font-large-2 float-right"></i>
</div>
</div>
<div class="mb-0 mt-1">
<ngb-progressbar height="7px" width="100%" type="gradient-x-success" [value]="75"></ngb-progressbar>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6 col-12">
<div class="card pull-up">
<div class="card-content">
<div class="card-body card_padding">
<div class="media d-flex">
<div class="media-body text-left">
<h3 class="danger">99.89 %</h3>
<h6>Customer Satisfaction</h6>
</div>
<div>
<i class="icon-heart danger font-large-2 float-right"></i>
</div>
</div>
<div class="mb-0 mt-1">
<ngb-progressbar height="7px" width="100%" type="gradient-x-danger" [value]="85"></ngb-progressbar>
</div>
</div>
</div>
</div>
</div>
</div>
<!--/ eCommerce statistic -->
<!-- Products sell and New Orders -->
<div class="row">
<div class="col-xl-8 col-12">
<div class="card card-shadow">
<div class="card-header card-header-transparent py-20">
<div class="btn-group dropdown">
<a [routerLink]="" ngbDropdown class="d-inline-block">
<button class="btn btn_dropdown btn_set_padding btn-dropdown-toggle" id="dropdownBasic1"
ngbDropdownToggle>PRODUCTS SALES</button>
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
<button class="dropdown-item">Sales</button>
<button class="dropdown-item">Total Sales</button>
<button class="dropdown-item">Profit</button>
</div>
</a>
</div>
<ul ngbNav #nav="ngbNav" class="justify-content-end nav nav-pills">
<li [ngbNavItem]="1">
<a ngbNavLink>Day</a>
<ng-template ngbNavContent>
<div class="areaChartLegend scoreLineShadow">
<x-chartist *ngIf="lineAreaDay" [data]="lineAreaDay.data" [type]="lineAreaDay.type"
[options]="lineAreaDay.options" [responsiveOptions]="lineAreaDay.responsiveOptions"
[events]="lineAreaDay.events">
</x-chartist>
</div>
</ng-template>
</li>
<li [ngbNavItem]="2">
<a ngbNavLink>Week</a>
<ng-template ngbNavContent>
<div class="areaChartLegend scoreLineShadow">
<x-chartist *ngIf="lineAreaWeek" [data]="lineAreaWeek.data" [type]="lineAreaWeek.type"
[options]="lineAreaWeek.options" [responsiveOptions]="lineAreaWeek.responsiveOptions"
[events]="lineAreaWeek.events">
</x-chartist>
</div>
</ng-template>
</li>
<li [ngbNavItem]="3">
<a ngbNavLink>Month</a>
<ng-template ngbNavContent>
<div class="areaChartLegend scoreLineShadow">
<x-chartist *ngIf="lineAreaMonth" [data]="lineAreaMonth.data" [type]="lineAreaMonth.type"
[options]="lineAreaMonth.options" [responsiveOptions]="lineAreaMonth.responsiveOptions"
[events]="lineAreaMonth.events">
</x-chartist>
</div>
</ng-template>
</li>
</ul>
<div [ngbNavOutlet]="nav"></div>
</div>
<br>
</div>
</div>
<div class="col-xl-4 col-lg-12" *blockUI="'newOrders'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadNewOrders($event)">
<ng-container mCardHeaderTitle>
New Orders
</ng-container>
<ng-container mCardContent>
<div id="new-orders" class="media-list position-relative">
<div class="table-responsive">
<table id="new-orders-table" class="table table-hover table-xl mb-0 order-tbl_change">
<thead>
<tr>
<th class="border-top-0">Product</th>
<th class="border-top-0">Customers</th>
<th class="border-top-0">Total</th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-truncate">iPhone X</td>
<td class="text-truncate p-1">
<ul class="list-unstyled users-list m-0">
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="John Doe"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-19.png" alt="Avatar">
</li>
<li data-toggle="tooltip" data-popup="tooltip-custom"
data-original-title="Katherine Nichols" class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-18.png" alt="Avatar">
</li>
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Joseph Weaver"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-17.png" alt="Avatar">
</li>
<li class="avatar avatar-sm">
<span class="badge badge-info">+4 more</span>
</li>
</ul>
</td>
<td class="text-truncate">$8999</td>
</tr>
<tr>
<td class="text-truncate">Pixel 2</td>
<td class="text-truncate p-1">
<ul class="list-unstyled users-list m-0">
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Alice Scott"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-16.png" alt="Avatar">
</li>
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Charles Miller"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-15.png" alt="Avatar">
</li>
</ul>
</td>
<td class="text-truncate">$5550</td>
</tr>
<tr>
<td class="text-truncate">OnePlus</td>
<td class="text-truncate p-1">
<ul class="list-unstyled users-list m-0">
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Christine Ramos"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-11.png" alt="Avatar">
</li>
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Thomas Brewer"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-10.png" alt="Avatar">
</li>
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Alice Chapman"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-9.png" alt="Avatar">
</li>
<li class="avatar avatar-sm">
<span class="badge badge-info">+3 more</span>
</li>
</ul>
</td>
<td class="text-truncate">$9000</td>
</tr>
<tr>
<td class="text-truncate">Galaxy</td>
<td class="text-truncate p-1">
<ul class="list-unstyled users-list m-0">
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Ryan Schneider"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-14.png" alt="Avatar">
</li>
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Tiffany Oliver"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-13.png" alt="Avatar">
</li>
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Joan Reid"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-12.png" alt="Avatar">
</li>
</ul>
</td>
<td class="text-truncate">$7500</td>
</tr>
<tr>
<td class="text-truncate">Moto Z2</td>
<td class="text-truncate p-1">
<ul class="list-unstyled users-list m-0">
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Kimberly Simmons"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-8.png" alt="Avatar">
</li>
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Willie Torres"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-7.png" alt="Avatar">
</li>
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Rebecca Jones"
class="avatar avatar-sm pull-up">
<img class="media-object rounded-circle"
src="../../../../assets/images/portrait/small/avatar-s-6.png" alt="Avatar">
</li>
<li class="avatar avatar-sm">
<span class="badge badge-info">+1 more</span>
</li>
</ul>
</td>
<td class="text-truncate">$8500</td>
</tr>
</tbody>
</table>
</div>
</div>
</ng-container>
</m-card>
</div>
</div>
<!--/ Products sell and New Orders -->
<!-- Recent Transactions -->
<div class="row match_height">
<div id="recent-transactions" class="col-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Recent Transactions</h4>
<div class="heading-elements invoice">
<ul class="list-inline mb-0">
<li><a [routerLink]="" class="btn btn-sm btn-danger box-shadow-2 round btn-min-width pull-right"
(click)="rotueInvoice()">Invoice Summary</a></li>
</ul>
</div>
</div>
<div class="card-content">
<div class="table-responsive" fxFlex="auto" [perfectScrollbar]="config">
<table class="table table-hover table-xl border_bottom">
<thead>
<tr>
<th scope="col" class="border-top-0">Status</th>
<th scope="col" class="border-top-0">Invoice#</th>
<th scope="col" class="border-top-0">Customer Name</th>
<th scope="col" class="border-top-0">Products</th>
<th scope="col" class="border-top-0">Categories</th>
<th scope="col" class="border-top-0">Shipping</th>
<th scope="col" class="border-top-0">Amount</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of rows">
<td class="text-truncate row_padding">
<i class="la la-dot-circle-o {{row.statusSymbol}} font-medium-1 mr-1"></i>
{{row.status}}
</td>
<td class="text-truncate row_padding">
<a [routerLink]="">{{ row.invoice }}</a>
</td>
<td class="text-truncate row_padding">
<span class="avatar avatar-xs"><img class="box-shadow-2 image-name-space"
[src]="row.image"></span><span>{{row.name}}</span>
</td>
<td class="text-truncate row_padding">
<span><img class="media-object avatar avatar-md avatar-online media-left pull-up square"
[src]="row.categories"></span>
</td>
<td class="text-truncate row_padding">
<span>
<button type="button"
class="btn btn-sm btn-outline-{{row.type}} round">{{row.buttonname}}</button>
</span>
</td>
<td class="text-truncate row_padding">
<ngb-progressbar height="7px" type="{{row.progressColor}}" [value]=row.value>
</ngb-progressbar>
</td>
<td class="text-truncate row_padding">{{ row.amount }} </td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!--/ Recent Transactions -->
<!--Recent Orders & Monthly Sales -->
<div class="row match_height">
<div class="col-xl-12 col-lg-12">
<div class="card">
<div class="card-content top_space">
<div id="cost-revenue" class="ecommercesaleslineArea position-relative">
<x-chartist *ngIf="ecommercesaleslineArea" [data]="ecommercesaleslineArea.data"
[type]="ecommercesaleslineArea.type" [options]="ecommercesaleslineArea.options"
[responsiveOptions]="ecommercesaleslineArea.responsiveOptions"
[events]="ecommercesaleslineArea.events">
</x-chartist>
</div>
</div>
<div class="card-footer border_top">
<div class="row mt-1">
<div class="col-3 text-center">
<h6 class="text-muted">Total Products</h6>
<h2 class="block font-weight-normal">18.6 k</h2>
<div class="TotalProducts">
<ngb-progressbar height="7px" type="gradient-x-info" [value]="70"></ngb-progressbar>
</div>
</div>
<div class="col-3 text-center">
<h6 class="text-muted">Total Sales</h6>
<h2 class="block font-weight-normal">64.5 M</h2>
<div class="TotalSales">
<ngb-progressbar height="7px" type="gradient-x-warning" [value]="60"></ngb-progressbar>
</div>
</div>
<div class="col-3 text-center">
<h6 class="text-muted">Total Cost</h6>
<h2 class="block font-weight-normal">24.3 B</h2>
<div class="TotalCost">
<ngb-progressbar height="7px" type="gradient-x-danger" [value]="40"></ngb-progressbar>
</div>
</div>
<div class="col-3 text-center">
<h6 class="text-muted">Total Revenue</h6>
<h2 class="block font-weight-normal">36.7 M</h2>
<div class="TotalRevenue">
<ngb-progressbar height="7px" type="gradient-x-success" [value]="90"></ngb-progressbar>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!--/Recent Orders & Monthly Sales -->
<div class="row" matchHeight="card">
<div class="col-xl-4 col-lg-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Basic Card</h4>
</div>
<div class="card-content">
<img class="img-fluid" src="../../../../assets/images/carousel/05.jpg" alt="Card image cap">
<div class="card-body">
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the
card's content.</p>
<a [routerLink]="" class="card-link">Card link</a>
<a [routerLink]="" class="card-link">Another link</a>
</div>
</div>
<div class="card-footer border-top-blue-grey border-top-lighten-5 text-muted">
<span class="float-left">3 hours ago</span>
<span class="float-right">
<a [routerLink]="" class="card-link">Read More <i class="fa fa-angle-right"></i></a>
</span>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Project Stats</h4>
</div>
<div class="card-content">
<p class="font-medium-2 text-muted text-center dountchartheader">Project Tasks</p>
<div id="donut-dashboard-chart" class="donut">
<x-chartist *ngIf="donutChart" class="pr_stats" [data]="donutChart.data" [type]="donutChart.type"
[options]="donutChart.options" [responsiveOptions]="donutChart.responsiveOptions"
[events]="donutChart.events">
</x-chartist>
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col Started">
<span class="mb-1 text-muted cardtext d-block">23% - Done</span>
<div>
<ngb-progressbar height="7px" type="success" [value]="23"></ngb-progressbar>
</div>
</div>
<div class="col Progress">
<span class="mb-1 text-muted cardtext d-block">14% - In Progress</span>
<div>
<ngb-progressbar height="7px" type="danger" [value]="14"></ngb-progressbar>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col Remaining">
<span class="mb-1 text-muted cardtext d-block">35% - Remaining</span>
<div>
<ngb-progressbar height="7px" type="warning" [value]="35"></ngb-progressbar>
</div>
</div>
<div class="col Done">
<span class="mb-1 text-muted cardtext d-block">28% - Started</span>
<div>
<ngb-progressbar height="7px" type="primary" [value]="28"></ngb-progressbar>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-12">
<div class="card">
<div class="card-content">
<div class="card-body sales-growth-chart">
<div id="monthly-sales" class=""></div>
<div class="barchart">
<x-chartist *ngIf="barChart" [data]="barChart.data" [type]="barChart.type"
[options]="barChart.options" [responsiveOptions]="barChart.responsiveOptions"
[events]="barChart.events">
</x-chartist>
</div>
</div>
<div class="card-footer">
<div class="chart-title mb-1 text-center">
<h6>Total monthly Sales.</h6>
</div>
<div class="chart-stats text-center">
<a [routerLink]="" class="btn btn-sm btn-danger box-shadow-2 mr-1">Statistics <i
class="feather ft-bar-chart" (click)=" reLoad()"></i></a> <span class="text-muted">for the last
year.</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!--/ Basic Horizontal Timeline -->
</div>
</div>
</div>
<!-- ////////////////////////////////////////////////////////////////////////////-->

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { EcommerceComponent } from './ecommerce.component';
describe('EcommerceComponent', () => {
let component: EcommerceComponent;
let fixture: ComponentFixture<EcommerceComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ EcommerceComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EcommerceComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,401 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import * as Chartist from 'chartist';
import { DatatableComponent } from '@swimlane/ngx-datatable';
import { ChartEvent, ChartType } from 'ng-chartist';
import 'chartist-plugin-tooltips';
import { BlockUI, NgBlockUI } from 'ng-block-ui';
import { PerfectScrollbarDirective, PerfectScrollbarComponent, PerfectScrollbarConfigInterface } from 'ngx-perfect-scrollbar';
import { ChartApiService } from '../../../_services/chart.api';
import { TableApiService } from '../../../_services/table-api.service';
import { Router } from '@angular/router';
export interface Chart {
type: ChartType;
data: Chartist.IChartistData;
options?: any;
responsiveOptions?: any;
events?: ChartEvent;
}
@Component({
selector: 'app-ecommerce',
templateUrl: './ecommerce.component.html',
styleUrls: ['./ecommerce.component.css']
})
export class EcommerceComponent implements OnInit {
@BlockUI('newOrders') blockUINewOrders: NgBlockUI;
public config: PerfectScrollbarConfigInterface = { wheelPropagation: true };
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective) directiveRef?: PerfectScrollbarDirective;
currentJustify = 'end';
loadingIndicator = true;
options = {
close: false,
expand: false,
minimize: false,
reload: true
};
ChartistData: any;
datatableData: any;
lineAreaDay: any;
lineAreaWeek: any;
lineAreaMonth: any;
ecommercesaleslineArea: any;
donutChart: any;
barChart: any;
rows: any;
@ViewChild(DatatableComponent, { static: true }) table: DatatableComponent;
Daygraph = true;
Weekgraph = false;
Monthgraph = false;
constructor(private chartApiservice: ChartApiService,
private tableApiservice: TableApiService,
private route: Router) { }
getTabledata() {
this.rows = this.datatableData.rows;
}
getlineArea() {
const ChartData = this.ChartistData;
this.lineAreaDay = {
type: 'Line',
data: ChartData['lineArea'],
options: {
lineSmooth: Chartist.Interpolation.simple({
divisor: 1.8
}),
fullwidth: true,
height: '320px',
low: 0,
showArea: true,
fullWidth: true,
showPoint: false,
axisX: {
showGrid: false,
},
axisY: {
low: 0,
offset: 16,
scaleMinSpace: 40,
labelInterpolationFnc: function (value) {
return value + 'K';
},
},
},
responsiveOptions: [
['screen and (max-width: 640px) and (min-width: 200px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}],
['screen and (max-width: 380px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}]
],
events: {
created(data: any): void {
const defs = data.svg.elem('defs');
defs.elem('linearGradient', {
id: 'gradient2',
x1: 1,
y1: 1,
x2: 1,
y2: 1
}).elem('stop', {
offset: 0,
'stop-color': 'rgba(22, 141, 238, 1)'
}).parent().elem('stop', {
offset: 1,
'stop-color': 'rgba(98, 188, 270, 11)'
});
},
},
};
this.lineAreaWeek = {
type: 'Line',
data: ChartData['lineAreaWeek'],
options: {
lineSmooth: Chartist.Interpolation.simple({
divisor: 2
}),
fullwidth: true,
height: '320px',
low: 0,
showArea: true,
fullWidth: true,
showPoint: false,
chartPadding: {
top: 33,
},
axisX: {
showGrid: false
},
axisY: {
low: 0,
scaleMinSpace: 40,
labelInterpolationFnc: function (value) {
return value + 'K';
},
offset: 20,
},
},
responsiveOptions: [
['screen and (max-width: 640px) and (min-width: 200px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}],
['screen and (max-width: 380px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}]
],
events: {
created(data: any): void {
const defs = data.svg.elem('defs');
defs.elem('linearGradient', {
id: 'gradient2',
x1: 0,
y1: 0,
x2: 1,
y2: 0
}).elem('stop', {
offset: 0,
'stop-color': 'rgba(22, 141, 238, 1)'
}).parent().elem('stop', {
offset: 1,
'stop-color': 'rgba(98, 188, 246, 1)'
});
},
},
};
this.lineAreaMonth = {
type: 'Line',
data: ChartData['lineAreaMonth'],
options: {
lineSmooth: Chartist.Interpolation.simple({
divisor: 2
}),
// low: 650,
fullwidth: true,
height: '320px',
low: 0,
chartPadding: {
top: 30,
left: 0,
right: 25
},
showArea: true,
fullWidth: true,
showPoint: false,
axisX: {
showGrid: false
},
axisY: {
low: 0,
scaleMinSpace: 60,
labelInterpolationFnc: function (value) {
return value + 'K';
},
}
},
responsiveOptions: [
['screen and (max-width: 640px) and (min-width: 200px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}],
['screen and (max-width: 380px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}]
],
events: {
created(data: any): void {
const defs = data.svg.elem('defs');
defs.elem('linearGradient', {
id: 'gradient2',
x1: 0,
y1: 0,
x2: 1,
y2: 0
}).elem('stop', {
offset: 0,
'stop-color': 'rgba(22, 141, 238, 1)'
}).parent().elem('stop', {
offset: 1,
'stop-color': 'rgba(98, 188, 246, 1)'
});
},
},
};
this.ecommercesaleslineArea = {
type: 'Line',
data: ChartData['lineArea2'],
options: {
height: '300px',
low: 0,
showArea: true,
fullWidth: true,
onlyInteger: true,
axisX: {
showGrid: false
},
axisY: {
low: 0,
scaleMinSpace: 40,
showGrid: false
},
},
responsiveOptions: [
['screen and (max-width: 640px) and (min-width: 381px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}],
['screen and (max-width: 380px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}]
],
events: {
draw(data: any): void {
const circleRadius = 6;
if (data.type === 'point') {
const circle = new Chartist.Svg('circle', {
cx: data.x,
cy: data.y,
r: circleRadius,
class: 'ct-point-circle'
});
data.element.replace(circle);
}
}
},
};
// Doughnut
this.donutChart = {
type: 'Pie',
data: ChartData.donutDashboard,
options: {
width: '100%',
height: '290px',
donut: true,
startAngle: 0,
low: 0,
high: 8,
fullWidth: true,
plugins: [
Chartist.plugins.tooltip({
appendToBody: false,
class: 'donut_tooltip',
})
],
labelInterpolationFnc: function (value) {
const total = ChartData.donutDashboard.series.reduce(function (prev, series) {
return prev + series.value;
}, 0);
return total + '%';
}
},
events: {
draw(data: any): void {
if (data.type === 'label') {
if (data.index === 0) {
data.element.attr({
dx: data.element.root().width() / 2,
dy: data.element.root().height() / 2
});
} else {
data.element.remove();
}
}
}
}
};
///////////////////// End doughnutchart////////////////
///////////////////// Start barchart////////////////
this.barChart = {
type: 'Bar',
data: ChartData['Bar'],
options: {
fullwidth: true,
height: '380px',
seriesBarDistance: 21,
chartPadding: {
top: 0,
},
plugins: [
Chartist.plugins.tooltip({
appendToBody: false,
class: 'bar_tooltip',
})
],
axisX: {
showLable: true,
showGrid: false,
offset: 60,
labelInterpolationFnc: function (value) {
return value.slice(0, 3);
}
},
axisY: {
scaleMinSpace: 40,
}
},
};
}
///////////////////// End barchart////////////////
ngOnInit() {
this.chartApiservice.getEcommerceData().subscribe(Response => {
this.ChartistData = Response;
this.getlineArea();
});
this.tableApiservice.getEcommerceTableData().subscribe(Response => {
this.datatableData = Response;
this.getTabledata();
});
}
reloadNewOrders() {
this.blockUINewOrders.start('Loading..');
setTimeout(() => {
this.blockUINewOrders.stop();
}, 2500);
}
rotueInvoice() {
this.route.navigate(['/invoice/invoice-summary']);
}
reLoad(){
this.route.navigate(['/sale'])
}
}

View File

@@ -0,0 +1,125 @@
///////////////////// Start Barchart ///////////////
export const barChartOptions: any = {
responsive: true,
scaleShowVerticalLines: false,
maintainAspectRatio: false,
legend: {
labels: {
padding: 30
}
},
scales: {
xAxes: [{
categoryPercentage: 0.36,
barPercentage: 0.68
}]
}
};
export const barChartLabels: string[] = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN'];
export const barChartType = 'bar';
export const barChartLegend = true;
export const barChartData: any[] = [
{ data: [70, 75, 90, 60, 80, 75, 65], label: 'Fulfilled',
backgroundColor: '#00a5a8',
borderColor: '#00a5a8',
pointBackgroundColor: '#00a5a8',
pointBorderColor: '#00a5a8',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#00a5a8',
barPercentage: 0.5,
categoryPercentage: 0.5 },
{ data: [60, 65, 80, 63, 90, 80, 70], label: 'Booked',
backgroundColor: '#ff4081',
borderColor: '#ff4081',
pointBackgroundColor: '#ff4081',
pointBorderColor: '#ff4081',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#ff4081',
barPercentage: 0.5,
categoryPercentage: 0.5 },
{ data: [42, 45, 65, 40, 42, 63, 35], label: 'Arrived',
backgroundColor: '#626e82',
borderColor: '#626e82',
pointBackgroundColor: '#626e82',
pointBorderColor: '#626e82',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#626e82',
barPercentage: 0.5,
categoryPercentage: 0.5 },
{ data: [50, 55, 70, 40, 47, 65, 38], label: 'No show',
backgroundColor: '#ff6e40',
borderColor: '#ff6e40',
pointBackgroundColor: '#ff6e40',
pointBorderColor: '#ff6e40',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#ff6e40',
barPercentage: 0.5,
categoryPercentage: 0.5 },
{ data: [40, 40, 45, 45, 45, 40, 45], label: 'reschedule',
backgroundColor: '#7c4dff',
borderColor: '#7c4dff',
pointBackgroundColor: '#7c4dff',
pointBorderColor: '#7c4dff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#7c4dff',
barPercentage: 0.5,
categoryPercentage: 0.5 },
{
type: 'line', // override the default type
data: [40, 60, 80, 60, 75, 60, 70],
label:'Appointment',
backgroundColor: 'rgba(0,255,255,0)',
borderColor: '#1e9ff2',
fill: false,
pointBorderColor: '#1e9ff2',
pointBackgroundColor: '#FFF',
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
pointRadius: 4,
lineTension: 0.4
}
];
export const barChartColors: Array<any> = [
{
backgroundColor: '#00a5a8',
borderColor: '#00a5a8',
pointBackgroundColor: '#00a5a8',
pointBorderColor: '#00a5a8',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#00a5a8',
},
{
backgroundColor: '#ff4081',
borderColor: '#ff4081',
pointBackgroundColor: '#ff4081',
pointBorderColor: '#ff4081',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#ff4081'
},
{
backgroundColor: '#626e82',
borderColor: '#626e82',
pointBackgroundColor: '#626e82',
pointBorderColor: '#626e82',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#626e82'
},
{
backgroundColor: '#ff6e40',
borderColor: '#ff6e40',
pointBackgroundColor: '#ff6e40',
pointBorderColor: '#ff6e40',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#ff6e40'
},
{
backgroundColor: '#7c4dff',
borderColor: '#7c4dff',
pointBackgroundColor: '#7c4dff',
pointBorderColor: '#7c4dff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: '#7c4dff'
},
];
///////////////////// End barchart////////////////

View File

@@ -0,0 +1,196 @@
<div class="app-content content">
<div class="content-overlay"></div>
<div class="content-wrapper">
<div class="content-header row">
</div>
<div class="content-body"><!-- Hospital Info cards -->
<div class="row">
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
<div class="card pull-up">
<div class="card-content">
<div class="card-body">
<div class="media d-flex">
<div class="align-self-center">
<i class="la la-user-md font-large-2 success"></i>
</div>
<div class="media-body text-right">
<h5 class="text-muted text-bold-500">Doctors Available</h5>
<h3 class="text-bold-600">122</h3>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
<div class="card pull-up">
<div class="card-content">
<div class="card-body">
<div class="media d-flex">
<div class="align-self-center">
<i class="la la-stethoscope font-large-2 warning"></i>
</div>
<div class="media-body text-right">
<h5 class="text-muted text-bold-500">Visiting Doctors</h5>
<h3 class="text-bold-600">34</h3>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
<div class="card pull-up">
<div class="card-content">
<div class="card-body">
<div class="media d-flex">
<div class="align-self-center">
<i class="la la-calendar-check-o font-large-2 info"></i>
</div>
<div class="media-body text-right">
<h5 class="text-muted text-bold-500">Today's Inquiry</h5>
<h3 class="text-bold-600">3.5K</h3>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
<div class="card pull-up">
<div class="card-content">
<div class="card-body">
<div class="media d-flex">
<div class="align-self-center">
<i class="la la-bed font-large-2 danger"></i>
</div>
<div class="media-body text-right">
<h5 class="text-muted text-bold-500">Rooms Available</h5>
<h3 class="text-bold-600">179</h3>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Hospital Info cards Ends -->
<!-- Appointment Bar Line Chart -->
<div class="row">
<div class="col-12">
<div class="card">
<section id="chartjs-bar-charts">
<div class="row">
<div class="col-12" *blockUI="'barCharts'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadBarCharts($event)">
<ng-container mCardHeaderTitle>
Appointment
</ng-container>
<ng-container mCardBody>
<div class="z">
<canvas class="barchart" height="328" baseChart [datasets]="barChartData" [labels]="barChartLabels"
[options]="barChartOptions" [legend]="barChartLegend"
[chartType]="barChartType"></canvas>
</div>
</ng-container>
</m-card>
</div>
</div>
</section>
</div>
</div>
</div>
<!-- Appointment Bar Line Chart Ends -->
<!-- Appointment Table -->
<div class="row" matchHeight="card">
<div class="col-12 col-md-4">
<div class="card">
<div class="card-header">
<h4 class="card-title">Doctors Available</h4>
</div>
<div class="card-content">
<div class="table-responsive">
<table id="recent-orders" class="table table-hover table-xl mb-0">
<tbody>
<tr *ngFor = "let doctor of doctors ">
<td class="text-truncate p-1 border-top-0">
<div class="avatar avatar-md">
<img class="media-object rounded-circle" [src]= doctor.image
alt="Avatar">
</div>
</td>
<td class="text-truncate pl-0 border-top-0">
<div class="name">{{doctor.name}}</div>
<div class="designation text-light font-small-2">Dentist</div>
</td>
<td class="text-right border-top-0">
<a href="hospital-book-appointment.html" class="btn btn-sm btn-outline-success">Book Appointment</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div id="recent-appointments" class="col-12 col-md-8">
<div class="card">
<div class="card-header">
<h4 class="card-title">Recent Appointments</h4>
<a class="heading-elements-toggle"><i class="la la-ellipsis-v font-medium-3"></i></a>
<div class="heading-elements">
<ul class="list-inline mb-0">
<li><a class="btn btn-sm btn-danger box-shadow-2 round btn-min-width pull-right" href="hospital-book-appointment.html"
target="_blank">View all</a></li>
</ul>
</div>
</div>
<div class="card-content mt-1">
<div class="table-responsive">
<table id="recent-orders-doctors" class="table table-hover table-xl mb-0">
<thead>
<tr>
<th class="border-top-0">Doctor</th>
<th class="border-top-0">Patients</th>
<th class="border-top-0">Specialities</th>
<th class="border-top-0">Timings</th>
<th class="border-top-0">Amount</th>
</tr>
</thead>
<tbody>
<tr class="pull-up" *ngFor="let doctor of doctorList">
<td class="text-truncate">{{doctor.name}}</td>
<td class="text-truncate p-1">
<ul class="list-unstyled users-list m-0">
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Kimberly Simmons" class="avatar avatar-sm pull-up" *ngFor="let imageUrl of doctor.image">
<img class="media-object rounded-circle" [src]="imageUrl" alt="Avatar">
</li>
<li class="avatar avatar-sm">
<span class="badge badge-info">{{doctor.bagde}}</span>
</li>
</ul>
</td>
<td>
<button type="button" class="btn btn-sm btn-outline-{{doctor.type}} round">{{doctor.designation}}</button>
</td>
<td class="text-truncate">{{doctor.time}}</td>
<td class="text-truncate">{{doctor.amount}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Appointment Table Ends -->
</div>
</div>
</div>
<!-- END: Content-->

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HospitalComponent } from './hospital.component';
describe('HospitalComponent', () => {
let component: HospitalComponent;
let fixture: ComponentFixture<HospitalComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ HospitalComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(HospitalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,66 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { PerfectScrollbarComponent, PerfectScrollbarDirective, PerfectScrollbarConfigInterface } from 'ngx-perfect-scrollbar';
import * as chartsData from './data';
@Component({
selector: 'app-hospital',
templateUrl: './hospital.component.html',
styleUrls: ['./hospital.component.css']
})
export class HospitalComponent {
public config: PerfectScrollbarConfigInterface = { suppressScrollY: true };
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective, { static: true }) directiveRef?: PerfectScrollbarDirective;
constructor() { }
doctors = [
{'name': 'Jane Andre','image':'../../../assets/images/portrait/small/avatar-s-4.png'},
{'name': 'Kail Reack','image':'../../../assets/images/portrait/small/avatar-s-5.png'},
{'name': 'Shail Black','image':'../../../assets/images/portrait/small/avatar-s-6.png'},
{'name': 'Zena wall','image':'../../../assets/images/portrait/small/avatar-s-7.png'},
{'name': 'Colin Welch','image':'../../../assets/images/portrait/small/avatar-s-8.png'}
]
firstRow = ['../../../assets/images/portrait/small/avatar-s-4.png',
'../../../assets/images/portrait/small/avatar-s-5.png',
'../../../assets/images/portrait/small/avatar-s-6.png'];
secondRow = ['../../../assets/images/portrait/small/avatar-s-7.png',
'../../../assets/images/portrait/small/avatar-s-8.png'];
thirdRow = ['../../../assets/images/portrait/small/avatar-s-1.png',
'../../../assets/images/portrait/small/avatar-s-2.png',
'../../../assets/images/portrait/small/avatar-s-3.png'];
fourthRow = ['../../../assets/images/portrait/small/avatar-s-11.png',
'../../../assets/images/portrait/small/avatar-s-12.png'];
fifthRow = ['../../../assets/images/portrait/small/avatar-s-6.png',
'../../../assets/images/portrait/small/avatar-s-4.png'];
doctorList = [
{
'type': 'danger', 'designation': 'Dentist', 'name': 'Jane Andre',
'image': this.firstRow, 'time': '8:00 A.M. - 12:00 P.M.', 'amount': '$ 1200.00', 'bagde': '+8 more'
},
{
'type': 'success', 'designation': 'Dermatologist', 'name': 'Kail Reack',
'image': this.secondRow, 'time': '10:00 A.M. - 1:00 P.M.', 'amount': '$ 1190.00', 'bagde': '+5 more'
},
{
'type': 'danger', 'designation': 'Psychiatrist', 'name': 'Shail Black',
'image': this.thirdRow, 'time': '11:00 A.M. - 2:00 P.M.', 'amount': '$ 999.00', 'bagde': '+3 more'
},
{
'type': 'success', 'designation': 'Gastroenterologist', 'name': 'Zena wall',
'image': this.fourthRow, 'time': '11:30 A.M. - 3:00 P.M.', 'amount': '$ 1150.00'
},
{
'type': 'danger', 'designation': 'Pediatrician', 'name': 'Colin Welch',
'image': this.fifthRow, 'time': '5:00 P.M. - 8:00 P.M.', 'amount': '$ 1180.00'
}
];
public barChartOptions = chartsData.barChartOptions;
public barChartLabels = chartsData.barChartLabels;
public barChartType = chartsData.barChartType;
public barChartLegend = chartsData.barChartLegend;
public barChartData = chartsData.barChartData;
public barChartColors = chartsData.barChartColors;
}

View File

@@ -0,0 +1,281 @@
:host ::ng-deep .chartist .ct-series-a .ct-line {
stroke: url(#gradient2);
stroke-linecap: round;
/* -webkit-filter: drop-shadow(0px 20px 11px rgba(0, 0, 0, 0.5)) !important; */
}
:host ::ng-deep .chartist {
filter: drop-shadow(0px 20px 11px rgba(252, 198, 198, 0.8)) !important;
}
:host ::ng-deep .chartist .ct-grid{
stroke-dasharray: 0px;
stroke: rgba(0, 0, 0, 0.4);
stroke-width: 0.6px;
}
:host ::ng-deep .chartist .ct-series-b .ct-line {
stroke: #c8c2c3;
stroke-dasharray: 8px 3px;
}
:host ::ng-deep .chartist .ct-label.ct-vertical.ct-start {
font-weight: 600;
color: #636161;
font-size: 12px;
}
:host ::ng-deep .earningchart .ct-series-a .ct-area {
fill: rgba(255,117,136,1);
}
:host ::ng-deep .earningchart .ct-series-a .ct-point-circle {
stroke-width: 3px;
stroke: #FF4961;
fill: #ffffff;
}
:host ::ng-deep .earningchart .ct-series-a .ct-line {
stroke: #FF4961;
stroke-width: 3px;
}
:host ::ng-deep .avatar-xs {
width: 32px !important;
border: 2px solid #FFF;
}
:host ::ng-deep .donut-chart2{
margin-bottom: -25px;
margin-top: -17px;
}
:host ::ng-deep .donut-chart2 .ct-series-a .ct-slice-donut {
stroke: #28d094;
stroke-width: 5.5px !important;
}
:host ::ng-deep .donut-chart2 .ct-series-b .ct-slice-donut {
stroke: #ff4961;
stroke-width: 5.5px !important;
}
:host ::ng-deep .donut-chart2 {
-webkit-filter: drop-shadow(0px 10px 11px rgba(187,187,187)) !important;
filter: drop-shadow(0px 10px 11px rgba(187,187,187));
}
:host ::ng-deep .donut-chart1 {
margin-bottom: -25px;
margin-top: -17px;
}
:host ::ng-deep .donut-chart1 .ct-series-a .ct-slice-donut {
stroke: #ff7889;
stroke-width: 5.5px !important;
}
:host ::ng-deep .donut-chart1 .ct-series-b .ct-slice-donut {
stroke: #ffffff;
stroke-width: 5.5px !important;
}
:host ::ng-deep .donut-chart1 .ct-label {
fill: #ffffff;
color: rgba(0, 0, 0, 0.4);
font-size: 1.75rem;
line-height: 1;
}
:host ::ng-deep .donut-chart2 .ct-label {
fill: #ff4b62;
color: rgba(0, 0, 0, 0.4);
font-size: 1.75rem;
line-height: 1;
}
:host ::ng-deep .position-relative {
position: relative !important;
margin-left: 0px;
}
:host ::ng-deep .pt-1,
.py-1 {
padding-top: 0rem !important;
}
:host ::ng-deep .chartist .ct-label.ct-horizontal.ct-end {
/* align-items: flex-start;
justify-content: flex-start;
text-align: left;
text-anchor: start; */
font-weight: 600;
color: #636161;
font-size: 12px;
font-family: sans-serif;
}
:host ::ng-deep .container > .ct-chart .ct-series.ct-series-c .ct-line {
stroke-width: 2px;
stroke-dasharray: 20px 180px;
stroke: #28d094;
animation: draw 0.3s linear infinite;
}
@keyframes draw {
from {
stroke-dashoffset: 200
}
to {
stroke-dashoffset: 0;
}
}
:host ::ng-deep .ct-series-c .ct-point,
.ct-series-c .ct-line,
.ct-series-c .ct-bar,
.ct-series-c .ct-slice-donut {
stroke: #28d094;
}
:host ::ng-deep .ct-chart .ct-series.ct-series-c .ct-line {
stroke: #28d094;
}
:host ::ng-deep .ct-series-b .ct-point,
.ct-series-b .ct-line,
.ct-series-b .ct-bar,
.ct-series-b .ct-slice-donut {
stroke: #ff4961;
}
:host ::ng-deep .container > .ct-chart .ct-series.ct-series-a .ct-line {
stroke-dasharray: 5px;
animation: dash 4s linear infinite;
}
@keyframes dash {
to {
stroke-dashoffset: 2000;
}
}
:host ::ng-deep .ct-chart .ct-point {
stroke-width: 10px;
stroke-linecap: round;
}
:host ::ng-deep .container > .ct-chart .ct-series.ct-series-b .ct-line {
stroke-width: 10px;
stroke-dasharray: 15px 5px;
animation: draw 4s linear infinite;
}
@keyframes draw {
from {
stroke-dashoffset: 100
}
to {
stroke-dashoffset: 0;
}
}
:host ::ng-deep .container {
max-width: 100% !important;
}
:host ::ng-deep .btn.gradient-blackberry.active,
.gradient-blackberry {
background-color: #f05b4f;
}
:host ::ng-deep .Visit {
background-color: #28d094;
}
:host ::ng-deep .Sales {
/* background-image: linear-gradient(45deg,#843cf7,#38b8f2)!important; */
background-color: #d70206;
}
:host ::ng-deep .col-md-11 {
padding-right: 0 !important;
}
:host ::ng-deep .col-md-1 {
padding-left: 0 !important;
}
:host ::ng-deep .box-shadow-0 .ct-label.ct-vertical.ct-start {
font-weight: bold;
color: #6e6e6e;
font-size: 12px;
}
:host ::ng-deep .box-shadow-0 .ct-label.ct-horizontal.ct-end {
font-weight: bold;
color: #6e6e6e;
font-size: 12px;
}
:host ::ng-deep .text-truncate {
padding: 0.9rem 2rem;
}
.mr-2 {
margin-left: 1rem !important;
margin-right: 0rem !important;
}
.mt-2 {
margin-top : 1.5rem !important;
}
.ml-2 {
margin-left : 2rem !important;
}
:host ::ng-deep .my-custom-cell {
padding-right: 6% !important;
padding-top: 1.5% !important;
}
:host ::ng-deep .border_bottom {
margin-bottom: 0rem !important;
}
:host ::ng-deep .border-top-0 {
padding: 1.25rem 2rem !important;
}
:host ::ng-deep .progress {
box-shadow: 0 10px 18px 0 rgba(62, 57, 107, .2);
margin-top: 1rem!important;
}
:host ::ng-deep .btn-danger {
color: #FFF !important;
}
:host ::ng-deep .users-list li + li {
margin-left: -10px !important;
}
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}
:host ::ng-deep .ps--active-x > .ps__rail-x {
display: none !important;
}
:host ::ng-deep .progress {
margin-bottom: 1rem !important;
}

View File

@@ -0,0 +1,269 @@
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1">
</div>
<div class="content-body">
<!-- Revenue, Hit Rate & Deals -->
<div class="row">
<div class="col-xl-6 col-12">
<div class="Revenue" *blockUI="'revenue'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadRevenue($event)">
<ng-container mCardHeaderTitle>
Revenue
</ng-container>
<ng-container mCardBody>
<div class="row mb-1">
<div class="col-6 col-md-4">
<h5>Current week</h5>
<h2 class="danger">$82,124</h2>
</div>
<div class="col-6 col-md-4">
<h5>Previous week</h5>
<h2 class="text-muted">$52,502</h2>
</div>
</div>
<div class="chartist">
<x-chartist *ngIf="lineArea" [data]="lineArea.data" [type]="lineArea.type" [options]="lineArea.options"
[responsiveOptions]="lineArea.responsiveOptions" [events]="lineArea.events">
</x-chartist>
</div>
</ng-container>
</m-card>
</div>
</div>
<div class="col-xl-6 col-12">
<div class="row">
<div class="col-md-6 col-12 ">
<div class="HitRate" *blockUI="'hitrate'; message: 'Loading'">
<m-card [options]="hitRateOptions" id="card" (reloadFunction)="reloadHitRate($event)">
<ng-container mCardHeaderTitle>
Hit Rate <span class="danger">-12%</span>
</ng-container>
<ng-container mCardBody>
<div id="donut-chart2" class="height-230 donut-chart2">
<x-chartist *ngIf="donutChart2" [data]="donutChart2.data" [type]="donutChart2.type" [options]="donutChart2.options"
[responsiveOptions]="donutChart2.responsiveOptions" [events]="donutChart2.events">
</x-chartist>
</div>
</ng-container>
</m-card>
</div>
</div>
<div class="col-md-6 col-12">
<m-card [options]="dealsOptions">
<ng-container mCardBody>
<h4 class="card-title white">Deals <span class="white">-55%</span>
<span class="float-right">
<span class="white">152</span><span class="red lighten-4">/200</span>
</span>
</h4>
<div id="donut-chart1" class="height-230 donut-chart1">
<x-chartist *ngIf="donutChart1" [data]="donutChart1.data" [type]="donutChart1.type" [options]="donutChart1.options"
[responsiveOptions]="donutChart1.responsiveOptions" [events]="donutChart1.events">
</x-chartist>
</div>
</ng-container>
</m-card>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-12">
<div class="card pull-up">
<div class="card-content">
<div class="card-body">
<div class="media d-flex">
<div class="media-body text-left">
<h6 class="text-muted">Order Value </h6>
<h3>$ 88,568</h3>
</div>
<div class="align-self-center">
<i class="icon-trophy success font-large-2 float-right"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6 col-12">
<div class="card pull-up">
<div class="card-content">
<div class="card-body">
<div class="media d-flex">
<div class="media-body text-left">
<h6 class="text-muted">Calls</h6>
<h3>3,568</h3>
</div>
<div class="align-self-center">
<i class="icon-call-in danger font-large-2 float-right"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!--/ Revenue, Hit Rate & Deals -->
<!-- Emails Products & Avg Deals -->
<div class="row">
<div class="col-12 col-md-3">
<div class="EmailRate" *blockUI="'email'; message: 'Updating'">
<m-card [options]="emailsOptions" (reloadFunction)="reloadEmail($event)">
<ng-container mCardHeaderTitle>
Emails
</ng-container>
<ng-container mCardBody>
<p>Open rate <span class="float-right text-bold-600">89%</span></p>
<ngb-progressbar height="7px" type="danger" [value]="89"></ngb-progressbar>
<p class="pt-1">Sent <span class="float-right"><span class="text-bold-600">310</span>/500</span>
</p>
<ngb-progressbar height="7px" type="success" [value]="50"></ngb-progressbar>
</ng-container>
</m-card>
</div>
</div>
<div class="col-12 col-md-3">
<div class="card">
<div class="card-header">
<h4 class="card-title">Top Products</h4>
<div class="heading-elements">
<ul class="list-inline mb-0">
<li><a class="info">Show all</a></li>
</ul>
</div>
</div>
<div class="card-content collapse show">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table mb-0">
<tbody>
<tr>
<th scope="row" class="border-top-0">iPone X</th>
<td class="border-top-0">2245</td>
</tr>
<tr>
<th scope="row">One Plus</th>
<td>1850</td>
</tr>
<tr>
<th scope="row">Samsung S7</th>
<td>1550</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-6">
<div class="card">
<div class="card-header">
<h4 class="card-title text-center">Average Deal Size</h4>
</div>
<div class="card-content collapse show">
<div class="card-body pt-0">
<div class="row">
<div class="col-md-6 col-12 border-right-blue-grey border-right-lighten-5 text-center">
<h6 class="danger text-bold-600">-30%</h6>
<h4 class="font-large-2 text-bold-400">$12,536</h4>
<p class="blue-grey lighten-2 mb-0">Per rep</p>
</div>
<div class="col-md-6 col-12 text-center">
<h6 class="success text-bold-600">12%</h6>
<h4 class="font-large-2 text-bold-400">$18,548</h4>
<p class="blue-grey lighten-2 mb-0">Per team</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!--/ Emails Products & Avg Deals -->
<!-- Total earning & Recent Sales -->
<div class="row">
<div class="col-12 col-md-4">
<div class="card">
<div class="card-content">
<div class="earning-chart position-relative">
<div class="chart-title position-absolute mt-2 ml-2">
<h1 class="display-4">$1,596</h1>
<span class="text-muted">Total Earning</span>
</div>
<div id="cost-revenue" class="earningchart position-relative">
<x-chartist *ngIf="earningchart" [data]="earningchart.data" [type]="earningchart.type" [options]="earningchart.options"
[responsiveOptions]="earningchart.responsiveOptions" [events]="earningchart.events">
</x-chartist>
</div>
<div class="chart-stats position-absolute position-bottom-0 position-right-0 mb-2 mr-3">
<a [routerLink]="" class="btn round btn-danger mr-1 btn-glow">Statistics <i class="feather ft-bar-chart"></i></a>
<span class="text-muted">for the <a [routerLink]="" class="danger darken-2">last year.</a></span>
</div>
</div>
</div>
</div>
</div>
<div id="recent-sales" class="col-12 col-md-8">
<div class="card">
<div class="card-header">
<h4 class="card-title">Recent Sales</h4>
<div class="heading-elements">
<ul class="list-inline mb-0">
<li><a [routerLink]="" class="btn btn-sm btn-danger box-shadow-2 round btn-min-width pull-right" (click)="rotueInvoice()">View
all</a></li>
</ul>
</div>
</div>
<div class="card-content mt-1">
<div class="table-responsive" fxFlex="auto" [perfectScrollbar]="config">
<table class="table border_bottom table-hover">
<thead>
<tr>
<th scope="col" class="border-top-0">Product</th>
<th scope="col" class="border-top-0">Customers</th>
<th scope="col" class="border-top-0">Categories</th>
<th scope="col" class="border-top-0">Popularity</th>
<th scope="col" class="border-top-0">Amount</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of rows">
<td class="text-truncate">
{{row.product}}
</td>
<td class="text-truncate p-1">
<ul class="list-unstyled users-list m-0">
<li class="avatar avatar-sm pull-up" *ngFor="let imageUrl of row.image">
<img class="media-object rounded-circle" [src]="imageUrl" alt="Avatar">
</li>
</ul>
</td>
<td class="text-truncate">
<span>
<button type="button"
class="btn btn-sm btn-outline-{{row.type}} round">{{row.buttonname}}</button>
</span>
</td>
<td class="text-truncate">
<ngb-progressbar height="7px" type="{{row.type}}" [value]=row.value>
</ngb-progressbar>
</td>
<td class="text-truncate">{{ row.amount }} </td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!--/ Total earning & Recent Sales -->
</div>
</div>
</div>
<!-- ////////////////////////////////////////////////////////////////////////////-->

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SalesComponent } from './sales.component';
describe('SalesComponent', () => {
let component: SalesComponent;
let fixture: ComponentFixture<SalesComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ SalesComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SalesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,332 @@
import { Component, OnInit, ViewChild, Renderer2 } from '@angular/core';
import * as Chartist from 'chartist';
import { DatatableComponent } from '@swimlane/ngx-datatable';
import { ChartEvent, ChartType } from 'ng-chartist';
import { BlockUI, NgBlockUI } from 'ng-block-ui';
import { PerfectScrollbarComponent, PerfectScrollbarDirective, PerfectScrollbarConfigInterface } from 'ngx-perfect-scrollbar';
import { ChartApiService } from '../../../_services/chart.api';
import { Router } from '@angular/router';
export interface Chart {
type: ChartType;
data: Chartist.IChartistData;
options?: any;
responsiveOptions?: any;
events?: ChartEvent;
}
@Component({
selector: 'app-sales',
templateUrl: './sales.component.html',
styleUrls: ['./sales.component.css']
})
export class SalesComponent implements OnInit {
@BlockUI('revenue') blockUIRevenue: NgBlockUI;
@BlockUI('hitrate') blockUIHitRate: NgBlockUI;
@BlockUI('email') blockUIEmail: NgBlockUI;
public config: PerfectScrollbarConfigInterface = { suppressScrollY: true };
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective, { static: true }) directiveRef?: PerfectScrollbarDirective;
salesData: any;
lineArea: any;
earningchart: any;
donutChart2: any;
donutChart1: any;
options = {
bodyClass: ['pt-0'],
close: false,
expand: false,
minimize: false,
reload: true
};
hitRateOptions = {
bodyClass: ['bg-hexagons', 'pt-0'],
headerClass: ['bg-hexagons'],
cardClass: ['pull-up'],
close: false,
expand: false,
minimize: false,
reload: true
};
dealsOptions = {
bodyClass: ['bg-hexagons-danger'],
cardClass: ['pull-up'],
contentClass: ['bg-gradient-directional-danger']
};
emailsOptions = {
bodyClass: ['pt-0'],
close: false,
expand: false,
minimize: false,
reload: true
};
loadingIndicator = true;
firstRow = ['../../../assets/images/portrait/small/avatar-s-4.png',
'../../../assets/images/portrait/small/avatar-s-5.png',
'../../../assets/images/portrait/small/avatar-s-6.png'];
secondRow = ['../../../assets/images/portrait/small/avatar-s-7.png',
'../../../assets/images/portrait/small/avatar-s-8.png'];
thirdRow = ['../../../assets/images/portrait/small/avatar-s-1.png',
'../../../assets/images/portrait/small/avatar-s-2.png',
'../../../assets/images/portrait/small/avatar-s-3.png'];
fourthRow = ['../../../assets/images/portrait/small/avatar-s-11.png',
'../../../assets/images/portrait/small/avatar-s-12.png'];
fifthRow = ['../../../assets/images/portrait/small/avatar-s-6.png',
'../../../assets/images/portrait/small/avatar-s-4.png'];
rows = [
{
'type': 'danger', 'value': 85, 'product': 'iPhone X',
'image': this.firstRow, 'buttonname': 'Mobile', 'amount': '$ 1200.00', 'bagde': '+8 more'
},
{
'type': 'success', 'value': 75, 'product': 'iPad',
'image': this.secondRow, 'buttonname': 'Teblet', 'amount': '$ 1190.00', 'bagde': '+5 more'
},
{
'type': 'danger', 'value': 65, 'product': 'OnePlus',
'image': this.thirdRow, 'buttonname': 'Mobile', 'amount': '$ 999.00', 'bagde': '+3 more'
},
{
'type': 'success', 'value': 55, 'product': 'ZenPad',
'image': this.fourthRow, 'buttonname': 'Teblet', 'amount': '$ 1150.00'
},
{
'type': 'danger', 'value': 45, 'product': 'Pixel 2',
'image': this.fifthRow, 'buttonname': 'Mobile', 'amount': '$ 1180.00'
}
];
@ViewChild(DatatableComponent, { static: true }) table: DatatableComponent;
Daygraph = true;
Weekgraph = false;
Monthgraph = false;
ngOnInit() {
this.chartApiservice.getSalesData().subscribe(Response => {
this.salesData = Response;
this.getChartdata();
});
}
constructor(private _renderer: Renderer2, private route: Router,
private chartApiservice: ChartApiService) { }
reloadRevenue() {
this.blockUIRevenue.start('Loading..');
setTimeout(() => {
this.blockUIRevenue.stop();
}, 2500);
}
reloadHitRate() {
this.blockUIHitRate.start('Please Wait..');
setTimeout(() => {
this.blockUIHitRate.stop();
}, 2500);
}
reloadEmail() {
this.blockUIEmail.start();
setTimeout(() => {
this.blockUIEmail.stop();
}, 2500);
}
rotueInvoice() {
this.route.navigate(['/invoice/invoice-summary']);
}
getChartdata() {
const Chartdata = this.salesData;
this.lineArea = {
type: 'Line',
data: Chartdata['lineArea'],
options: {
lineSmooth: Chartist.Interpolation.simple({
divisor: 2.8
}),
fullWidth: true,
height: '270px',
showArea: false,
showPoint: false,
axisX: {
showGrid: false,
showLabel: true,
offset: 32
},
axisY: {
showGrid: true,
showLabel: true,
scaleMinSpace: 28,
offset: 44
},
},
events: {
created(data: any): void {
const defs = data.svg.elem('defs');
defs.elem('linearGradient', {
id: 'gradient2',
x1: 0,
y1: 0,
x2: 1,
y2: 0
}).elem('stop', {
offset: 0,
'stop-color': 'rgb(255,73,97)'
}).parent().elem('stop', {
offset: 1,
'stop-color': 'rgb(255,73,97)'
});
},
draw(data: any): void {
const circleRadius = 4;
if (data.type === 'point') {
const circle = new Chartist.Svg('circle', {
cx: data.x,
cy: data.y,
r: circleRadius,
class: 'ct-point-circle'
});
data.element.replace(circle);
} else if (data.type === 'label') {
// adjust label position for rotation
const dX = data.width / 2 + (26 - data.width);
data.element.attr({ x: data.element.attr('x') - dX });
}
}
},
};
this.earningchart = {
type: 'Line',
data: Chartdata['earningchart'],
options: {
chartPadding: 0,
height: '440px',
low: 0,
showArea: true,
fullWidth: true,
onlyInteger: true,
axisX: {
showGrid: false,
showLabel: false,
offset: -1
},
axisY: {
scaleMinSpace: 40,
showGrid: false,
showLabel: false,
offset: -2
},
},
responsiveOptions: [
['screen and (max-width: 640px) and (min-width: 381px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 2 === 0 ? value : null;
}
}
}],
['screen and (max-width: 380px)', {
axisX: {
labelInterpolationFnc: function (value, index) {
return index % 3 === 0 ? value : null;
}
}
}]
],
events: {
created(data: any): void {
const defs = data.svg.elem('defs');
defs.elem('linearGradient', {
id: 'gradient1',
x1: 0,
y1: 0,
x2: 1,
y2: 0
}).elem('stop', {
offset: 0,
'stop-color': 'rgb(255,73,97)'
}).parent().elem('stop', {
offset: 1,
'stop-color': 'rgb(255,73,97)'
});
},
draw(data: any): void {
const circleRadius = 6;
if (data.type === 'point') {
const circle = new Chartist.Svg('circle', {
cx: data.x,
cy: data.y,
r: circleRadius,
class: 'ct-point-circle'
});
data.element.replace(circle);
}
}
},
};
// Doughnut
this.donutChart2 = {
type: 'Pie',
data: Chartdata['donut1'],
options: {
chartPadding: 0,
fullwidth: true,
height: '273px',
donut: true,
showLabel: true,
startAngle: 0,
labelInterpolationFnc: function (value) {
const total = 82;
return total + '%';
}
},
events: {
draw(data: any): void {
if (data.type === 'label') {
if (data.index === 0) {
data.element.attr({
dx: data.element.root().width() / 2,
dy: data.element.root().height() / 2
});
} else {
data.element.remove();
}
}
}
}
};
this.donutChart1 = {
type: 'Pie',
data: Chartdata['donut2'],
options: {
chartPadding: 0,
fullwidth: true,
height: '273px',
donut: true,
showLabel: true,
labelInterpolationFnc: function (value) {
const total = 76;
return total + '%';
}
},
events: {
draw(data: any): void {
if (data.type === 'label') {
if (data.index === 0) {
data.element.attr({
dx: data.element.root().width() / 2,
dy: data.element.root().height() / 2
});
} else {
data.element.remove();
}
}
}
}
};
}
}

Some files were not shown because too many files have changed in this diff Show More