mirror of
				https://github.com/richard-loafle/fuse-angular.git
				synced 2025-10-31 12:23:33 +00:00 
			
		
		
		
	Filter pipe added,
spacing class helpers added(margin, padding), Normalize css added, Icon size class helpers added, slideInLeft, slideInRight animation added, Chat app almost completed.
This commit is contained in:
		
							parent
							
								
									b9569a5ba8
								
							
						
					
					
						commit
						56e6b854c2
					
				| @ -20,6 +20,7 @@ import { PerfectScrollbarConfigInterface, PerfectScrollbarModule } from 'ngx-per | |||||||
| import { HttpModule } from '@angular/http'; | import { HttpModule } from '@angular/http'; | ||||||
| import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; | import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; | ||||||
| import { FuseFakeDbService } from './fuse-fake-db/fuse-fake-db.service'; | import { FuseFakeDbService } from './fuse-fake-db/fuse-fake-db.service'; | ||||||
|  | import { INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS } from '@angular/platform-browser-dynamic/src/platform_providers'; | ||||||
| 
 | 
 | ||||||
| const PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = { | const PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = { | ||||||
|     suppressScrollX: true |     suppressScrollX: true | ||||||
| @ -30,6 +31,10 @@ const appRoutes: Routes = [ | |||||||
|         path        : 'apps/mail', |         path        : 'apps/mail', | ||||||
|         loadChildren: './main/apps/mail/mail.module#MailModule' |         loadChildren: './main/apps/mail/mail.module#MailModule' | ||||||
|     }, |     }, | ||||||
|  |     { | ||||||
|  |         path        : 'apps/chat', | ||||||
|  |         loadChildren: './main/apps/chat/chat.module#ChatModule' | ||||||
|  |     }, | ||||||
|     { |     { | ||||||
|         path      : '**', |         path      : '**', | ||||||
|         redirectTo: 'apps/dashboards/project' |         redirectTo: 'apps/dashboards/project' | ||||||
|  | |||||||
| @ -8,4 +8,16 @@ export class Animations | |||||||
|         transition('1 => 0', animate('300ms ease-out')), |         transition('1 => 0', animate('300ms ease-out')), | ||||||
|         transition('0 => 1', animate('300ms ease-in')) |         transition('0 => 1', animate('300ms ease-in')) | ||||||
|     ]); |     ]); | ||||||
|  |     public static slideInLeft = trigger('slideInLeft', [ | ||||||
|  |         state('void', style({transform: 'translateX(-100%)', display: 'none'})), | ||||||
|  |         state('*', style({transform: 'translateX(0)', display: 'flex'})), | ||||||
|  |         transition('void => *', animate('300ms')), | ||||||
|  |         transition('* => void', animate('300ms')) | ||||||
|  |     ]); | ||||||
|  |     public static slideInRight = trigger('slideInRight', [ | ||||||
|  |         state('void', style({transform: 'translateX(100%)', display: 'none'})), | ||||||
|  |         state('*', style({transform: 'translateX(0)', display: 'flex'})), | ||||||
|  |         transition('void => *', animate('300ms')), | ||||||
|  |         transition('* => void', animate('300ms')) | ||||||
|  |     ]); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { NgModule } from '@angular/core'; | import { NgModule } from '@angular/core'; | ||||||
| import { FormsModule } from '@angular/forms'; | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; | ||||||
| import { CommonModule } from '@angular/common'; | import { CommonModule } from '@angular/common'; | ||||||
| 
 | 
 | ||||||
| import { MaterialModule } from './material.module'; | import { MaterialModule } from './material.module'; | ||||||
| @ -23,7 +23,8 @@ import { FusePipesModule } from '../pipes/pipes.module'; | |||||||
|         CommonModule, |         CommonModule, | ||||||
|         FormsModule, |         FormsModule, | ||||||
|         FusePipesModule, |         FusePipesModule, | ||||||
|         PerfectScrollbarModule |         PerfectScrollbarModule, | ||||||
|  |         ReactiveFormsModule | ||||||
|     ], |     ], | ||||||
|     exports     : [ |     exports     : [ | ||||||
|         FlexLayoutModule, |         FlexLayoutModule, | ||||||
| @ -33,7 +34,8 @@ import { FusePipesModule } from '../pipes/pipes.module'; | |||||||
|         FuseMdSidenavHelperDirective, |         FuseMdSidenavHelperDirective, | ||||||
|         FuseMdSidenavTogglerDirective, |         FuseMdSidenavTogglerDirective, | ||||||
|         FusePipesModule, |         FusePipesModule, | ||||||
|         PerfectScrollbarModule |         PerfectScrollbarModule, | ||||||
|  |         ReactiveFormsModule | ||||||
|     ] |     ] | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										152
									
								
								src/app/core/pipes/filter.pipe.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								src/app/core/pipes/filter.pipe.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,152 @@ | |||||||
|  | /** | ||||||
|  |  * Created by vadimdez on 28/06/16. | ||||||
|  |  */ | ||||||
|  | import { Pipe, Injectable } from '@angular/core'; | ||||||
|  | 
 | ||||||
|  | @Pipe({ | ||||||
|  |     name: 'filterBy', | ||||||
|  |     pure: false | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | @Injectable() | ||||||
|  | export class FilterPipe { | ||||||
|  | 
 | ||||||
|  |     private filterByString(filter) { | ||||||
|  |         if (filter) { | ||||||
|  |             filter = filter.toLowerCase(); | ||||||
|  |         } | ||||||
|  |         return value => { | ||||||
|  |             return !filter || (value ? ('' + value).toLowerCase().indexOf(filter) !== -1 : false); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private filterByBoolean(filter) { | ||||||
|  |         return value => { | ||||||
|  |             return Boolean(value) === filter; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private filterByObject(filter) { | ||||||
|  |         return value => { | ||||||
|  |             for (let key in filter) { | ||||||
|  | 
 | ||||||
|  |                 if (key === '$or') { | ||||||
|  |                     if (!this.filterByOr(filter.$or)(this.getValue(value))) { | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (!value.hasOwnProperty(key) && !Object.getOwnPropertyDescriptor(Object.getPrototypeOf(value), key)) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let val = this.getValue(value[key]); | ||||||
|  |                 const filterType = typeof filter[key]; | ||||||
|  |                 let isMatching; | ||||||
|  | 
 | ||||||
|  |                 if (filterType === 'boolean') { | ||||||
|  |                     isMatching = this.filterByBoolean(filter[key])(val); | ||||||
|  |                 } else if (filterType === 'string') { | ||||||
|  |                     isMatching = this.filterByString(filter[key])(val); | ||||||
|  |                 } else if (filterType === 'object') { | ||||||
|  |                     isMatching = this.filterByObject(filter[key])(val); | ||||||
|  |                 } else { | ||||||
|  |                     isMatching = this.filterDefault(filter[key])(val); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (!isMatching) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Filter value by $or | ||||||
|  |      * | ||||||
|  |      * @param filter | ||||||
|  |      * @returns {(value:any)=>boolean} | ||||||
|  |      */ | ||||||
|  |     private filterByOr(filter: any[]) { | ||||||
|  |         return (value: any) => { | ||||||
|  |             let hasMatch = false; | ||||||
|  |             const length = filter.length; | ||||||
|  |             const isArray = value instanceof Array; | ||||||
|  | 
 | ||||||
|  |             const arrayComparison = (i) => { | ||||||
|  |                 return value.indexOf(filter[i]) !== -1; | ||||||
|  |             }; | ||||||
|  |             const otherComparison = (i) => { | ||||||
|  |                 return value === filter[i]; | ||||||
|  |             }; | ||||||
|  |             const comparison = isArray ? arrayComparison : otherComparison; | ||||||
|  | 
 | ||||||
|  |             for (let i = 0; i < length; i++) { | ||||||
|  |                 if (comparison(i)) { | ||||||
|  |                     hasMatch = true; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return hasMatch; | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Checks function's value if type is function otherwise same value | ||||||
|  |      * @param value | ||||||
|  |      * @returns {any} | ||||||
|  |      */ | ||||||
|  |     private getValue(value: any) { | ||||||
|  |         return typeof value === 'function' ? value() : value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Defatul filterDefault function | ||||||
|  |      * | ||||||
|  |      * @param filter | ||||||
|  |      * @returns {(value:any)=>boolean} | ||||||
|  |      */ | ||||||
|  |     private filterDefault(filter) { | ||||||
|  |         return value => { | ||||||
|  |             return filter === undefined || filter == value; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private isNumber(value) { | ||||||
|  |         return !isNaN(parseInt(value, 10)) && isFinite(value); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     transform(array: any[], filter: any): any { | ||||||
|  |         const type = typeof filter; | ||||||
|  | 
 | ||||||
|  |         if (!array) { | ||||||
|  |             return array; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (type === 'boolean') { | ||||||
|  |             return array.filter(this.filterByBoolean(filter)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (type === 'string') { | ||||||
|  |             if (this.isNumber(filter)) { | ||||||
|  |                 return array.filter(this.filterDefault(filter)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return array.filter(this.filterByString(filter)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (type === 'object') { | ||||||
|  |             return array.filter(this.filterByObject(filter)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (type === 'function') { | ||||||
|  |             return array.filter(filter); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return array.filter(this.filterDefault(filter)); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -4,20 +4,24 @@ import { KeysPipe } from './keys.pipe'; | |||||||
| import { GetByIdPipe } from './getById.pipe'; | import { GetByIdPipe } from './getById.pipe'; | ||||||
| import { HtmlToPlaintextPipe } from './htmlToPlaintext.pipe'; | import { HtmlToPlaintextPipe } from './htmlToPlaintext.pipe'; | ||||||
| import { SearchPipe } from './search.pipe'; | import { SearchPipe } from './search.pipe'; | ||||||
|  | import { FilterPipe } from './filter.pipe'; | ||||||
| 
 | 
 | ||||||
| @NgModule({ | @NgModule({ | ||||||
|     declarations: [ |     declarations: [ | ||||||
|         KeysPipe, |         KeysPipe, | ||||||
|         GetByIdPipe, |         GetByIdPipe, | ||||||
|         HtmlToPlaintextPipe, |         HtmlToPlaintextPipe, | ||||||
|         SearchPipe |         SearchPipe, | ||||||
|  |         FilterPipe | ||||||
|  | 
 | ||||||
|     ], |     ], | ||||||
|     imports     : [], |     imports     : [], | ||||||
|     exports     : [ |     exports     : [ | ||||||
|         KeysPipe, |         KeysPipe, | ||||||
|         GetByIdPipe, |         GetByIdPipe, | ||||||
|         HtmlToPlaintextPipe, |         HtmlToPlaintextPipe, | ||||||
|         SearchPipe |         SearchPipe, | ||||||
|  |         FilterPipe | ||||||
|     ] |     ] | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -20,12 +20,16 @@ | |||||||
| @include angular-material-typography($custom-typography); | @include angular-material-typography($custom-typography); | ||||||
| 
 | 
 | ||||||
| // Partials | // Partials | ||||||
|  | @import "partials/normalize"; | ||||||
|  | @import "partials/spacing"; | ||||||
| @import "partials/global"; | @import "partials/global"; | ||||||
| @import "partials/_material"; | @import "partials/icons"; | ||||||
|  | @import "partials/material"; | ||||||
| @import "partials/angular-material-fix"; | @import "partials/angular-material-fix"; | ||||||
| @import "partials/typography"; | @import "partials/typography"; | ||||||
| @import "partials/page-layouts"; | @import "partials/page-layouts"; | ||||||
| @import "partials/navigation"; | @import "partials/navigation"; | ||||||
|  | @import "partials/forms"; | ||||||
| 
 | 
 | ||||||
| // Plugins | // Plugins | ||||||
| @import "partials/plugins/plugins"; | @import "partials/plugins/plugins"; | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								src/app/core/scss/partials/_forms.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/app/core/scss/partials/_forms.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | button, | ||||||
|  | input[type=email], | ||||||
|  | input[type=tel], | ||||||
|  | input[type=text], | ||||||
|  | input[type=password], | ||||||
|  | input[type=image], | ||||||
|  | input[type=submit], | ||||||
|  | input[type=button], | ||||||
|  | input[type=search], | ||||||
|  | textarea { | ||||||
|  |     appearance: none; | ||||||
|  |     -moz-appearance: none; | ||||||
|  |     -webkit-appearance: none; | ||||||
|  |     outline: none; | ||||||
|  | } | ||||||
| @ -2,6 +2,10 @@ | |||||||
|     box-sizing: border-box; |     box-sizing: border-box; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | html { | ||||||
|  |     | ||||||
|  | } | ||||||
|  | 
 | ||||||
| html, body { | html, body { | ||||||
|     margin: 0; |     margin: 0; | ||||||
|     width: 100%; |     width: 100%; | ||||||
|  | |||||||
							
								
								
									
										22
									
								
								src/app/core/scss/partials/_icons.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/app/core/scss/partials/_icons.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | i, | ||||||
|  | md-icon { | ||||||
|  |     color: rgba(0, 0, 0, 0.54); | ||||||
|  |     font-size: 24px; | ||||||
|  |     width: 24px; | ||||||
|  |     height: 24px; | ||||||
|  |     min-width: 24px; | ||||||
|  |     min-height: 24px; | ||||||
|  |     line-height: 24px; | ||||||
|  | 
 | ||||||
|  |     @for $size from 2 through 128 { | ||||||
|  | 
 | ||||||
|  |         &.s-#{$size * 2} { | ||||||
|  |             font-size: #{($size * 2) + 'px'} !important; | ||||||
|  |             width: #{($size * 2) + 'px'} !important; | ||||||
|  |             height: #{($size * 2) + 'px'} !important; | ||||||
|  |             min-width: #{($size * 2) + 'px'} !important; | ||||||
|  |             min-height: #{($size * 2) + 'px'} !important; | ||||||
|  |             line-height: #{($size * 2) + 'px'} !important; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -39,6 +39,54 @@ | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .avatar-wrapper { | ||||||
|  |     position: relative; | ||||||
|  | 
 | ||||||
|  |     .avatar { | ||||||
|  |         margin-top: 0; | ||||||
|  |         margin-bottom: 0; | ||||||
|  |     } | ||||||
|  |     md-icon.status { | ||||||
|  |         position: absolute; | ||||||
|  |         top: 28px; | ||||||
|  |         left: 28px; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | md-icon.status { | ||||||
|  |     border-radius: 50%; | ||||||
|  | 
 | ||||||
|  |     &.online { | ||||||
|  |         color: #4CAF50; | ||||||
|  |         &:before { | ||||||
|  |             content: "check_circle"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     &.do-not-disturb { | ||||||
|  |         color: #F44336; | ||||||
|  |         &:before { | ||||||
|  |             content: "do_not_disturb_on"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     &.away { | ||||||
|  |         background-color: #FFC107; | ||||||
|  |         color: #FFFFFF; | ||||||
|  |         &:before { | ||||||
|  |             content: "access_time"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     &.offline { | ||||||
|  |         color: #646464; | ||||||
|  |         background-color: #FFFFFF; | ||||||
|  |         &:before { | ||||||
|  |             content: "not_interested"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*----------------------------------------------------------------*/ | /*----------------------------------------------------------------*/ | ||||||
| /*  Forms | /*  Forms | ||||||
| /*----------------------------------------------------------------*/ | /*----------------------------------------------------------------*/ | ||||||
|  | |||||||
							
								
								
									
										447
									
								
								src/app/core/scss/partials/_normalize.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										447
									
								
								src/app/core/scss/partials/_normalize.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,447 @@ | |||||||
|  | /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ | ||||||
|  | 
 | ||||||
|  | /* Document | ||||||
|  |    ========================================================================== */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Correct the line height in all browsers. | ||||||
|  |  * 2. Prevent adjustments of font size after orientation changes in | ||||||
|  |  *    IE on Windows Phone and in iOS. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | html { | ||||||
|  |     line-height: 1.15; /* 1 */ | ||||||
|  |     -ms-text-size-adjust: 100%; /* 2 */ | ||||||
|  |     -webkit-text-size-adjust: 100%; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Sections | ||||||
|  |    ========================================================================== */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Remove the margin in all browsers (opinionated). | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | body { | ||||||
|  |     margin: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct display in IE 9-. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | article, | ||||||
|  | aside, | ||||||
|  | footer, | ||||||
|  | header, | ||||||
|  | nav, | ||||||
|  | section { | ||||||
|  |     display: block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Correct the font size and margin on `h1` elements within `section` and | ||||||
|  |  * `article` contexts in Chrome, Firefox, and Safari. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | h1 { | ||||||
|  |     font-size: 2em; | ||||||
|  |     margin: 0.67em 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Grouping content | ||||||
|  |    ========================================================================== */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct display in IE 9-. | ||||||
|  |  * 1. Add the correct display in IE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | figcaption, | ||||||
|  | figure, | ||||||
|  | main { /* 1 */ | ||||||
|  |     display: block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct margin in IE 8. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | figure { | ||||||
|  |     margin: 1em 40px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Add the correct box sizing in Firefox. | ||||||
|  |  * 2. Show the overflow in Edge and IE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | hr { | ||||||
|  |     box-sizing: content-box; /* 1 */ | ||||||
|  |     height: 0; /* 1 */ | ||||||
|  |     overflow: visible; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Correct the inheritance and scaling of font size in all browsers. | ||||||
|  |  * 2. Correct the odd `em` font sizing in all browsers. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | pre { | ||||||
|  |     font-family: monospace, monospace; /* 1 */ | ||||||
|  |     font-size: 1em; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Text-level semantics | ||||||
|  |    ========================================================================== */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Remove the gray background on active links in IE 10. | ||||||
|  |  * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | a { | ||||||
|  |     background-color: transparent; /* 1 */ | ||||||
|  |     -webkit-text-decoration-skip: objects; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Remove the bottom border in Chrome 57- and Firefox 39-. | ||||||
|  |  * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | abbr[title] { | ||||||
|  |     border-bottom: none; /* 1 */ | ||||||
|  |     text-decoration: underline; /* 2 */ | ||||||
|  |     text-decoration: underline dotted; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Prevent the duplicate application of `bolder` by the next rule in Safari 6. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | b, | ||||||
|  | strong { | ||||||
|  |     font-weight: inherit; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct font weight in Chrome, Edge, and Safari. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | b, | ||||||
|  | strong { | ||||||
|  |     font-weight: bolder; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Correct the inheritance and scaling of font size in all browsers. | ||||||
|  |  * 2. Correct the odd `em` font sizing in all browsers. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | code, | ||||||
|  | kbd, | ||||||
|  | samp { | ||||||
|  |     font-family: monospace, monospace; /* 1 */ | ||||||
|  |     font-size: 1em; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct font style in Android 4.3-. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | dfn { | ||||||
|  |     font-style: italic; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct background and color in IE 9-. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | mark { | ||||||
|  |     background-color: #ff0; | ||||||
|  |     color: #000; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct font size in all browsers. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | small { | ||||||
|  |     font-size: 80%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Prevent `sub` and `sup` elements from affecting the line height in | ||||||
|  |  * all browsers. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | sub, | ||||||
|  | sup { | ||||||
|  |     font-size: 75%; | ||||||
|  |     line-height: 0; | ||||||
|  |     position: relative; | ||||||
|  |     vertical-align: baseline; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub { | ||||||
|  |     bottom: -0.25em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sup { | ||||||
|  |     top: -0.5em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Embedded content | ||||||
|  |    ========================================================================== */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct display in IE 9-. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | audio, | ||||||
|  | video { | ||||||
|  |     display: inline-block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct display in iOS 4-7. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | audio:not([controls]) { | ||||||
|  |     display: none; | ||||||
|  |     height: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Remove the border on images inside links in IE 10-. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | img { | ||||||
|  |     border-style: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Hide the overflow in IE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | svg:not(:root) { | ||||||
|  |     overflow: hidden; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Forms | ||||||
|  |    ========================================================================== */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Change the font styles in all browsers (opinionated). | ||||||
|  |  * 2. Remove the margin in Firefox and Safari. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | button, | ||||||
|  | input, | ||||||
|  | optgroup, | ||||||
|  | select, | ||||||
|  | textarea { | ||||||
|  |     font-family: sans-serif; /* 1 */ | ||||||
|  |     font-size: 100%; /* 1 */ | ||||||
|  |     line-height: 1.15; /* 1 */ | ||||||
|  |     margin: 0; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Show the overflow in IE. | ||||||
|  |  * 1. Show the overflow in Edge. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | button, | ||||||
|  | input { /* 1 */ | ||||||
|  |     overflow: visible; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Remove the inheritance of text transform in Edge, Firefox, and IE. | ||||||
|  |  * 1. Remove the inheritance of text transform in Firefox. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | button, | ||||||
|  | select { /* 1 */ | ||||||
|  |     text-transform: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` | ||||||
|  |  *    controls in Android 4. | ||||||
|  |  * 2. Correct the inability to style clickable types in iOS and Safari. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | button, | ||||||
|  | html [type="button"], /* 1 */ | ||||||
|  | [type="reset"], | ||||||
|  | [type="submit"] { | ||||||
|  |     -webkit-appearance: button; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Remove the inner border and padding in Firefox. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | button::-moz-focus-inner, | ||||||
|  | [type="button"]::-moz-focus-inner, | ||||||
|  | [type="reset"]::-moz-focus-inner, | ||||||
|  | [type="submit"]::-moz-focus-inner { | ||||||
|  |     border-style: none; | ||||||
|  |     padding: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Restore the focus styles unset by the previous rule. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | button:-moz-focusring, | ||||||
|  | [type="button"]:-moz-focusring, | ||||||
|  | [type="reset"]:-moz-focusring, | ||||||
|  | [type="submit"]:-moz-focusring { | ||||||
|  |     outline: 1px dotted ButtonText; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Correct the padding in Firefox. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | fieldset { | ||||||
|  |     padding: 0.35em 0.75em 0.625em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Correct the text wrapping in Edge and IE. | ||||||
|  |  * 2. Correct the color inheritance from `fieldset` elements in IE. | ||||||
|  |  * 3. Remove the padding so developers are not caught out when they zero out | ||||||
|  |  *    `fieldset` elements in all browsers. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | legend { | ||||||
|  |     box-sizing: border-box; /* 1 */ | ||||||
|  |     color: inherit; /* 2 */ | ||||||
|  |     display: table; /* 1 */ | ||||||
|  |     max-width: 100%; /* 1 */ | ||||||
|  |     padding: 0; /* 3 */ | ||||||
|  |     white-space: normal; /* 1 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Add the correct display in IE 9-. | ||||||
|  |  * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | progress { | ||||||
|  |     display: inline-block; /* 1 */ | ||||||
|  |     vertical-align: baseline; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Remove the default vertical scrollbar in IE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | textarea { | ||||||
|  |     overflow: auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Add the correct box sizing in IE 10-. | ||||||
|  |  * 2. Remove the padding in IE 10-. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | [type="checkbox"], | ||||||
|  | [type="radio"] { | ||||||
|  |     box-sizing: border-box; /* 1 */ | ||||||
|  |     padding: 0; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Correct the cursor style of increment and decrement buttons in Chrome. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | [type="number"]::-webkit-inner-spin-button, | ||||||
|  | [type="number"]::-webkit-outer-spin-button { | ||||||
|  |     height: auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Correct the odd appearance in Chrome and Safari. | ||||||
|  |  * 2. Correct the outline style in Safari. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | [type="search"] { | ||||||
|  |     -webkit-appearance: textfield; /* 1 */ | ||||||
|  |     outline-offset: -2px; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | [type="search"]::-webkit-search-cancel-button, | ||||||
|  | [type="search"]::-webkit-search-decoration { | ||||||
|  |     -webkit-appearance: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 1. Correct the inability to style clickable types in iOS and Safari. | ||||||
|  |  * 2. Change font properties to `inherit` in Safari. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | ::-webkit-file-upload-button { | ||||||
|  |     -webkit-appearance: button; /* 1 */ | ||||||
|  |     font: inherit; /* 2 */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Interactive | ||||||
|  |    ========================================================================== */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * Add the correct display in IE 9-. | ||||||
|  |  * 1. Add the correct display in Edge, IE, and Firefox. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | details, /* 1 */ | ||||||
|  | menu { | ||||||
|  |     display: block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * Add the correct display in all browsers. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | summary { | ||||||
|  |     display: list-item; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Scripting | ||||||
|  |    ========================================================================== */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct display in IE 9-. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | canvas { | ||||||
|  |     display: inline-block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct display in IE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | template { | ||||||
|  |     display: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Hidden | ||||||
|  |    ========================================================================== */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add the correct display in IE 10-. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | [hidden] { | ||||||
|  |     display: none; | ||||||
|  | } | ||||||
							
								
								
									
										62
									
								
								src/app/core/scss/partials/_spacing.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/app/core/scss/partials/_spacing.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | |||||||
|  | // Margin and Padding | ||||||
|  | @each $prop, $abbrev in (margin: m, padding: p) { | ||||||
|  | 
 | ||||||
|  |     @for $index from 0 through 64 { | ||||||
|  |         $size: $index *4; | ||||||
|  |         $length: #{$size}px; | ||||||
|  |         .#{$abbrev}-#{$size} { | ||||||
|  |             #{$prop}: $length !important; | ||||||
|  |         } | ||||||
|  |         .#{$abbrev}t-#{$size} { | ||||||
|  |             #{$prop}-top: $length !important; | ||||||
|  |         } | ||||||
|  |         .#{$abbrev}r-#{$size} { | ||||||
|  |             #{$prop}-right: $length !important; | ||||||
|  |         } | ||||||
|  |         .#{$abbrev}b-#{$size} { | ||||||
|  |             #{$prop}-bottom: $length !important; | ||||||
|  |         } | ||||||
|  |         .#{$abbrev}l-#{$size} { | ||||||
|  |             #{$prop}-left: $length !important; | ||||||
|  |         } | ||||||
|  |         .#{$abbrev}x-#{$size} { | ||||||
|  |             #{$prop}-right: $length !important; | ||||||
|  |             #{$prop}-left: $length !important; | ||||||
|  |         } | ||||||
|  |         .#{$abbrev}y-#{$size} { | ||||||
|  |             #{$prop}-top: $length !important; | ||||||
|  |             #{$prop}-bottom: $length !important; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Some special margin utils | ||||||
|  | .m-auto { | ||||||
|  |     margin: auto !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .mt-auto { | ||||||
|  |     margin-top: auto !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .mr-auto { | ||||||
|  |     margin-right: auto !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .mb-auto { | ||||||
|  |     margin-bottom: auto !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ml-auto { | ||||||
|  |     margin-left: auto !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .mx-auto { | ||||||
|  |     margin-right: auto !important; | ||||||
|  |     margin-left: auto !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .my-auto { | ||||||
|  |     margin-top: auto !important; | ||||||
|  |     margin-bottom: auto !important; | ||||||
|  | } | ||||||
							
								
								
									
										325
									
								
								src/app/fuse-fake-db/chat.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										325
									
								
								src/app/fuse-fake-db/chat.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,325 @@ | |||||||
|  | export class ChatFakeDb | ||||||
|  | { | ||||||
|  |     public static contacts = [ | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680b3249760ea21de52', | ||||||
|  |             'name'  : 'Alice Freeman', | ||||||
|  |             'avatar': 'assets/images/avatars/alice.jpg', | ||||||
|  |             'status': 'online', | ||||||
|  |             'mood'  : 'I never sign anything until I pretend to read it first..' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680606588342058356d', | ||||||
|  |             'name'  : 'Arnold', | ||||||
|  |             'avatar': 'assets/images/avatars/Arnold.jpg', | ||||||
|  |             'status': 'do-not-disturb', | ||||||
|  |             'mood'  : 'Looks like Andrew Jackson\'s been tossed to the back of the bus.' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a68009e20d0a9e9acf2a', | ||||||
|  |             'name'  : 'Barrera', | ||||||
|  |             'avatar': 'assets/images/avatars/Barrera.jpg', | ||||||
|  |             'status': 'do-not-disturb', | ||||||
|  |             'mood'  : 'Love is going to bed early.Marriage is going to sleep early.', | ||||||
|  |             'unread': null | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a6809fdd915739187ed5', | ||||||
|  |             'name'  : 'Blair', | ||||||
|  |             'avatar': 'assets/images/avatars/Blair.jpg', | ||||||
|  |             'status': 'offline', | ||||||
|  |             'mood'  : 'I would be unstoppable. If i could just get started.', | ||||||
|  |             'unread': 3 | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a68007920cf75051da64', | ||||||
|  |             'name'  : 'Boyle', | ||||||
|  |             'avatar': 'assets/images/avatars/Boyle.jpg', | ||||||
|  |             'status': 'offline', | ||||||
|  |             'mood'  : '\'GOOD MORNING COFFEE\'....Meet your maker!!!!' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a68031fdbb1db2c1af47', | ||||||
|  |             'name'  : 'Christy', | ||||||
|  |             'avatar': 'assets/images/avatars/Christy.jpg', | ||||||
|  |             'status': 'offline', | ||||||
|  |             'mood'  : 'We always hold hands. If I let go, she shops.', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680bc670af746c435e2', | ||||||
|  |             'name'  : 'Copeland', | ||||||
|  |             'avatar': 'assets/images/avatars/Copeland.jpg', | ||||||
|  |             'status': 'online', | ||||||
|  |             'mood'  : 'I get enough exercise just pushing my luck.', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680e7eb988a58ddf303', | ||||||
|  |             'name'  : 'Estes', | ||||||
|  |             'avatar': 'assets/images/avatars/Estes.jpg', | ||||||
|  |             'status': 'away', | ||||||
|  |             'mood'  : 'What comes after the man bun hairstyle? The he-hive!', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680dcb077889f758961', | ||||||
|  |             'name'  : 'Harper', | ||||||
|  |             'avatar': 'assets/images/avatars/Harper.jpg', | ||||||
|  |             'status': 'offline', | ||||||
|  |             'mood'  : 'Always try to be modest and be proud of it!', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a6806acf030f9341e925', | ||||||
|  |             'name'  : 'Helen', | ||||||
|  |             'avatar': 'assets/images/avatars/Helen.jpg', | ||||||
|  |             'status': 'away', | ||||||
|  |             'mood'  : 'Why are there stitch marks on zombies? Who\'s giving them medical attention?', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680ae1ae9a3c960d487', | ||||||
|  |             'name'  : 'Henderson', | ||||||
|  |             'avatar': 'assets/images/avatars/Henderson.jpg', | ||||||
|  |             'status': 'offline', | ||||||
|  |             'mood'  : 'I can\'t decide if people who wear pajamas in public have given up on life or are living it to the fullest.', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680b8d240c011dd224b', | ||||||
|  |             'name'  : 'Josefina', | ||||||
|  |             'avatar': 'assets/images/avatars/Josefina.jpg', | ||||||
|  |             'status': 'online', | ||||||
|  |             'mood'  : 'The fastest way to being happy is to make other people happy. You go first', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a68034cb3968e1f79eac', | ||||||
|  |             'name'  : 'Katina', | ||||||
|  |             'avatar': 'assets/images/avatars/Katina.jpg', | ||||||
|  |             'status': 'away', | ||||||
|  |             'mood'  : 'If I was a rat,,, I wouldn\'t give anyone my ass.', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a6801146cce777df2a08', | ||||||
|  |             'name'  : 'Lily', | ||||||
|  |             'avatar': 'assets/images/avatars/Lily.jpg', | ||||||
|  |             'status': 'do-not-disturb', | ||||||
|  |             'mood'  : 'A zip line but from the sofa to the fridge', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a6808a178bfd034d6ecf', | ||||||
|  |             'name'  : 'Mai', | ||||||
|  |             'avatar': 'assets/images/avatars/Mai.jpg', | ||||||
|  |             'status': 'away', | ||||||
|  |             'mood'  : 'If a girl tells you she has a nipple ring, the only correct response is \'I don\'t believe you.\'', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680653c265f5c79b5a9', | ||||||
|  |             'name'  : 'Nancy', | ||||||
|  |             'avatar': 'assets/images/avatars/Nancy.jpg', | ||||||
|  |             'status': 'do-not-disturb', | ||||||
|  |             'mood'  : 'Prison counts as a gated community, right?', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680bbcec3cc32a8488a', | ||||||
|  |             'name'  : 'Nora', | ||||||
|  |             'avatar': 'assets/images/avatars/Nora.jpg', | ||||||
|  |             'status': 'do-not-disturb', | ||||||
|  |             'mood'  : 'I never date left handed women. Righty tighty, lefty loosey.', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a6803d87f1b77e17b62b', | ||||||
|  |             'name'  : 'Odessa', | ||||||
|  |             'avatar': 'assets/images/avatars/Odessa.jpg', | ||||||
|  |             'status': 'away', | ||||||
|  |             'mood'  : 'A day without sunshine is like, night.', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680e87cb319bd9bd673', | ||||||
|  |             'name'  : 'Reyna', | ||||||
|  |             'avatar': 'assets/images/avatars/Reyna.jpg', | ||||||
|  |             'status': 'offline', | ||||||
|  |             'mood'  : 'I can\'t wait for summer in Canada...', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a6802d10e277a0f35775', | ||||||
|  |             'name'  : 'Shauna', | ||||||
|  |             'avatar': 'assets/images/avatars/Shauna.jpg', | ||||||
|  |             'status': 'online', | ||||||
|  |             'mood'  : 'My take home pay doesn’t ven take me home.', | ||||||
|  |             'unread': null, | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680aef1e5cf26dd3d1f', | ||||||
|  |             'name'  : 'Shepard', | ||||||
|  |             'avatar': 'assets/images/avatars/Shepard.jpg', | ||||||
|  |             'status': 'online', | ||||||
|  |             'mood'  : 'I don\'t speak Spanish, but I\'m pretty sure \'Dora\' means \'annoying\'', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680cd7efa56a45aea5d', | ||||||
|  |             'name'  : 'Tillman', | ||||||
|  |             'avatar': 'assets/images/avatars/Tillman.jpg', | ||||||
|  |             'status': 'do-not-disturb', | ||||||
|  |             'mood'  : '', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a680fb65c91a82cb35e2', | ||||||
|  |             'name'  : 'Trevino', | ||||||
|  |             'avatar': 'assets/images/avatars/Trevino.jpg', | ||||||
|  |             'status': 'away', | ||||||
|  |             'mood'  : 'Apparently, a rat and a plastic tube does not count as a DIY abortion kit.', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a68018c663044be49cbf', | ||||||
|  |             'name'  : 'Tyson', | ||||||
|  |             'avatar': 'assets/images/avatars/Tyson.jpg', | ||||||
|  |             'status': 'do-not-disturb', | ||||||
|  |             'mood'  : 'I\'m wondering why life keeps teaching me lessons I have no desire to learn...', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '5725a6809413bf8a0a5272b1', | ||||||
|  |             'name'  : 'Velazquez', | ||||||
|  |             'avatar': 'assets/images/avatars/Velazquez.jpg', | ||||||
|  |             'status': 'online', | ||||||
|  |             'mood'  : 'Modulation in all things.', | ||||||
|  |         } | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     public static chats = [ | ||||||
|  |         { | ||||||
|  |             'id'    : '1725a680b3249760ea21de52', | ||||||
|  |             'dialog': [ | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a680b3249760ea21de52', | ||||||
|  |                     'message': 'Quickly come to the meeting room 1B, we have a big server issue', | ||||||
|  |                     'time'   : '2017-03-22T08:54:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a6802d10e277a0f35724', | ||||||
|  |                     'message': 'I’m having breakfast right now, can’t you wait for 10 minutes?', | ||||||
|  |                     'time'   : '2017-03-22T08:55:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a680b3249760ea21de52', | ||||||
|  |                     'message': 'We are losing money! Quick!', | ||||||
|  |                     'time'   : '2017-03-22T09:00:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a6802d10e277a0f35724', | ||||||
|  |                     'message': 'It’s not my money, you know. I will eat my breakfast and then I will come to the meeting room.', | ||||||
|  |                     'time'   : '2017-03-22T09:02:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a680b3249760ea21de52', | ||||||
|  |                     'message': 'You are the worst!', | ||||||
|  |                     'time'   : '2017-03-22T09:05:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a680b3249760ea21de52', | ||||||
|  |                     'message': 'We are losing money! Quick!', | ||||||
|  |                     'time'   : '2017-03-22T09:15:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a6802d10e277a0f35724', | ||||||
|  |                     'message': 'It’s not my money, you know. I will eat my breakfast and then I will come to the meeting room.', | ||||||
|  |                     'time'   : '2017-03-22T09:20:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a680b3249760ea21de52', | ||||||
|  |                     'message': 'You are the worst!', | ||||||
|  |                     'time'   : '2017-03-22T09:22:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a680b3249760ea21de52', | ||||||
|  |                     'message': 'We are losing money! Quick!', | ||||||
|  |                     'time'   : '2017-03-22T09:25:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a6802d10e277a0f35724', | ||||||
|  |                     'message': 'It’s not my money, you know. I will eat my breakfast and then I will come to the meeting room.', | ||||||
|  |                     'time'   : '2017-03-22T09:27:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a680b3249760ea21de52', | ||||||
|  |                     'message': 'You are the worst!', | ||||||
|  |                     'time'   : '2017-03-22T09:33:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a680b3249760ea21de52', | ||||||
|  |                     'message': 'We are losing money! Quick!', | ||||||
|  |                     'time'   : '2017-03-22T09:35:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a6802d10e277a0f35724', | ||||||
|  |                     'message': 'It’s not my money, you know. I will eat my breakfast and then I will come to the meeting room.', | ||||||
|  |                     'time'   : '2017-03-22T09:45:28.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a680b3249760ea21de52', | ||||||
|  |                     'message': 'You are the worst!', | ||||||
|  |                     'time'   : '2017-03-22T10:00:28.299Z' | ||||||
|  |                 } | ||||||
|  |             ] | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '2725a680b8d240c011dd2243', | ||||||
|  |             'dialog': [ | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a680b8d240c011dd224b', | ||||||
|  |                     'message': 'Quickly come to the meeting room 1B, we have a big server issue', | ||||||
|  |                     'time'   : '2017-04-22T01:00:00.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a6802d10e277a0f35724', | ||||||
|  |                     'message': 'I’m having breakfast right now, can’t you wait for 10 minutes?', | ||||||
|  |                     'time'   : '2017-04-22T01:05:00.299Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a680b8d240c011dd224b', | ||||||
|  |                     'message': 'We are losing money! Quick!', | ||||||
|  |                     'time'   : '2017-04-22T01:10:00.299Z' | ||||||
|  |                 } | ||||||
|  |             ] | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'id'    : '3725a6809413bf8a0a5272b4', | ||||||
|  |             'dialog': [ | ||||||
|  |                 { | ||||||
|  |                     'who'    : '5725a6809413bf8a0a5272b1', | ||||||
|  |                     'message': 'Quickly come to the meeting room 1B, we have a big server issue', | ||||||
|  |                     'time'   : '2017-04-22T02:10:00.299Z' | ||||||
|  |                 } | ||||||
|  |             ] | ||||||
|  |         } | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     public static user = [ | ||||||
|  |         { | ||||||
|  |             'id'      : '5725a6802d10e277a0f35724', | ||||||
|  |             'name'    : 'John Doe', | ||||||
|  |             'avatar'  : 'assets/images/avatars/profile.jpg', | ||||||
|  |             'status'  : 'online', | ||||||
|  |             'mood'    : 'it\'s a status....not your diary...', | ||||||
|  |             'chatList': [ | ||||||
|  |                 { | ||||||
|  |                     'id'             : '1725a680b3249760ea21de52', | ||||||
|  |                     'contactId'      : '5725a680b3249760ea21de52', | ||||||
|  |                     'name'           : 'Alice Freeman', | ||||||
|  |                     'unread'         : 4, | ||||||
|  |                     'lastMessageTime': '2017-06-12T02:10:18.931Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'id'             : '2725a680b8d240c011dd2243', | ||||||
|  |                     'contactId'      : '5725a680b8d240c011dd224b', | ||||||
|  |                     'name'           : 'Josefina', | ||||||
|  |                     'unread'         : null, | ||||||
|  |                     'lastMessageTime': '2017-02-18T10:30:18.931Z' | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     'id'             : '3725a6809413bf8a0a5272b4', | ||||||
|  |                     'contactId'      : '5725a6809413bf8a0a5272b1', | ||||||
|  |                     'name'           : 'Velazquez', | ||||||
|  |                     'unread'         : 2, | ||||||
|  |                     'lastMessageTime': '2017-03-18T12:30:18.931Z' | ||||||
|  |                 } | ||||||
|  |             ] | ||||||
|  |         } | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -1,5 +1,6 @@ | |||||||
| import {InMemoryDbService} from 'angular-in-memory-web-api'; | import {InMemoryDbService} from 'angular-in-memory-web-api'; | ||||||
| import {MailFakeDb} from './mail'; | import {MailFakeDb} from './mail'; | ||||||
|  | import {ChatFakeDb} from './chat'; | ||||||
| 
 | 
 | ||||||
| export class FuseFakeDbService implements InMemoryDbService | export class FuseFakeDbService implements InMemoryDbService | ||||||
| { | { | ||||||
| @ -8,7 +9,10 @@ export class FuseFakeDbService implements InMemoryDbService | |||||||
|         return { |         return { | ||||||
|             'mail-mails'   : MailFakeDb.mails, |             'mail-mails'   : MailFakeDb.mails, | ||||||
|             'mail-folders' : MailFakeDb.folders, |             'mail-folders' : MailFakeDb.folders, | ||||||
|             'mail-labels' : MailFakeDb.labels |             'mail-labels'  : MailFakeDb.labels, | ||||||
|  |             'chat-contacts': ChatFakeDb.contacts, | ||||||
|  |             'chat-chats'   : ChatFakeDb.chats, | ||||||
|  |             'chat-user'    : ChatFakeDb.user, | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								src/app/main/apps/chat/chat-start/chat-start.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/app/main/apps/chat/chat-start/chat-start.component.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | <div fxFlex fxLayout="column" fxLayoutAlign="center center"> | ||||||
|  | 
 | ||||||
|  |     <div class="big-circle mat-elevation-z1" fxLayout="column" fxLayoutAlign="center center"> | ||||||
|  | 
 | ||||||
|  |         <md-icon class="s-128">chat</md-icon> | ||||||
|  | 
 | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <span class="app-title my-24">Chat App</span> | ||||||
|  | 
 | ||||||
|  |     <span fxHide fxShow.gt-md class="app-message">Select contact to start the chat!..</span> | ||||||
|  | 
 | ||||||
|  |     <button md-raised-button fxHide.gt-md class="" fuseMdSidenavToggler="chat-left-sidenav"> | ||||||
|  |         Select contact to start the chat!.. | ||||||
|  |     </button> | ||||||
|  | 
 | ||||||
|  | </div> | ||||||
							
								
								
									
										30
									
								
								src/app/main/apps/chat/chat-start/chat-start.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/app/main/apps/chat/chat-start/chat-start.component.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | @import "src/app/core/scss/fuse"; | ||||||
|  | 
 | ||||||
|  | :host { | ||||||
|  |     display: flex; | ||||||
|  |     flex: 1; | ||||||
|  |     height: 100%; | ||||||
|  |     background: linear-gradient(to bottom, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.6) 20%, rgba(255, 255, 255, 0.8)); | ||||||
|  | 
 | ||||||
|  |     .big-circle { | ||||||
|  |         background: linear-gradient(to bottom, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.6) 20%, rgba(255, 255, 255, 0.8)); | ||||||
|  |         border-radius: 50%; | ||||||
|  |         width: 300px; | ||||||
|  |         height: 300px; | ||||||
|  |         line-height: 300px; | ||||||
|  |         text-align: center; | ||||||
|  | 
 | ||||||
|  |         md-icon{ | ||||||
|  |             color: mat-color($accent); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .app-title { | ||||||
|  |         font-weight: 500; | ||||||
|  |         font-size: 32px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .secondary-text { | ||||||
|  |         font-size: 16px; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								src/app/main/apps/chat/chat-start/chat-start.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/app/main/apps/chat/chat-start/chat-start.component.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | import {Component, OnInit} from '@angular/core'; | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |     selector   : 'fuse-chat-start', | ||||||
|  |     templateUrl: './chat-start.component.html', | ||||||
|  |     styleUrls  : ['./chat-start.component.scss'] | ||||||
|  | }) | ||||||
|  | export class ChatStartComponent implements OnInit | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  |     constructor() | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ngOnInit() | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										115
									
								
								src/app/main/apps/chat/chat-view/chat-view.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								src/app/main/apps/chat/chat-view/chat-view.component.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,115 @@ | |||||||
|  | <!-- CHAT --> | ||||||
|  | <div class="chat" fxFlex fxLayout="column"> | ||||||
|  | 
 | ||||||
|  |     <!-- CHAT TOOLBAR --> | ||||||
|  |     <md-toolbar class="chat-toolbar"> | ||||||
|  | 
 | ||||||
|  |         <div fxFlex fxLayout="row" fxLayoutAlign="space-between center"> | ||||||
|  | 
 | ||||||
|  |             <div fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  | 
 | ||||||
|  |                 <!-- RESPONSIVE CHATS BUTTON--> | ||||||
|  |                 <div md-button fxHide.gt-md class="responsive-chats-button mat-icon-button mr-16" | ||||||
|  |                      fuseMdSidenavToggler="chat-left-sidenav" | ||||||
|  |                      aria-label="chats button"> | ||||||
|  |                     <md-icon class="s-36">chat</md-icon> | ||||||
|  |                 </div> | ||||||
|  |                 <!-- / RESPONSIVE CHATS BUTTON--> | ||||||
|  | 
 | ||||||
|  |                 <!-- CHAT CONTACT--> | ||||||
|  |                 <div class="chat-contact" fxLayout="row" fxLayoutAlign="start center" | ||||||
|  |                      fuseMdSidenavToggler="chat-right-sidenav" (click)="selectContact()"> | ||||||
|  | 
 | ||||||
|  |                     <div class="avatar-wrapper"> | ||||||
|  | 
 | ||||||
|  |                         <img [src]="contact.avatar" | ||||||
|  |                              class="avatar" | ||||||
|  |                              alt="{{contact.name}}"/> | ||||||
|  | 
 | ||||||
|  |                         <md-icon class="s-16 status" | ||||||
|  |                                  [ngClass]="contact.status"> | ||||||
|  |                         </md-icon> | ||||||
|  |                     </div> | ||||||
|  | 
 | ||||||
|  |                     <div class="chat-contact-name"> | ||||||
|  |                         {{contact.name}} | ||||||
|  |                     </div> | ||||||
|  | 
 | ||||||
|  |                 </div> | ||||||
|  |                 <!-- / CHAT CONTACT--> | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |             <div> | ||||||
|  |                 <button md-button class="mat-icon-button" [mdMenuTriggerFor]="contactMenu" | ||||||
|  |                         aria-label="more"> | ||||||
|  |                     <md-icon>more_vert</md-icon> | ||||||
|  |                 </button> | ||||||
|  | 
 | ||||||
|  |                 <md-menu #contactMenu="mdMenu"> | ||||||
|  |                     <button md-menu-item fuseMdSidenavToggler="chat-right-sidenav" (click)="selectContact()"> | ||||||
|  |                         Contact Info | ||||||
|  |                     </button> | ||||||
|  |                 </md-menu> | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |         </div> | ||||||
|  |     </md-toolbar> | ||||||
|  |     <!-- / CHAT TOOLBAR --> | ||||||
|  | 
 | ||||||
|  |     <!-- CHAT CONTENT --> | ||||||
|  |     <div id="chat-content" fxFlex perfect-scrollbar> | ||||||
|  | 
 | ||||||
|  |         <!-- CHAT MESSAGES --> | ||||||
|  |         <div class="chat-messages"> | ||||||
|  | 
 | ||||||
|  |             <!-- MESSAGE --> | ||||||
|  |             <div fxLayout="row" *ngFor="let message of dialog" class="message-row" | ||||||
|  |                  [ngClass]="{'user' :message.who === user.id}"> | ||||||
|  | 
 | ||||||
|  |                 <img *ngIf="message.who === contact.id" | ||||||
|  |                      src="{{contact.avatar}}" | ||||||
|  |                      class="avatar" | ||||||
|  |                      alt="{{contact.name}}"/> | ||||||
|  | 
 | ||||||
|  |                 <img *ngIf="message.who ===user.id" class="avatar" src="{{user.avatar}}"> | ||||||
|  | 
 | ||||||
|  |                 <div class="bubble"> | ||||||
|  |                     <div class="message">{{message.message}}</div> | ||||||
|  |                     <div class="time secondary-text">{{message.time | date:'medium'}}</div> | ||||||
|  |                 </div> | ||||||
|  | 
 | ||||||
|  |             </div> | ||||||
|  |             <!-- / MESSAGE --> | ||||||
|  | 
 | ||||||
|  |         </div> | ||||||
|  |         <!-- CHAT MESSAGES --> | ||||||
|  | 
 | ||||||
|  |     </div> | ||||||
|  |     <!-- / CHAT CONTENT --> | ||||||
|  | 
 | ||||||
|  |     <!-- CHAT FOOTER --> | ||||||
|  |     <div class="chat-footer" fxLayout="row" fxLayoutAlign="center center"> | ||||||
|  | 
 | ||||||
|  |         <!-- REPLY FORM --> | ||||||
|  |         <form #replyForm="ngForm" | ||||||
|  |               (ngSubmit)="reply($event)" | ||||||
|  |               (keyup.enter)="reply($event)" | ||||||
|  |               fxFlex class="reply-form" | ||||||
|  |               fxLayout="row" | ||||||
|  |               fxLayoutAlign="start center"> | ||||||
|  | 
 | ||||||
|  |             <md-input-container class="" fxFlex floatPlaceholder="never"> | ||||||
|  |                 <textarea mdInput #replyInput placeholder="Type and hit enter to send message" | ||||||
|  |                           ngModel name="message"></textarea> | ||||||
|  |             </md-input-container> | ||||||
|  | 
 | ||||||
|  |             <button md-fab class="" type="submit" aria-label="Send message"> | ||||||
|  |                 <md-icon>send</md-icon> | ||||||
|  |             </button> | ||||||
|  | 
 | ||||||
|  |         </form> | ||||||
|  |         <!-- / REPLY FORM --> | ||||||
|  |     </div> | ||||||
|  |     <!-- / CHAT FOOTER--> | ||||||
|  | </div> | ||||||
|  | <!-- / CHAT --> | ||||||
							
								
								
									
										135
									
								
								src/app/main/apps/chat/chat-view/chat-view.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								src/app/main/apps/chat/chat-view/chat-view.component.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | |||||||
|  | :host { | ||||||
|  |     display: flex; | ||||||
|  |     flex: 1; | ||||||
|  |     height: 100%; | ||||||
|  |     background: linear-gradient(to bottom, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.6) 20%, rgba(255, 255, 255, 0.8)); | ||||||
|  |     overflow: hidden; | ||||||
|  | 
 | ||||||
|  |     .chat { | ||||||
|  |         height: 100%; | ||||||
|  | 
 | ||||||
|  |         .chat-toolbar { | ||||||
|  |             min-height: 64px; | ||||||
|  |             background-color: #F3F4F5; | ||||||
|  |             color: rgba(0, 0, 0, 0.87); | ||||||
|  |             border-bottom: 1px solid rgba(0, 0, 0, .08); | ||||||
|  | 
 | ||||||
|  |             .responsive-chats-button { | ||||||
|  |                 padding: 0; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             .chat-contact { | ||||||
|  |                 cursor: pointer; | ||||||
|  | 
 | ||||||
|  |                 .avatar { | ||||||
|  |                     margin-right: 16px; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 .chat-contact-name { | ||||||
|  | 
 | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         #chat-content { | ||||||
|  |             background: transparent; | ||||||
|  | 
 | ||||||
|  |             .message-row { | ||||||
|  |                 padding: 16px; | ||||||
|  | 
 | ||||||
|  |                 .bubble { | ||||||
|  |                     position: relative; | ||||||
|  |                     padding: 6px 7px 8px 9px; | ||||||
|  |                     background-color: #FFF; | ||||||
|  |                     box-shadow: 0 1px .5px rgba(0, 0, 0, .13); | ||||||
|  |                     border-radius: 6px; | ||||||
|  | 
 | ||||||
|  |                     &:before { | ||||||
|  |                         background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAmCAMAAADp2asXAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAADGUExURQAAAP////b29vn5+f///wAAAP///wAAAAAAAP///9ra2v////j4+PHx8fv7++Hh4fHx8f////////////////39/QAAAP////////z8/P////39/f39/fz8/P////////////z8/P////////////z8/P////////////v7+/Hx8f///9bW1vz8/K2trf////39/f39/WJiYgAAAExMTFtbWwAAAN3d3cjIyPr6+vX19QAAAO7u7vz8/NTU1Ofn5zMzM////zGPlXsAAABBdFJOUwAcm/kREh4CCDWL1SneR6TfAQffhMYK/A5nRrLWfRc5DW2ih5f+19Kn+9v4g/1LCJuXHwQUKgahcXS6DNnlDMMKKzPoTgAAAKBJREFUKM+V08USwmAQA+C/0NIWd3d3d8/7vxTMcIPkQK7f7CG7s8bQAOY/SCuwFYQU1P+eiCqIK2gpWCmoCrAgoKQgJ8CHgIqAMjg0MxxSQ3DogEMWFBZtUPAHYGB1CyDQWE6AH7BrfXzlAxGAQhECTGAmwN1Okz0Gb/LW4fEItIfrOfNELMh3tck7u+PhcT2zQ7l77/K8iY8yJwV3BeYFqpc/uSyPGdAAAAAASUVORK5CYII=); | ||||||
|  |                         content: ''; | ||||||
|  |                         position: absolute; | ||||||
|  |                         left: -11px; | ||||||
|  |                         bottom: 3px; | ||||||
|  |                         width: 12px; | ||||||
|  |                         height: 19px; | ||||||
|  |                         background-position: 50% 50%; | ||||||
|  |                         background-repeat: no-repeat; | ||||||
|  |                         background-size: contain; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     .message { | ||||||
|  |                         white-space: pre-wrap; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     .time { | ||||||
|  |                         font-size: 11px; | ||||||
|  |                         margin-top: 8px; | ||||||
|  |                         text-align: right; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 &.contact { | ||||||
|  | 
 | ||||||
|  |                     .avatar { | ||||||
|  |                         margin: 0 16px 0 0; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 &.user { | ||||||
|  |                     align-items: flex-end; | ||||||
|  | 
 | ||||||
|  |                     .avatar { | ||||||
|  |                         order: 2; | ||||||
|  |                         margin: 0 0 0 16px; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     .bubble { | ||||||
|  |                         margin-left: auto; | ||||||
|  |                         background-color: #E8F5E9; | ||||||
|  |                         border: 1px solid #DFEBE0; | ||||||
|  |                         order: 1; | ||||||
|  |                         &:before { | ||||||
|  |                             right: -11px; | ||||||
|  |                             left: auto; | ||||||
|  |                             background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAmCAMAAADp2asXAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAD2UExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRsXAAAANzwzNPmxNrtyau5oIWRedDkwNntyczgwdfpyJ+/n97wzsLWtNjsytvwzczfvtPmxau6nNjqxtrtyio1KtzwzNjryAAAANzwzgAAANzwzK7Aor/Us9Lnw8vevAAAAMzevtbpxrvMrX+IdwAAAEROOi45Lr3MrZGjf9LoxX+MctnqydLkwhgYGMzfv9vuyQAAANzwzNvuy9zxy7vMu7XGqNvtzKKykwAAANruzKq6nLnMriQkGMXXuL3PsNjsySgzKAAAANLkw83fvd3vy9z4xtzwzRpFmIEAAABQdFJOUwAXChEGBAMBAgwhDvJ7k0YqMc0Zmwj6apf2kjU0+dkw/swh/CP9j2Wr2gndvaYeBRoxQg6gUPt/FaHJGdTj9A9k7XQLeE6iFcN12xkSt9r4NKizowAAAMFJREFUKM+V0sdywlAMBVDbMX7PQCihQ+iQ0HsJvfem/P/PwBIzugu0PXNnNNJVyPmhsIPhhoB2COwIGuLdhAcl3AhCBoBoHUC6BCBbA0C/EkBFB5D/FjxQwQYg1RI8UKINgDoSAPUlAPqUAMgfAEBfXsEDBV0+Hogi4Zhg4THj9YwHoqEBYOrgYTI3GVgMNn8r+Qq94k9yZNosW/3Hy9VuTjWfHkOX6367bGZUU7de66ieHZrO1OGg8Z1WTgYAFLgD5S1PCkzo1B0AAAAASUVORK5CYII=); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .chat-footer { | ||||||
|  |             min-height: 64px; | ||||||
|  |             max-height: 96px; | ||||||
|  |             background-color: #F3F4F5; | ||||||
|  |             color: rgba(0, 0, 0, 0.87); | ||||||
|  |             border-top: 1px solid rgba(0, 0, 0, .08); | ||||||
|  |             padding: 8px 8px 8px 16px; | ||||||
|  | 
 | ||||||
|  |             .reply-form { | ||||||
|  | 
 | ||||||
|  |                 md-input-container { | ||||||
|  |                     margin: 0; | ||||||
|  |                     padding-right: 16px; | ||||||
|  | 
 | ||||||
|  |                     textarea { | ||||||
|  |                         overflow: auto; | ||||||
|  |                         max-height: 80px; | ||||||
|  |                         transition: height 200ms ease; | ||||||
|  |                         &.grow { | ||||||
|  |                             height: 80px; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     .md-errors-spacer { | ||||||
|  |                         display: none; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 .md-button { | ||||||
|  |                     margin: 0; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										101
									
								
								src/app/main/apps/chat/chat-view/chat-view.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/app/main/apps/chat/chat-view/chat-view.component.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | |||||||
|  | import { AfterViewInit, Component, OnInit, ViewChild, ViewChildren } from '@angular/core'; | ||||||
|  | import { ChatService } from '../chat.service'; | ||||||
|  | import { NgForm } from '@angular/forms'; | ||||||
|  | import { PerfectScrollbarDirective } from 'ngx-perfect-scrollbar'; | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |     selector   : 'fuse-chat-view', | ||||||
|  |     templateUrl: './chat-view.component.html', | ||||||
|  |     styleUrls  : ['./chat-view.component.scss'] | ||||||
|  | }) | ||||||
|  | export class ChatViewComponent implements OnInit, AfterViewInit | ||||||
|  | { | ||||||
|  |     user: any; | ||||||
|  |     chat: any; | ||||||
|  |     dialog: any; | ||||||
|  |     contact: any; | ||||||
|  |     replyInput: any; | ||||||
|  |     selectedChat: any; | ||||||
|  |     @ViewChild(PerfectScrollbarDirective) directiveScroll: PerfectScrollbarDirective; | ||||||
|  |     @ViewChildren('replyInput') replyInputField; | ||||||
|  |     @ViewChild('replyForm') replyForm: NgForm; | ||||||
|  | 
 | ||||||
|  |     constructor(private chatService: ChatService) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ngOnInit() | ||||||
|  |     { | ||||||
|  |         this.user = this.chatService.user; | ||||||
|  |         this.chatService.onChatSelected | ||||||
|  |             .subscribe(chatData => { | ||||||
|  |                 if ( chatData ) | ||||||
|  |                 { | ||||||
|  |                     this.selectedChat = chatData; | ||||||
|  |                     this.contact = chatData.contact; | ||||||
|  |                     this.dialog = chatData.dialog; | ||||||
|  |                     this.readyToReply(); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ngAfterViewInit() | ||||||
|  |     { | ||||||
|  |         this.replyInput = this.replyInputField.first.nativeElement; | ||||||
|  |         this.readyToReply(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     selectContact() | ||||||
|  |     { | ||||||
|  |         this.chatService.selectContact(this.contact); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     readyToReply() | ||||||
|  |     { | ||||||
|  |         setTimeout(() => { | ||||||
|  |             this.replyForm.reset(); | ||||||
|  |             this.focusReplyInput(); | ||||||
|  |             this.scrollToBottom(); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     focusReplyInput() | ||||||
|  |     { | ||||||
|  |         setTimeout(() => { | ||||||
|  |             this.replyInput.focus(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     scrollToBottom(speed?: number) | ||||||
|  |     { | ||||||
|  |         speed = speed || 400; | ||||||
|  |         if ( this.directiveScroll ) | ||||||
|  |         { | ||||||
|  |             setTimeout(() => { | ||||||
|  |                 this.directiveScroll.scrollToBottom(0, speed); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     reply(event) | ||||||
|  |     { | ||||||
|  |         // Message
 | ||||||
|  |         const message = { | ||||||
|  |             who    : this.user.id, | ||||||
|  |             message: this.replyForm.form.value.message, | ||||||
|  |             time   : new Date().toISOString() | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         // Add the message to the chat
 | ||||||
|  |         this.dialog.push(message); | ||||||
|  | 
 | ||||||
|  |         // Update the server
 | ||||||
|  |         this.chatService.updateDialog(this.selectedChat.chatId, this.dialog).then(response => { | ||||||
|  |             this.readyToReply(); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,3 +1,43 @@ | |||||||
| <p> | <div class="page-layout carded fullwidth"> | ||||||
|   chat works! | 
 | ||||||
| </p> |     <!-- TOP BACKGROUND --> | ||||||
|  |     <div class="top-bg md-accent-bg"></div> | ||||||
|  |     <!-- / TOP BACKGROUND --> | ||||||
|  | 
 | ||||||
|  |     <!-- CENTER --> | ||||||
|  |     <div class="center"> | ||||||
|  | 
 | ||||||
|  |         <!-- CONTENT CARD --> | ||||||
|  |         <div class="content-card"> | ||||||
|  | 
 | ||||||
|  |             <md-sidenav-container> | ||||||
|  | 
 | ||||||
|  |                 <!-- LEFT SIDENAV --> | ||||||
|  |                 <md-sidenav class="sidenav mat-sidenav-opened" align="start" opened="true" mode="side" | ||||||
|  |                             fuseMdSidenavHelper="chat-left-sidenav" md-is-locked-open="gt-md"> | ||||||
|  |                     <fuse-chat-left-sidenav></fuse-chat-left-sidenav> | ||||||
|  |                 </md-sidenav> | ||||||
|  |                 <!-- / LEFT SIDENAV --> | ||||||
|  | 
 | ||||||
|  |                 <!-- CONTENT --> | ||||||
|  |                 <fuse-chat-start *ngIf="!selectedChat"></fuse-chat-start> | ||||||
|  | 
 | ||||||
|  |                 <fuse-chat-view *ngIf="selectedChat"></fuse-chat-view> | ||||||
|  |                 <!-- / CONTENT --> | ||||||
|  | 
 | ||||||
|  |                 <!-- RIGHT SIDENAV --> | ||||||
|  |                 <md-sidenav class="sidenav mat-sidenav-opened" align="end" opened="false" mode="over" | ||||||
|  |                             fuseMdSidenavHelper="chat-right-sidenav"> | ||||||
|  |                     <fuse-chat-right-sidenav></fuse-chat-right-sidenav> | ||||||
|  |                 </md-sidenav> | ||||||
|  |                 <!-- / RIGHT SIDENAV --> | ||||||
|  | 
 | ||||||
|  |             </md-sidenav-container> | ||||||
|  | 
 | ||||||
|  |         </div> | ||||||
|  |         <!-- / CONTENT CARD --> | ||||||
|  | 
 | ||||||
|  |     </div> | ||||||
|  |     <!-- / CENTER --> | ||||||
|  | 
 | ||||||
|  | </div> | ||||||
|  | |||||||
| @ -0,0 +1,31 @@ | |||||||
|  | :host { | ||||||
|  |     height: 100% !important; | ||||||
|  | 
 | ||||||
|  |     .center { | ||||||
|  |         padding: 32px 32px 0 32px; | ||||||
|  |         max-width: 1400px; | ||||||
|  |         height: 100%; | ||||||
|  |         margin: 0 auto; | ||||||
|  | 
 | ||||||
|  |         .content-card { | ||||||
|  |             position: relative; | ||||||
|  |             background: url('/assets/images/patterns/rain-grey.png') repeat; | ||||||
|  |             height: 100%; | ||||||
|  | 
 | ||||||
|  |             .mat-sidenav-container { | ||||||
|  |                 width: 100%; | ||||||
|  |                 height: 100%; | ||||||
|  |                 background: transparent; | ||||||
|  | 
 | ||||||
|  |                 md-sidenav { | ||||||
|  |                     display: flex; | ||||||
|  |                     flex-direction: column; | ||||||
|  |                     width: 400px; | ||||||
|  |                     max-width: 90%; | ||||||
|  |                     box-shadow: 0 0 1px rgba(0, 0, 0, .37); | ||||||
|  |                     overflow: hidden; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,15 +1,25 @@ | |||||||
| import { Component, OnInit } from '@angular/core'; | import { Component, OnInit, ViewEncapsulation } from '@angular/core'; | ||||||
|  | import { ChatService } from './chat.service'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|     selector   : 'fuse-chat', |     selector   : 'fuse-chat', | ||||||
|     templateUrl: './chat.component.html', |     templateUrl: './chat.component.html', | ||||||
|     styleUrls  : ['./chat.component.scss'] |     styleUrls  : ['./chat.component.scss'] | ||||||
| }) | }) | ||||||
| export class ChatComponent implements OnInit { | export class ChatComponent implements OnInit | ||||||
|  | { | ||||||
|  |     selectedChat: any; | ||||||
| 
 | 
 | ||||||
|   constructor() { } |     constructor(private chatService: ChatService) | ||||||
|  |     { | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|   ngOnInit() { |     ngOnInit() | ||||||
|  |     { | ||||||
|  |         this.chatService.onChatSelected | ||||||
|  |             .subscribe(chatData => { | ||||||
|  |                 this.selectedChat = chatData; | ||||||
|  |             }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,10 +2,21 @@ import {NgModule} from '@angular/core'; | |||||||
| import {SharedModule} from '../../../core/modules/shared.module'; | import {SharedModule} from '../../../core/modules/shared.module'; | ||||||
| import {RouterModule, Routes} from '@angular/router'; | import {RouterModule, Routes} from '@angular/router'; | ||||||
| import {ChatComponent} from './chat.component'; | import {ChatComponent} from './chat.component'; | ||||||
|  | import {ChatService} from './chat.service'; | ||||||
|  | import { ChatViewComponent } from './chat-view/chat-view.component'; | ||||||
|  | import { ChatStartComponent } from './chat-start/chat-start.component'; | ||||||
|  | import {ChatsSidenavComponent} from './sidenavs/left/chats/chats.component'; | ||||||
|  | import { UserSidenavComponent } from './sidenavs/left/user/user.component'; | ||||||
|  | import { LeftSidenavComponent } from './sidenavs/left/left.component'; | ||||||
|  | import { RightSidenavComponent } from './sidenavs/right/right.component'; | ||||||
|  | import { ContactSidenavComponent } from './sidenavs/right/contact/contact.component'; | ||||||
| 
 | 
 | ||||||
| const routes: Routes = [ | const routes: Routes = [ | ||||||
|     { |     { | ||||||
|         path: 'apps/chat', component: ChatComponent, children: [] |         path   : 'apps/chat', component: ChatComponent, children: [], | ||||||
|  |         resolve: { | ||||||
|  |             chat: ChatService | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
| @ -15,7 +26,17 @@ const routes: Routes = [ | |||||||
|         RouterModule.forChild(routes) |         RouterModule.forChild(routes) | ||||||
|     ], |     ], | ||||||
|     declarations: [ |     declarations: [ | ||||||
|         ChatComponent |         ChatComponent, | ||||||
|  |         ChatViewComponent, | ||||||
|  |         ChatStartComponent, | ||||||
|  |         ChatsSidenavComponent, | ||||||
|  |         UserSidenavComponent, | ||||||
|  |         LeftSidenavComponent, | ||||||
|  |         RightSidenavComponent, | ||||||
|  |         ContactSidenavComponent | ||||||
|  |     ], | ||||||
|  |     providers   : [ | ||||||
|  |         ChatService | ||||||
|     ] |     ] | ||||||
| }) | }) | ||||||
| export class ChatModule | export class ChatModule | ||||||
|  | |||||||
							
								
								
									
										259
									
								
								src/app/main/apps/chat/chat.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								src/app/main/apps/chat/chat.service.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,259 @@ | |||||||
|  | import { Injectable } from '@angular/core'; | ||||||
|  | import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router'; | ||||||
|  | import { Observable } from 'rxjs/Observable'; | ||||||
|  | import { Http } from '@angular/http'; | ||||||
|  | import { Subject } from 'rxjs/Subject'; | ||||||
|  | import { BehaviorSubject } from 'rxjs/BehaviorSubject'; | ||||||
|  | 
 | ||||||
|  | @Injectable() | ||||||
|  | export class ChatService implements Resolve<any> | ||||||
|  | { | ||||||
|  |     contacts: any[]; | ||||||
|  |     chats: any[]; | ||||||
|  |     user: any; | ||||||
|  |     onChatSelected = new BehaviorSubject<any>(null); | ||||||
|  |     onContactSelected = new BehaviorSubject<any>(null); | ||||||
|  |     onChatsUpdated = new Subject<any>(); | ||||||
|  |     onUserUpdated = new Subject<any>(); | ||||||
|  |     onLeftSidenavViewChanged = new Subject<any>(); | ||||||
|  |     onRightSidenavViewChanged = new Subject<any>(); | ||||||
|  | 
 | ||||||
|  |     constructor(private http: Http) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Get chat | ||||||
|  |      * @param contactId | ||||||
|  |      * @returns {Promise<any>} | ||||||
|  |      */ | ||||||
|  |     getChat(contactId) | ||||||
|  |     { | ||||||
|  |         const chatItem = this.user.chatList.find((item) => { | ||||||
|  |             return item.contactId === contactId; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         /** | ||||||
|  |          * Create new chat, if it's not created yet. | ||||||
|  |          */ | ||||||
|  |         if ( !chatItem ) | ||||||
|  |         { | ||||||
|  |             this.createNewChat(contactId).then((newChats) => { | ||||||
|  |                 this.getChat(contactId); | ||||||
|  |             }); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return new Promise((resolve, reject) => { | ||||||
|  |             this.http.get('api/chat-chats/' + chatItem.id) | ||||||
|  |                 .subscribe(response => { | ||||||
|  |                     const chat = response.json().data; | ||||||
|  | 
 | ||||||
|  |                     const chatContact = this.contacts.find((contact) => { | ||||||
|  |                         return contact.id === contactId; | ||||||
|  |                     }); | ||||||
|  | 
 | ||||||
|  |                     const chatData = { | ||||||
|  |                         chatId : chat.id, | ||||||
|  |                         dialog : chat.dialog, | ||||||
|  |                         contact: chatContact | ||||||
|  |                     }; | ||||||
|  | 
 | ||||||
|  |                     this.onChatSelected.next({...chatData}); | ||||||
|  | 
 | ||||||
|  |                 }, reject); | ||||||
|  | 
 | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Create New Chat | ||||||
|  |      * @param contactId | ||||||
|  |      * @returns {Promise<any>} | ||||||
|  |      */ | ||||||
|  |     createNewChat(contactId) | ||||||
|  |     { | ||||||
|  |         return new Promise((resolve, reject) => { | ||||||
|  | 
 | ||||||
|  |             const contact = this.contacts.find((item) => { | ||||||
|  |                 return item.id === contactId; | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             const chatId = this.guidGenerator(); | ||||||
|  | 
 | ||||||
|  |             const chat = { | ||||||
|  |                 id    : chatId, | ||||||
|  |                 dialog: [] | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             const chatListItem = { | ||||||
|  |                 'id'             : chatId, | ||||||
|  |                 'contactId'      : contactId, | ||||||
|  |                 'unread'         : null, | ||||||
|  |                 'lastMessageTime': '2017-02-18T10:30:18.931Z' | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             /** | ||||||
|  |              * Add new chat list item to the user's chat list | ||||||
|  |              */ | ||||||
|  |             this.user.chatList.push(chatListItem); | ||||||
|  | 
 | ||||||
|  |             /** | ||||||
|  |              * Post the created chat | ||||||
|  |              */ | ||||||
|  |             this.http.post('api/chat-chats', {...chat}) | ||||||
|  |                 .subscribe(response => { | ||||||
|  | 
 | ||||||
|  |                     /** | ||||||
|  |                      * Post the new the user data | ||||||
|  |                      */ | ||||||
|  |                     this.http.post('api/chat-user/' + this.user.id, this.user) | ||||||
|  |                         .subscribe(addedlistItem => { | ||||||
|  | 
 | ||||||
|  |                             /** | ||||||
|  |                              * Update the user data from server | ||||||
|  |                              */ | ||||||
|  |                             this.getUser().then(updatedUser => { | ||||||
|  |                                 this.onUserUpdated.next(updatedUser); | ||||||
|  |                                 resolve(updatedUser); | ||||||
|  |                             }); | ||||||
|  |                         }); | ||||||
|  |                 }, reject); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Select Contact | ||||||
|  |      * @param contact | ||||||
|  |      */ | ||||||
|  |     selectContact(contact) | ||||||
|  |     { | ||||||
|  |         this.onContactSelected.next(contact); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Set user status | ||||||
|  |      * @param status | ||||||
|  |      */ | ||||||
|  |     setUserStatus(status) | ||||||
|  |     { | ||||||
|  |         this.user.status = status; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Update user data | ||||||
|  |      * @param userData | ||||||
|  |      */ | ||||||
|  |     updateUserData(userData) | ||||||
|  |     { | ||||||
|  |         this.http.post('api/chat-user/' + this.user.id, userData) | ||||||
|  |             .subscribe(response => { | ||||||
|  |                     this.user = userData; | ||||||
|  |                 } | ||||||
|  |             ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Update the chat dialog | ||||||
|  |      * @param chatId | ||||||
|  |      * @param dialog | ||||||
|  |      * @returns {Promise<any>} | ||||||
|  |      */ | ||||||
|  |     updateDialog(chatId, dialog): Promise<any> | ||||||
|  |     { | ||||||
|  |         return new Promise((resolve, reject) => { | ||||||
|  | 
 | ||||||
|  |             const newData = { | ||||||
|  |                 id    : chatId, | ||||||
|  |                 dialog: dialog | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             this.http.post('api/chat-chats/' + chatId, newData) | ||||||
|  |                 .subscribe(updatedChat => { | ||||||
|  |                     resolve(updatedChat); | ||||||
|  |                 }, reject); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * The Mail App Main Resolver | ||||||
|  |      * @param {ActivatedRouteSnapshot} route | ||||||
|  |      * @param {RouterStateSnapshot} state | ||||||
|  |      * @returns {Observable<any> | Promise<any> | any} | ||||||
|  |      */ | ||||||
|  |     resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any | ||||||
|  |     { | ||||||
|  |         return new Promise((resolve, reject) => { | ||||||
|  |             Promise.all([ | ||||||
|  |                 this.getContacts(), | ||||||
|  |                 this.getChats(), | ||||||
|  |                 this.getUser() | ||||||
|  |             ]).then( | ||||||
|  |                 ([contacts, chats, user]) => { | ||||||
|  |                     this.contacts = contacts; | ||||||
|  |                     this.chats = chats; | ||||||
|  |                     this.user = user; | ||||||
|  |                     resolve(); | ||||||
|  |                 }, | ||||||
|  |                 reject | ||||||
|  |             ); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Get Contacts | ||||||
|  |      * @returns {Promise<any>} | ||||||
|  |      */ | ||||||
|  |     getContacts(): Promise<any> | ||||||
|  |     { | ||||||
|  |         return new Promise((resolve, reject) => { | ||||||
|  |             this.http.get('api/chat-contacts') | ||||||
|  |                 .subscribe(response => { | ||||||
|  |                     resolve(response.json().data); | ||||||
|  |                 }, reject); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Get Chats | ||||||
|  |      * @returns {Promise<any>} | ||||||
|  |      */ | ||||||
|  |     getChats(): Promise<any> | ||||||
|  |     { | ||||||
|  |         return new Promise((resolve, reject) => { | ||||||
|  |             this.http.get('api/chat-chats') | ||||||
|  |                 .subscribe(response => { | ||||||
|  |                     resolve(response.json().data); | ||||||
|  |                 }, reject); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Get User | ||||||
|  |      * @returns {Promise<any>} | ||||||
|  |      */ | ||||||
|  |     getUser(): Promise<any> | ||||||
|  |     { | ||||||
|  |         return new Promise((resolve, reject) => { | ||||||
|  |             this.http.get('api/chat-user') | ||||||
|  |                 .subscribe(response => { | ||||||
|  |                     resolve(response.json().data[0]); | ||||||
|  |                 }, reject); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Random ID Generator | ||||||
|  |      * @returns {string} | ||||||
|  |      */ | ||||||
|  |     guidGenerator() | ||||||
|  |     { | ||||||
|  |         function S4() | ||||||
|  |         { | ||||||
|  |             return (((1 + Math.random()) * 0x10000) || 0).toString(16).substring(1); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return (S4() + S4()); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										183
									
								
								src/app/main/apps/chat/sidenavs/left/chats/chats.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								src/app/main/apps/chat/sidenavs/left/chats/chats.component.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,183 @@ | |||||||
|  | <!-- SIDENAV HEADER --> | ||||||
|  | <div class="sidenav-header"> | ||||||
|  |     <!-- CHATS TOOLBAR --> | ||||||
|  |     <md-toolbar> | ||||||
|  | 
 | ||||||
|  |         <!-- TOOLBAR TOP --> | ||||||
|  |         <div fxFlex fxLayout="row" fxLayoutAlign="space-between center"> | ||||||
|  | 
 | ||||||
|  |             <!-- USER AVATAR WRAPPER --> | ||||||
|  |             <div class="avatar-wrapper"> | ||||||
|  | 
 | ||||||
|  |                 <!-- USER AVATAR --> | ||||||
|  |                 <img (click)="changeLeftSidenavView('user')" | ||||||
|  |                      src="{{user.avatar}}" | ||||||
|  |                      class="md-avatar avatar" | ||||||
|  |                      alt="{{user.name}}"/> | ||||||
|  |                 <!-- / USER AVATAR --> | ||||||
|  | 
 | ||||||
|  |                 <md-icon class="s-16 status" [ngClass]="user.status" [mdMenuTriggerFor]="userStatusMenu"></md-icon> | ||||||
|  | 
 | ||||||
|  |                 <!-- USER STATUS --> | ||||||
|  |                 <md-menu id="user-status-menu" #userStatusMenu="mdMenu"> | ||||||
|  | 
 | ||||||
|  |                     <button md-menu-item (click)="setUserStatus('online')"> | ||||||
|  |                         <div fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  |                             <md-icon class="s-16 status online"></md-icon> | ||||||
|  |                             <span>Online</span> | ||||||
|  |                         </div> | ||||||
|  |                     </button> | ||||||
|  | 
 | ||||||
|  |                     <button md-menu-item (click)="setUserStatus('away')"> | ||||||
|  |                         <div fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  |                             <md-icon class="s-16 status away"></md-icon> | ||||||
|  |                             <span>Away</span> | ||||||
|  |                         </div> | ||||||
|  |                     </button> | ||||||
|  | 
 | ||||||
|  |                     <button md-menu-item (click)="setUserStatus('do-not-disturb')"> | ||||||
|  |                         <div fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  |                             <md-icon class="s-16 status do-not-disturb"></md-icon> | ||||||
|  |                             <span>Do not disturb</span> | ||||||
|  |                         </div> | ||||||
|  |                     </button> | ||||||
|  | 
 | ||||||
|  |                     <button md-menu-item (click)="setUserStatus('offline')"> | ||||||
|  |                         <div fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  |                             <md-icon class="s-16 status offline"></md-icon> | ||||||
|  |                             <span>Offline</span> | ||||||
|  |                         </div> | ||||||
|  |                     </button> | ||||||
|  |                 </md-menu> | ||||||
|  |                 <!-- / USER STATUS --> | ||||||
|  | 
 | ||||||
|  |             </div> | ||||||
|  |             <!-- / USER AVATAR --> | ||||||
|  | 
 | ||||||
|  |             <div> | ||||||
|  |                 <button md-button class="mat-icon-button" | ||||||
|  |                         [mdMenuTriggerFor]="userMenu" | ||||||
|  |                         aria-label="more"> | ||||||
|  |                     <md-icon>more_vert</md-icon> | ||||||
|  |                 </button> | ||||||
|  |                 <md-menu #userMenu="mdMenu"> | ||||||
|  |                     <button md-menu-item (click)="changeLeftSidenavView('user')"> | ||||||
|  |                         Profile | ||||||
|  |                     </button> | ||||||
|  |                     <button md-menu-item (click)="logout()"> | ||||||
|  |                         Logout | ||||||
|  |                     </button> | ||||||
|  |                 </md-menu> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <!-- / TOOLBAR TOP --> | ||||||
|  | 
 | ||||||
|  |         <!-- TOOLBAR BOTTOM --> | ||||||
|  |         <md-toolbar-row> | ||||||
|  | 
 | ||||||
|  |             <!-- SEARCH --> | ||||||
|  |             <div class="search-wrapper" fxFlex fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  | 
 | ||||||
|  |                 <div class="search" fxFlex fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  | 
 | ||||||
|  |                     <md-icon>search</md-icon> | ||||||
|  | 
 | ||||||
|  |                     <input [(ngModel)]="chatSearch.name" type="text" placeholder="Search or start new chat" fxFlex> | ||||||
|  | 
 | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |             <!-- / SEARCH --> | ||||||
|  | 
 | ||||||
|  |         </md-toolbar-row> | ||||||
|  |         <!-- / TOOLBAR BOTTOM --> | ||||||
|  | 
 | ||||||
|  |     </md-toolbar> | ||||||
|  |     <!-- / CHATS TOOLBAR --> | ||||||
|  | 
 | ||||||
|  | </div> | ||||||
|  | <!-- / SIDENAV HEADER --> | ||||||
|  | 
 | ||||||
|  | <!-- SIDENAV CONTENT --> | ||||||
|  | <div class="sidenav-content" perfect-scrollbar fxFlex> | ||||||
|  | 
 | ||||||
|  |     <!-- CHATS CONTENT --> | ||||||
|  |     <div> | ||||||
|  | 
 | ||||||
|  |         <!-- CHATS LIST--> | ||||||
|  |         <div class="chat-list" fxLayout="column"> | ||||||
|  | 
 | ||||||
|  |             <div md-subheader *ngIf="(user.chatList | filterBy: chatSearch).length > 0"> | ||||||
|  |                 Chats | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |             <button md-button class="contact" | ||||||
|  |                     *ngFor="let chat of user.chatList | filterBy: chatSearch" | ||||||
|  |                     (click)="getChat(chat.contactId)" ngClass="{'unread':contact.unread}"> | ||||||
|  | 
 | ||||||
|  |                 <div fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  | 
 | ||||||
|  |                     <div class="avatar-wrapper" fxFlex="0 1 auto" fxLayoutAlign="center center"> | ||||||
|  |                         <img [src]="contacts |getById:chat.contactId:'avatar'" | ||||||
|  |                              class="avatar" | ||||||
|  |                              alt="{{contacts |getById:chat.contactId:'name'}}"/> | ||||||
|  |                         <md-icon class="s-16 status" [ngClass]="contacts |getById:chat.contactId:'status'"></md-icon> | ||||||
|  |                     </div> | ||||||
|  | 
 | ||||||
|  |                     <div fxLayout="row" fxFlex> | ||||||
|  | 
 | ||||||
|  |                         <div class="" fxFlex fxLayout="column" fxLayoutAlign="center start"> | ||||||
|  |                             <div class="contact-name">{{contacts |getById:chat.contactId:'name'}}</div> | ||||||
|  |                             <p class="contact-last-message text-truncate">{{chat.lastMessage}}</p> | ||||||
|  |                         </div> | ||||||
|  | 
 | ||||||
|  |                         <div fxLayout="column" fxLayoutAlign="center end"> | ||||||
|  |                             <div class="contact-last-message-time"> | ||||||
|  |                                 {{chat.lastMessageTime | date}} | ||||||
|  |                             </div> | ||||||
|  |                             <div *ngIf="chat.unread" class="unread-message-count">{{chat.unread}}</div> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </button> | ||||||
|  | 
 | ||||||
|  |         </div> | ||||||
|  |         <!-- / CHATS LIST--> | ||||||
|  | 
 | ||||||
|  |         <!-- CONTACTS LIST--> | ||||||
|  |         <div class="contact-list" fxLayout="column"> | ||||||
|  | 
 | ||||||
|  |             <div md-subheader *ngIf="(contacts| filterBy: chatSearch).length > 0"> | ||||||
|  |                 Contacts | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |             <button md-button class="contact" | ||||||
|  |                     ng-show="chatSearch" | ||||||
|  |                     *ngFor="let contact of contacts| filterBy: chatSearch" | ||||||
|  |                     (click)="getChat(contact.id)"> | ||||||
|  | 
 | ||||||
|  |                 <div fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  |                     <div class="avatar-wrapper" fxFlex="0 1 auto"> | ||||||
|  |                         <img src="{{contact.avatar}}" class="md-avatar avatar" alt="{{contact.name}}"/> | ||||||
|  |                         <md-icon class="s-16 status" [ngClass]="contact.status"></md-icon> | ||||||
|  |                     </div> | ||||||
|  | 
 | ||||||
|  |                     <div class="" fxLayout="column" fxLayoutAlign="center start"> | ||||||
|  |                         <div class="contact-name">{{contact.name}}</div> | ||||||
|  |                         <p class="contact-mood">{{contact.mood}}</p> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </button> | ||||||
|  |         </div> | ||||||
|  |         <!-- / CONTACTS LIST--> | ||||||
|  | 
 | ||||||
|  |         <!-- NO RESULTS MESSAGE --> | ||||||
|  |         <div *ngIf="(contacts| filterBy: chatSearch).length === 0" class="no-results-message"> | ||||||
|  |             No results.. | ||||||
|  |         </div> | ||||||
|  |         <!-- NO RESULTS MESSAGE--> | ||||||
|  | 
 | ||||||
|  |     </div> | ||||||
|  |     <!-- / CHATS CONTENT --> | ||||||
|  | 
 | ||||||
|  | </div> | ||||||
|  | <!-- / SIDENAV CONTENT --> | ||||||
							
								
								
									
										110
									
								
								src/app/main/apps/chat/sidenavs/left/chats/chats.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/app/main/apps/chat/sidenavs/left/chats/chats.component.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,110 @@ | |||||||
|  | @import "src/app/core/scss/fuse"; | ||||||
|  | 
 | ||||||
|  | :host { | ||||||
|  |     display: flex; | ||||||
|  |     flex: 1; | ||||||
|  |     flex-direction: column; | ||||||
|  | 
 | ||||||
|  |     .sidenav-header { | ||||||
|  | 
 | ||||||
|  |         md-toolbar { | ||||||
|  |             border-bottom: 1px solid rgba(0, 0, 0, .08); | ||||||
|  | 
 | ||||||
|  |             .avatar-wrapper { | ||||||
|  | 
 | ||||||
|  |                 .avatar, .status { | ||||||
|  |                     cursor: pointer; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             .search { | ||||||
|  |                 height: 36px; | ||||||
|  |                 line-height: 36px; | ||||||
|  |                 padding: 8px; | ||||||
|  |                 background: #FFFFFF; | ||||||
|  |                 font-size: 13px; | ||||||
|  |                 @include mat-elevation(1); | ||||||
|  | 
 | ||||||
|  |                 .icon { | ||||||
|  |                     margin: 0; | ||||||
|  |                     color: rgba(0, 0, 0, 0.54); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 input { | ||||||
|  |                     padding-left: 12px; | ||||||
|  |                     height: 36px; | ||||||
|  |                     color: rgba(0, 0, 0, 0.54); | ||||||
|  |                     border: none; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .sidenav-content { | ||||||
|  |         .contact-list, .chat-list { | ||||||
|  | 
 | ||||||
|  |             .mat-subheader { | ||||||
|  |                 padding-left: 16px; | ||||||
|  |                 font-size: 20px; | ||||||
|  |                 font-weight: 300; | ||||||
|  |                 height: 88px; | ||||||
|  |                 line-height: 88px; | ||||||
|  |                 color: mat-color($accent); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             .contact { | ||||||
|  |                 white-space: normal; | ||||||
|  |                 text-align: left; | ||||||
|  |                 letter-spacing: .010em; | ||||||
|  |                 min-height: 88px; | ||||||
|  |                 border-bottom: 1px solid rgba(0, 0, 0, 0.12); | ||||||
|  |                 padding: 16px; | ||||||
|  |                 font-weight: 400; | ||||||
|  | 
 | ||||||
|  |                 .avatar-wrapper { | ||||||
|  | 
 | ||||||
|  |                     .avatar { | ||||||
|  |                         margin-right: 16px; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 .contact-name { | ||||||
|  |                     font-size: 16px; | ||||||
|  |                     white-space: nowrap; | ||||||
|  |                     text-overflow: ellipsis; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 .contact-last-message { | ||||||
|  |                     line-height: 1.6em; | ||||||
|  |                     margin: 0; | ||||||
|  |                     font-weight: 500; | ||||||
|  |                     color: rgba(0, 0, 0, 0.54); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 .contact-mood { | ||||||
|  | 
 | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 .unread-message-count { | ||||||
|  |                     border-radius: 50%; | ||||||
|  |                     text-align: center; | ||||||
|  |                     width: 24px; | ||||||
|  |                     height: 24px; | ||||||
|  |                     line-height: 24px; | ||||||
|  |                     background-color: mat-color($accent); | ||||||
|  |                     color: map-get($accent, default-contrast); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .no-results-message { | ||||||
|  |             position: absolute; | ||||||
|  |             width: 100%; | ||||||
|  |             height: 88px; | ||||||
|  |             padding: 16px; | ||||||
|  |             background: #FFFFFF; | ||||||
|  |             font-size: 15px; | ||||||
|  |             font-weight: 400; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,66 @@ | |||||||
|  | import { Component, OnInit } from '@angular/core'; | ||||||
|  | import { ChatService } from '../../../chat.service'; | ||||||
|  | import { FuseMdSidenavHelperService } from '../../../../../../core/directives/md-sidenav-helper/md-sidenav-helper.service'; | ||||||
|  | import { ObservableMedia } from '@angular/flex-layout'; | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |     selector   : 'fuse-chat-chats-sidenav', | ||||||
|  |     templateUrl: './chats.component.html', | ||||||
|  |     styleUrls  : ['./chats.component.scss'] | ||||||
|  | }) | ||||||
|  | export class ChatsSidenavComponent implements OnInit | ||||||
|  | { | ||||||
|  |     user: any; | ||||||
|  |     chats: any[]; | ||||||
|  |     contacts: any[]; | ||||||
|  |     chatSearch: any; | ||||||
|  | 
 | ||||||
|  |     constructor(private chatService: ChatService, | ||||||
|  |                 private fuseMdSidenavService: FuseMdSidenavHelperService, | ||||||
|  |                 public media: ObservableMedia) | ||||||
|  |     { | ||||||
|  |         this.chatSearch = { | ||||||
|  |             name: '' | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ngOnInit() | ||||||
|  |     { | ||||||
|  |         this.user = this.chatService.user; | ||||||
|  |         this.chats = this.chatService.chats; | ||||||
|  |         this.contacts = this.chatService.contacts; | ||||||
|  | 
 | ||||||
|  |         this.chatService.onChatsUpdated.subscribe(updatedChats => { | ||||||
|  |             this.chats = updatedChats; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         this.chatService.onUserUpdated.subscribe(updatedUser => { | ||||||
|  |             this.user = updatedUser; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     getChat(contact) | ||||||
|  |     { | ||||||
|  |         this.chatService.getChat(contact); | ||||||
|  | 
 | ||||||
|  |         if ( !this.media.isActive('gt-md') ) | ||||||
|  |         { | ||||||
|  |             this.fuseMdSidenavService.getSidenav('chat-left-sidenav').toggle(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     setUserStatus(status) | ||||||
|  |     { | ||||||
|  |         this.chatService.setUserStatus(status); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     changeLeftSidenavView(view) | ||||||
|  |     { | ||||||
|  |         this.chatService.onLeftSidenavViewChanged.next(view); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     logout() | ||||||
|  |     { | ||||||
|  |         console.info('logout triggered'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								src/app/main/apps/chat/sidenavs/left/left.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/app/main/apps/chat/sidenavs/left/left.component.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | <div [ngSwitch]="view" class="views"> | ||||||
|  |     <fuse-chat-chats-sidenav class="view" | ||||||
|  |         *ngSwitchCase="'chats'" | ||||||
|  |         [@slideInRight]> | ||||||
|  |     </fuse-chat-chats-sidenav> | ||||||
|  | 
 | ||||||
|  |     <fuse-chat-user-sidenav class="view" | ||||||
|  |         *ngSwitchCase="'user'" | ||||||
|  |         [@slideInLeft]> | ||||||
|  |     </fuse-chat-user-sidenav> | ||||||
|  | </div> | ||||||
							
								
								
									
										20
									
								
								src/app/main/apps/chat/sidenavs/left/left.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/app/main/apps/chat/sidenavs/left/left.component.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | :host { | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column; | ||||||
|  |     height: 100%; | ||||||
|  | 
 | ||||||
|  |     .views { | ||||||
|  |         display: flex; | ||||||
|  |         flex-direction: column; | ||||||
|  |         height: 100%; | ||||||
|  | 
 | ||||||
|  |         .view { | ||||||
|  |             position: absolute; | ||||||
|  |             height: 100%; | ||||||
|  |             bottom: 0; | ||||||
|  |             left: 0; | ||||||
|  |             right: 0; | ||||||
|  |             top: 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								src/app/main/apps/chat/sidenavs/left/left.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/app/main/apps/chat/sidenavs/left/left.component.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | import { Component, OnInit } from '@angular/core'; | ||||||
|  | import { Animations } from '../../../../../core/animations'; | ||||||
|  | import { ChatService } from '../../chat.service'; | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |     selector   : 'fuse-chat-left-sidenav', | ||||||
|  |     templateUrl: './left.component.html', | ||||||
|  |     styleUrls  : ['./left.component.scss'], | ||||||
|  |     animations : [Animations.slideInLeft, Animations.slideInRight] | ||||||
|  | }) | ||||||
|  | export class LeftSidenavComponent implements OnInit | ||||||
|  | { | ||||||
|  |     view: string; | ||||||
|  | 
 | ||||||
|  |     constructor(private chatService: ChatService) | ||||||
|  |     { | ||||||
|  |         this.view = 'chats'; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ngOnInit() | ||||||
|  |     { | ||||||
|  |         this.chatService.onLeftSidenavViewChanged.subscribe(view => { | ||||||
|  |             this.view = view; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,78 @@ | |||||||
|  | <!-- SIDENAV HEADER --> | ||||||
|  | <div class="sidenav-header"> | ||||||
|  | 
 | ||||||
|  |     <!-- USER TOOLBAR --> | ||||||
|  |     <md-toolbar> | ||||||
|  | 
 | ||||||
|  |         <!-- TOOLBAR TOP --> | ||||||
|  |         <div fxFlex fxLayout="row" fxLayoutAlign="space-between center"> | ||||||
|  | 
 | ||||||
|  |             <button md-button class="mat-icon-button" (click)="changeLeftSidenavView('chats')" aria-label="back"> | ||||||
|  |                 <md-icon>arrow_back</md-icon> | ||||||
|  |             </button> | ||||||
|  | 
 | ||||||
|  |         </div> | ||||||
|  |         <!-- / TOOLBAR TOP --> | ||||||
|  | 
 | ||||||
|  |         <!-- TOOLBAR BOTTOM --> | ||||||
|  |         <md-toolbar-row class="toolbar-bottom" fxLayout="column" fxLayoutAlign="center center"> | ||||||
|  | 
 | ||||||
|  |             <img [src]="user.avatar" class="avatar user-avatar huge" alt="{{user.name}}"/> | ||||||
|  | 
 | ||||||
|  |             <div class="user-name my-8">{{user.name}}</div> | ||||||
|  | 
 | ||||||
|  |         </md-toolbar-row> | ||||||
|  |         <!-- / TOOLBAR BOTTOM --> | ||||||
|  | 
 | ||||||
|  |     </md-toolbar> | ||||||
|  |     <!-- / USER TOOLBAR --> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <!-- SIDENAV CONTENT --> | ||||||
|  | <div class="sidenav-content p-16" perfect-scrollbar fxFlex> | ||||||
|  | 
 | ||||||
|  |     <!-- USER MOOD --> | ||||||
|  |     <md-card> | ||||||
|  | 
 | ||||||
|  |         <form [formGroup]="userForm" fxLayout="column"> | ||||||
|  | 
 | ||||||
|  |             <md-input-container class="mb-24" fxFlex> | ||||||
|  |                 <textarea mdInput placeholder="Mood" name="mood" | ||||||
|  |                           formControlName="mood" rows="3"></textarea> | ||||||
|  |             </md-input-container> | ||||||
|  | 
 | ||||||
|  |             <md-radio-group formControlName="status" fxLayout="column"> | ||||||
|  | 
 | ||||||
|  |                 <md-radio-button value="online" class="py-8"> | ||||||
|  |                     <div fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  |                         <md-icon class="status online mr-8"></md-icon> | ||||||
|  |                         <span class="mat-h4 m-0">Online</span> | ||||||
|  |                     </div> | ||||||
|  |                 </md-radio-button> | ||||||
|  | 
 | ||||||
|  |                 <md-radio-button value="away" class="py-8"> | ||||||
|  |                     <div fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  |                         <md-icon class="status away mr-8"></md-icon> | ||||||
|  |                         <span class="mat-h4 m-0">Away</span> | ||||||
|  |                     </div> | ||||||
|  |                 </md-radio-button> | ||||||
|  | 
 | ||||||
|  |                 <md-radio-button value="do-not-disturb" class="py-8"> | ||||||
|  |                     <div fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  |                         <md-icon class="status do-not-disturb mr-8"></md-icon> | ||||||
|  |                         <span class="mat-h4 m-0">Do not disturb</span> | ||||||
|  |                     </div> | ||||||
|  |                 </md-radio-button> | ||||||
|  | 
 | ||||||
|  |                 <md-radio-button value="offline" class="py-8"> | ||||||
|  |                     <div fxLayout="row" fxLayoutAlign="start center"> | ||||||
|  |                         <md-icon class="status offline mr-8"></md-icon> | ||||||
|  |                         <span class="mat-h4 m-0">Offline</span> | ||||||
|  |                     </div> | ||||||
|  |                 </md-radio-button> | ||||||
|  |             </md-radio-group> | ||||||
|  | 
 | ||||||
|  |         </form> | ||||||
|  |     </md-card> | ||||||
|  |     <!-- / USER MOOD --> | ||||||
|  | </div> | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | @import "src/app/core/scss/fuse"; | ||||||
|  | 
 | ||||||
|  | :host { | ||||||
|  |     display: flex; | ||||||
|  |     flex: 1; | ||||||
|  |     flex-direction: column; | ||||||
|  | 
 | ||||||
|  |     md-toolbar { | ||||||
|  |         background-color: mat-color($accent); | ||||||
|  |         color: map-get($accent, default-contrast); | ||||||
|  | 
 | ||||||
|  |         .toolbar-bottom { | ||||||
|  |             height: 240px; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .sidenav-content{ | ||||||
|  |         background: whitesmoke; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								src/app/main/apps/chat/sidenavs/left/user/user.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/app/main/apps/chat/sidenavs/left/user/user.component.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | |||||||
|  | import { Component, OnDestroy, OnInit } from '@angular/core'; | ||||||
|  | import { ChatService } from '../../../chat.service'; | ||||||
|  | import { FormControl, FormGroup } from '@angular/forms'; | ||||||
|  | import 'rxjs/Rx'; | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |     selector   : 'fuse-chat-user-sidenav', | ||||||
|  |     templateUrl: './user.component.html', | ||||||
|  |     styleUrls  : ['./user.component.scss'] | ||||||
|  | }) | ||||||
|  | export class UserSidenavComponent implements OnInit, OnDestroy | ||||||
|  | { | ||||||
|  |     user: any; | ||||||
|  |     onFormChange: any; | ||||||
|  |     userForm: FormGroup; | ||||||
|  | 
 | ||||||
|  |     constructor(private chatService: ChatService) | ||||||
|  |     { | ||||||
|  |         this.user = this.chatService.user; | ||||||
|  |         this.userForm = new FormGroup({ | ||||||
|  |             mood  : new FormControl(this.user.mood), | ||||||
|  |             status: new FormControl(this.user.status) | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ngOnInit() | ||||||
|  |     { | ||||||
|  |         this.onFormChange = this.userForm.valueChanges | ||||||
|  |             .debounceTime(500) | ||||||
|  |             .distinctUntilChanged() | ||||||
|  |             .subscribe(data => { | ||||||
|  |                 this.user.mood = data.mood; | ||||||
|  |                 this.user.status = data.status; | ||||||
|  |                 this.chatService.updateUserData(this.user); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     changeLeftSidenavView(view) | ||||||
|  |     { | ||||||
|  |         this.chatService.onLeftSidenavViewChanged.next(view); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ngOnDestroy() | ||||||
|  |     { | ||||||
|  |         this.onFormChange.unsubscribe(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | <!-- SIDENAV HEADER --> | ||||||
|  | <div class="sidenav-header" *ngIf="contact"> | ||||||
|  | 
 | ||||||
|  |     <!-- CONTACT TOOLBAR --> | ||||||
|  |     <md-toolbar> | ||||||
|  | 
 | ||||||
|  |         <!-- TOOLBAR TOP --> | ||||||
|  |         <div fxFlex fxLayout="row" fxLayoutAlign="space-between center"> | ||||||
|  | 
 | ||||||
|  |             <div>Contact Info</div> | ||||||
|  | 
 | ||||||
|  |             <button md-button class="mat-icon-button" fuseMdSidenavToggler="chat-right-sidenav" aria-label="close"> | ||||||
|  |                 <md-icon>close</md-icon> | ||||||
|  |             </button> | ||||||
|  | 
 | ||||||
|  |         </div> | ||||||
|  |         <!-- / TOOLBAR TOP --> | ||||||
|  | 
 | ||||||
|  |         <!-- TOOLBAR BOTTOM --> | ||||||
|  |         <md-toolbar-row class="toolbar-bottom" fxLayout="column" fxLayoutAlign="center center"> | ||||||
|  | 
 | ||||||
|  |             <img [src]="contact.avatar" class="avatar contact-avatar huge" alt="{{contact.name}}"/> | ||||||
|  | 
 | ||||||
|  |             <div class="contact-name my-8">{{contact.name}}</div> | ||||||
|  | 
 | ||||||
|  |         </md-toolbar-row> | ||||||
|  |         <!-- / TOOLBAR BOTTOM --> | ||||||
|  | 
 | ||||||
|  |     </md-toolbar> | ||||||
|  |     <!-- / CONTACT TOOLBAR --> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <!-- SIDENAV CONTENT --> | ||||||
|  | <div class="sidenav-content p-16" perfect-scrollbar fxFlex *ngIf="contact"> | ||||||
|  | 
 | ||||||
|  |     <!-- CONTACT MOOD --> | ||||||
|  |     <md-card> | ||||||
|  | 
 | ||||||
|  |         <md-input-container fxFlex> | ||||||
|  |                 <textarea mdInput placeholder="Mood" name="mood" | ||||||
|  |                           [value]="contact.mood" rows="3" disabled> | ||||||
|  |                 </textarea> | ||||||
|  |         </md-input-container> | ||||||
|  | 
 | ||||||
|  |     </md-card> | ||||||
|  |     <!-- / CONTACT MOOD --> | ||||||
|  | </div> | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | @import "src/app/core/scss/fuse"; | ||||||
|  | 
 | ||||||
|  | :host { | ||||||
|  |     display: flex; | ||||||
|  |     flex: 1; | ||||||
|  |     flex-direction: column; | ||||||
|  | 
 | ||||||
|  |     md-toolbar { | ||||||
|  |         background-color: mat-color($accent); | ||||||
|  |         color: map-get($accent, default-contrast); | ||||||
|  | 
 | ||||||
|  |         .toolbar-bottom { | ||||||
|  |             height: 240px; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .sidenav-content{ | ||||||
|  |         background: whitesmoke; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,25 @@ | |||||||
|  | import { Component, OnInit } from '@angular/core'; | ||||||
|  | import { ChatService } from '../../../chat.service'; | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |     selector   : 'fuse-chat-contact-sidenav', | ||||||
|  |     templateUrl: './contact.component.html', | ||||||
|  |     styleUrls  : ['./contact.component.scss'] | ||||||
|  | }) | ||||||
|  | export class ContactSidenavComponent implements OnInit | ||||||
|  | { | ||||||
|  |     contact: any; | ||||||
|  | 
 | ||||||
|  |     constructor(private chatService: ChatService) | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ngOnInit() | ||||||
|  |     { | ||||||
|  |         this.chatService.onContactSelected.subscribe(contact => { | ||||||
|  |             this.contact = contact; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | <div [ngSwitch]="view" class="views"> | ||||||
|  | 
 | ||||||
|  |     <fuse-chat-contact-sidenav class="view" | ||||||
|  |         *ngSwitchCase="'contact'" | ||||||
|  |         [@slideInRight]> | ||||||
|  |     </fuse-chat-contact-sidenav> | ||||||
|  | 
 | ||||||
|  | </div> | ||||||
							
								
								
									
										20
									
								
								src/app/main/apps/chat/sidenavs/right/right.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/app/main/apps/chat/sidenavs/right/right.component.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | :host { | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column; | ||||||
|  |     height: 100%; | ||||||
|  | 
 | ||||||
|  |     .views { | ||||||
|  |         display: flex; | ||||||
|  |         flex-direction: column; | ||||||
|  |         height: 100%; | ||||||
|  | 
 | ||||||
|  |         .view { | ||||||
|  |             position: absolute; | ||||||
|  |             height: 100%; | ||||||
|  |             bottom: 0; | ||||||
|  |             left: 0; | ||||||
|  |             right: 0; | ||||||
|  |             top: 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								src/app/main/apps/chat/sidenavs/right/right.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/app/main/apps/chat/sidenavs/right/right.component.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | import { Component, OnInit } from '@angular/core'; | ||||||
|  | import { Animations } from '../../../../../core/animations'; | ||||||
|  | import { ChatService } from '../../chat.service'; | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |     selector   : 'fuse-chat-right-sidenav', | ||||||
|  |     templateUrl: './right.component.html', | ||||||
|  |     styleUrls  : ['./right.component.scss'], | ||||||
|  |     animations : [Animations.slideInLeft, Animations.slideInRight] | ||||||
|  | }) | ||||||
|  | export class RightSidenavComponent implements OnInit | ||||||
|  | { | ||||||
|  |     view: string; | ||||||
|  | 
 | ||||||
|  |     constructor(private chatService: ChatService) | ||||||
|  |     { | ||||||
|  |         this.view = 'contact'; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ngOnInit() | ||||||
|  |     { | ||||||
|  |         this.chatService.onRightSidenavViewChanged.subscribe(view => { | ||||||
|  |             this.view = view; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -26,7 +26,7 @@ | |||||||
|         "label-position": true, |         "label-position": true, | ||||||
|         "max-line-length": [ |         "max-line-length": [ | ||||||
|             true, |             true, | ||||||
|             120 |             180 | ||||||
|         ], |         ], | ||||||
|         "member-access": false, |         "member-access": false, | ||||||
|         "member-ordering": [ |         "member-ordering": [ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user