mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2025-01-10 12:35:07 +00:00
(Contacts App) ongoing
This commit is contained in:
parent
ccfd711c03
commit
c4a08dc939
|
@ -3,20 +3,66 @@ import { trigger, state, transition, animate, style } from '@angular/animations'
|
||||||
export class Animations
|
export class Animations
|
||||||
{
|
{
|
||||||
public static slideInOut = trigger('slideInOut', [
|
public static slideInOut = trigger('slideInOut', [
|
||||||
state('0', style({height: '0px', display: 'none'})),
|
state('0', style({
|
||||||
state('1', style({height: '*', display: 'block'})),
|
height : '0px',
|
||||||
|
display: 'none'
|
||||||
|
})),
|
||||||
|
state('1', style({
|
||||||
|
height : '*',
|
||||||
|
display: 'block'
|
||||||
|
})),
|
||||||
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', [
|
public static slideInLeft = trigger('slideInLeft', [
|
||||||
state('void', style({transform: 'translateX(-100%)', display: 'none'})),
|
state('void', style({
|
||||||
state('*', style({transform: 'translateX(0)', display: 'flex'})),
|
transform: 'translateX(-100%)',
|
||||||
|
display : 'none'
|
||||||
|
})),
|
||||||
|
state('*', style({
|
||||||
|
transform: 'translateX(0)',
|
||||||
|
display : 'flex'
|
||||||
|
})),
|
||||||
transition('void => *', animate('300ms')),
|
transition('void => *', animate('300ms')),
|
||||||
transition('* => void', animate('300ms'))
|
transition('* => void', animate('300ms'))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
public static slideInRight = trigger('slideInRight', [
|
public static slideInRight = trigger('slideInRight', [
|
||||||
state('void', style({transform: 'translateX(100%)', display: 'none'})),
|
state('void', style({
|
||||||
state('*', style({transform: 'translateX(0)', display: 'flex'})),
|
transform: 'translateX(100%)',
|
||||||
|
display : 'none'
|
||||||
|
})),
|
||||||
|
state('*', style({
|
||||||
|
transform: 'translateX(0)',
|
||||||
|
display : 'flex'
|
||||||
|
})),
|
||||||
|
transition('void => *', animate('300ms')),
|
||||||
|
transition('* => void', animate('300ms'))
|
||||||
|
]);
|
||||||
|
|
||||||
|
public static slideInTop = trigger('slideInTop', [
|
||||||
|
state('void', style({
|
||||||
|
transform: 'translateY(-100%)',
|
||||||
|
display : 'none'
|
||||||
|
})),
|
||||||
|
state('*', style({
|
||||||
|
transform: 'translateY(0)',
|
||||||
|
display : 'flex'
|
||||||
|
})),
|
||||||
|
transition('void => *', animate('300ms')),
|
||||||
|
transition('* => void', animate('300ms'))
|
||||||
|
]);
|
||||||
|
|
||||||
|
public static slideInBottom = trigger('slideInBottom', [
|
||||||
|
state('void', style({
|
||||||
|
transform: 'translateY(100%)',
|
||||||
|
display : 'none'
|
||||||
|
})),
|
||||||
|
state('*', style({
|
||||||
|
transform: 'translateY(0)',
|
||||||
|
display : 'flex'
|
||||||
|
})),
|
||||||
transition('void => *', animate('300ms')),
|
transition('void => *', animate('300ms')),
|
||||||
transition('* => void', animate('300ms'))
|
transition('* => void', animate('300ms'))
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -308,6 +308,7 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
|
||||||
&.inner-sidenav {
|
&.inner-sidenav {
|
||||||
|
|
||||||
> md-sidenav-container {
|
> md-sidenav-container {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
.sidenav {
|
.sidenav {
|
||||||
|
|
||||||
|
@ -332,7 +333,6 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 100%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,4 +352,60 @@ export class ContactsFakeDb
|
||||||
'notes' : ''
|
'notes' : ''
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static user = [
|
||||||
|
{
|
||||||
|
'id' : '5725a6802d10e277a0f35724',
|
||||||
|
'name' : 'John Doe',
|
||||||
|
'avatar' : 'assets/images/avatars/profile.jpg',
|
||||||
|
'starred' : [
|
||||||
|
'5725a680ae1ae9a3c960d487',
|
||||||
|
'5725a6801146cce777df2a08',
|
||||||
|
'5725a680bbcec3cc32a8488a',
|
||||||
|
'5725a680bc670af746c435e2',
|
||||||
|
'5725a68009e20d0a9e9acf2a'
|
||||||
|
],
|
||||||
|
'frequentContacts': [
|
||||||
|
'5725a6809fdd915739187ed5',
|
||||||
|
'5725a68031fdbb1db2c1af47',
|
||||||
|
'5725a680606588342058356d',
|
||||||
|
'5725a680e7eb988a58ddf303',
|
||||||
|
'5725a6806acf030f9341e925',
|
||||||
|
'5725a68034cb3968e1f79eac',
|
||||||
|
'5725a6801146cce777df2a08',
|
||||||
|
'5725a680653c265f5c79b5a9'
|
||||||
|
],
|
||||||
|
'groups' : [
|
||||||
|
{
|
||||||
|
'id' : '5725a6802d10e277a0f35739',
|
||||||
|
'name' : 'Friends',
|
||||||
|
'contactIds': [
|
||||||
|
'5725a680bbcec3cc32a8488a',
|
||||||
|
'5725a680e87cb319bd9bd673',
|
||||||
|
'5725a6802d10e277a0f35775'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a6802d10e277a0f35749',
|
||||||
|
'name' : 'Clients',
|
||||||
|
'contactIds': [
|
||||||
|
'5725a680cd7efa56a45aea5d',
|
||||||
|
'5725a68018c663044be49cbf',
|
||||||
|
'5725a6809413bf8a0a5272b1',
|
||||||
|
'5725a6803d87f1b77e17b62b'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a6802d10e277a0f35329',
|
||||||
|
'name' : 'Recent Workers',
|
||||||
|
'contactIds': [
|
||||||
|
'5725a680bbcec3cc32a8488a',
|
||||||
|
'5725a680653c265f5c79b5a9',
|
||||||
|
'5725a6808a178bfd034d6ecf',
|
||||||
|
'5725a6801146cce777df2a08'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ export class FuseFakeDbService implements InMemoryDbService
|
||||||
'profile-photos-videos': ProfileFakeDb.photosVideos,
|
'profile-photos-videos': ProfileFakeDb.photosVideos,
|
||||||
'profile-about' : ProfileFakeDb.about,
|
'profile-about' : ProfileFakeDb.about,
|
||||||
'contacts-contacts' : ContactsFakeDb.contacts,
|
'contacts-contacts' : ContactsFakeDb.contacts,
|
||||||
|
'contacts-user' : ContactsFakeDb.user,
|
||||||
'invoice' : InvoiceFakeDb.invoice,
|
'invoice' : InvoiceFakeDb.invoice,
|
||||||
'file-manager' : FileManagerFakeDb.files,
|
'file-manager' : FileManagerFakeDb.files,
|
||||||
'search-classic' : SearchFakeDb.classic,
|
'search-classic' : SearchFakeDb.classic,
|
||||||
|
|
|
@ -4,13 +4,15 @@
|
||||||
<ng-container cdkColumnDef="checkbox">
|
<ng-container cdkColumnDef="checkbox">
|
||||||
<md-header-cell *cdkHeaderCellDef></md-header-cell>
|
<md-header-cell *cdkHeaderCellDef></md-header-cell>
|
||||||
<md-cell *cdkCellDef="let contact">
|
<md-cell *cdkCellDef="let contact">
|
||||||
Check
|
<md-checkbox [(ngModel)]="checkboxes[contact.id]" (ngModelChange)="onSelectedChange(contact.id)"
|
||||||
|
(click)="$event.stopPropagation()">
|
||||||
|
</md-checkbox>
|
||||||
</md-cell>
|
</md-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- Avatar Column -->
|
<!-- Avatar Column -->
|
||||||
<ng-container cdkColumnDef="avatar">
|
<ng-container cdkColumnDef="avatar">
|
||||||
<md-header-cell *cdkHeaderCellDef>Name</md-header-cell>
|
<md-header-cell *cdkHeaderCellDef></md-header-cell>
|
||||||
<md-cell *cdkCellDef="let contact">
|
<md-cell *cdkCellDef="let contact">
|
||||||
<img class="avatar" *ngIf="contact.avatar" [alt]="contact.name"
|
<img class="avatar" *ngIf="contact.avatar" [alt]="contact.name"
|
||||||
[src]="contact.avatar"/>
|
[src]="contact.avatar"/>
|
||||||
|
@ -27,9 +29,9 @@
|
||||||
|
|
||||||
<!-- Email Column -->
|
<!-- Email Column -->
|
||||||
<ng-container cdkColumnDef="email">
|
<ng-container cdkColumnDef="email">
|
||||||
<md-header-cell *cdkHeaderCellDef>Email</md-header-cell>
|
<md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-sm>Email</md-header-cell>
|
||||||
<md-cell *cdkCellDef="let contact">
|
<md-cell *cdkCellDef="let contact" fxHide fxShow.gt-sm>
|
||||||
<p class="email text-truncate" fxShow.gt-sm>
|
<p class="email text-truncate">
|
||||||
{{contact.email}}
|
{{contact.email}}
|
||||||
</p>
|
</p>
|
||||||
</md-cell>
|
</md-cell>
|
||||||
|
@ -37,9 +39,9 @@
|
||||||
|
|
||||||
<!-- Phone Column -->
|
<!-- Phone Column -->
|
||||||
<ng-container cdkColumnDef="phone">
|
<ng-container cdkColumnDef="phone">
|
||||||
<md-header-cell *cdkHeaderCellDef>Phone</md-header-cell>
|
<md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-md>Phone</md-header-cell>
|
||||||
<md-cell *cdkCellDef="let contact">
|
<md-cell *cdkCellDef="let contact" fxHide fxShow.gt-md>
|
||||||
<p class="phone text-truncate" fxShow.gt-md>
|
<p class="phone text-truncate">
|
||||||
{{contact.phone}}
|
{{contact.phone}}
|
||||||
</p>
|
</p>
|
||||||
</md-cell>
|
</md-cell>
|
||||||
|
@ -47,9 +49,9 @@
|
||||||
|
|
||||||
<!-- Job Title Column -->
|
<!-- Job Title Column -->
|
||||||
<ng-container cdkColumnDef="jobTitle">
|
<ng-container cdkColumnDef="jobTitle">
|
||||||
<md-header-cell *cdkHeaderCellDef>Job title</md-header-cell>
|
<md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-lg>Job title</md-header-cell>
|
||||||
<md-cell *cdkCellDef="let contact">
|
<md-cell *cdkCellDef="let contact" fxHide fxShow.gt-lg>
|
||||||
<p class="job-title text-truncate" fxShow.gt-lg>
|
<p class="job-title text-truncate">
|
||||||
{{contact.jobTitle}}
|
{{contact.jobTitle}}
|
||||||
</p>
|
</p>
|
||||||
</md-cell>
|
</md-cell>
|
||||||
|
@ -57,9 +59,9 @@
|
||||||
|
|
||||||
<!-- Company Column -->
|
<!-- Company Column -->
|
||||||
<ng-container cdkColumnDef="company">
|
<ng-container cdkColumnDef="company">
|
||||||
<md-header-cell *cdkHeaderCellDef>Company</md-header-cell>
|
<md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-lg>Company</md-header-cell>
|
||||||
<md-cell *cdkCellDef="let contact">
|
<md-cell *cdkCellDef="let contact" fxHide fxShow.gt-lg>
|
||||||
<p class="company text-truncate" fxShow.gt-lg>
|
<p class="company text-truncate">
|
||||||
{{contact.company}}
|
{{contact.company}}
|
||||||
</p>
|
</p>
|
||||||
</md-cell>
|
</md-cell>
|
||||||
|
@ -68,15 +70,33 @@
|
||||||
<!-- Buttons Column -->
|
<!-- Buttons Column -->
|
||||||
<ng-container cdkColumnDef="buttons">
|
<ng-container cdkColumnDef="buttons">
|
||||||
<md-header-cell *cdkHeaderCellDef></md-header-cell>
|
<md-header-cell *cdkHeaderCellDef></md-header-cell>
|
||||||
<md-cell *cdkCellDef="let row">
|
<md-cell *cdkCellDef="let contact">
|
||||||
Buttons
|
<div fxFlex="row" fxLayoutAlign="end center">
|
||||||
|
<button md-icon-button (click)="toggleStar(contact.id)" aria-label="Toggle star">
|
||||||
|
<md-icon *ngIf="user.starred.includes(contact.id)">star</md-icon>
|
||||||
|
<md-icon *ngIf="!user.starred.includes(contact.id)">star_outline</md-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button md-icon-button [mdMenuTriggerFor]="moreMenu" aria-label="More"
|
||||||
|
ng-click="$mdOpenMenu($event)">
|
||||||
|
<md-icon>more_vert</md-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<md-menu #moreMenu="mdMenu">
|
||||||
|
<button md-menu-item aria-label="remove" (click)="removeContact(contact.id)">
|
||||||
|
<md-icon>delete</md-icon>
|
||||||
|
<span>Remove</span>
|
||||||
|
</button>
|
||||||
|
</md-menu>
|
||||||
|
</div>
|
||||||
|
|
||||||
</md-cell>
|
</md-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
|
<md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
|
||||||
<md-row *cdkRowDef="let row; columns: displayedColumns;"
|
<md-row *cdkRowDef="let row; columns: displayedColumns;"
|
||||||
(click)="onSelect(row)"
|
(click)="onSelect(row)"
|
||||||
[ngClass]="{'md-light-blue-50-bg':row == selected}"
|
[ngClass]="{'md-light-blue-50-bg':checkboxes[row.id]}"
|
||||||
md-ripple>
|
md-ripple>
|
||||||
</md-row>
|
</md-row>
|
||||||
</md-table>
|
</md-table>
|
||||||
|
|
|
@ -1,20 +1,30 @@
|
||||||
@import "src/app/core/scss/fuse";
|
@import "src/app/core/scss/fuse";
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
.mat-table {
|
.mat-table {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
|
||||||
|
.mat-column-checkbox {
|
||||||
|
flex: 0 1 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-avatar {
|
||||||
|
flex: 0 1 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-buttons {
|
||||||
|
flex: 0 1 80px;
|
||||||
|
}
|
||||||
|
|
||||||
.mat-row {
|
.mat-row {
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.mat-cell {
|
.mat-cell {
|
||||||
|
min-width: 0;
|
||||||
&.mat-column-icon {
|
|
||||||
flex: 0 1 auto;
|
|
||||||
padding: 0 24px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.mat-column-detail-button {
|
&.mat-column-detail-button {
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
|
|
|
@ -11,28 +11,70 @@ import { Observable } from 'rxjs/Observable';
|
||||||
export class ContactListComponent implements OnInit
|
export class ContactListComponent implements OnInit
|
||||||
{
|
{
|
||||||
contacts: any;
|
contacts: any;
|
||||||
|
user: any;
|
||||||
dataSource: FilesDataSource | null;
|
dataSource: FilesDataSource | null;
|
||||||
displayedColumns = ['checkbox', 'avatar', 'name', 'email', 'phone', 'jobTitle', 'buttons'];
|
displayedColumns = ['checkbox', 'avatar', 'name', 'email', 'phone', 'jobTitle', 'buttons'];
|
||||||
selected: any;
|
selectedContacts: any[];
|
||||||
|
checkboxes: {};
|
||||||
|
|
||||||
constructor(private fileManagerService: ContactsService)
|
constructor(private contactsService: ContactsService)
|
||||||
{
|
{
|
||||||
this.fileManagerService.onContactsChanged.subscribe(files => {
|
this.contactsService.onContactsChanged.subscribe(contacts => {
|
||||||
this.contacts = files;
|
|
||||||
|
this.contacts = contacts;
|
||||||
|
|
||||||
|
this.checkboxes = {};
|
||||||
|
contacts.map(contact => {
|
||||||
|
this.checkboxes[contact.id] = false;
|
||||||
});
|
});
|
||||||
this.fileManagerService.onContactSelected.subscribe(selected => {
|
|
||||||
this.selected = selected;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.contactsService.onSelectedContactsChanged.subscribe(selectedContacts => {
|
||||||
|
for ( const id in this.checkboxes )
|
||||||
|
{
|
||||||
|
this.checkboxes[id] = selectedContacts.includes(id);
|
||||||
|
}
|
||||||
|
this.selectedContacts = selectedContacts;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.contactsService.onUserDataChanged.subscribe(user => {
|
||||||
|
this.user = user;
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit()
|
ngOnInit()
|
||||||
{
|
{
|
||||||
this.dataSource = new FilesDataSource(this.fileManagerService);
|
this.dataSource = new FilesDataSource(this.contactsService);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelect(selected)
|
onSelect(selected)
|
||||||
{
|
{
|
||||||
this.fileManagerService.onContactSelected.next(selected);
|
// this.fileManagerService.onContactSelected.next(selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectedChange(contactId)
|
||||||
|
{
|
||||||
|
this.contactsService.toggleSelectedContact(contactId);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleStar(contactId)
|
||||||
|
{
|
||||||
|
if ( this.user.starred.includes(contactId) )
|
||||||
|
{
|
||||||
|
this.user.starred.splice(this.user.starred.indexOf(contactId), 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.user.starred.push(contactId);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.contactsService.updateUserData(this.user);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeContact(contactId)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
35
src/app/main/content/apps/contacts/contact.model.ts
Normal file
35
src/app/main/content/apps/contacts/contact.model.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
export class Contact
|
||||||
|
{
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
lastName: string;
|
||||||
|
avatar: string;
|
||||||
|
nickname: string;
|
||||||
|
company: string;
|
||||||
|
jobTitle: string;
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
|
address: string;
|
||||||
|
birthday: string;
|
||||||
|
notes: string;
|
||||||
|
|
||||||
|
constructor(contact)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
|
||||||
|
this.id = contact.id;
|
||||||
|
this.name = contact.name;
|
||||||
|
this.lastName = contact.lastName;
|
||||||
|
this.avatar = contact.avatar;
|
||||||
|
this.nickname = contact.nickname;
|
||||||
|
this.company = contact.company;
|
||||||
|
this.jobTitle = contact.jobTitle;
|
||||||
|
this.email = contact.email;
|
||||||
|
this.phone = contact.phone;
|
||||||
|
this.address = contact.address;
|
||||||
|
this.birthday = contact.birhday;
|
||||||
|
this.notes = contact.notes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
<div id="contacts" class="page-layout simple left-sidenav inner-sidenav" fxfxLayout="column">
|
<div id="contacts" class="page-layout simple left-sidenav inner-sidenav" fxLayout="column">
|
||||||
|
|
||||||
<!-- HEADER -->
|
<!-- HEADER -->
|
||||||
<div class="header md-accent-bg p-24" fxfxLayout="row" fxLayoutAlign="space-between center">
|
<div class="header md-accent-bg p-24" fxLayout="row" fxLayoutAlign="space-between center">
|
||||||
|
|
||||||
<!-- APP TITLE -->
|
<!-- APP TITLE -->
|
||||||
<div fxLayout="row" fxLayoutAlign="start center">
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
<md-icon>search</md-icon>
|
<md-icon>search</md-icon>
|
||||||
</label>
|
</label>
|
||||||
<md-input-container md-no-float class="m-0" floatPlaceholder="never">
|
<md-input-container md-no-float class="m-0" floatPlaceholder="never">
|
||||||
<input mdInput id="search" placeholder="Search for anyone">
|
<input mdInput [formControl]="searchInput" id="search" placeholder="Search for anything">
|
||||||
</md-input-container>
|
</md-input-container>
|
||||||
</div>
|
</div>
|
||||||
<!-- / SEARCH -->
|
<!-- / SEARCH -->
|
||||||
|
@ -34,15 +34,17 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- / HEADER -->
|
<!-- / HEADER -->
|
||||||
|
|
||||||
|
<!-- SELECTED BAR -->
|
||||||
|
<fuse-selected-bar class="md-accent-600-bg" *ngIf="hasSelectedContacts" [@slideInTop]></fuse-selected-bar>
|
||||||
|
<!-- / SELECTED BAR -->
|
||||||
|
|
||||||
<md-sidenav-container>
|
<md-sidenav-container>
|
||||||
|
|
||||||
<!-- SIDENAV -->
|
<!-- SIDENAV -->
|
||||||
<md-sidenav class="sidenav mat-sidenav-opened" align="start" opened="true" mode="side"
|
<md-sidenav class="sidenav mat-sidenav-opened" align="start" opened="true" mode="side"
|
||||||
fuseMdSidenavHelper="contacts-main-sidenav" md-is-locked-open="gt-md">
|
fuseMdSidenavHelper="contacts-main-sidenav" md-is-locked-open="gt-md">
|
||||||
|
|
||||||
<div class="sidenav-content" perfect-scrollbar>
|
|
||||||
<fuse-contacts-main-sidenav></fuse-contacts-main-sidenav>
|
<fuse-contacts-main-sidenav></fuse-contacts-main-sidenav>
|
||||||
</div>
|
|
||||||
|
|
||||||
</md-sidenav>
|
</md-sidenav>
|
||||||
<!-- / SIDENAV -->
|
<!-- / SIDENAV -->
|
||||||
|
@ -51,7 +53,7 @@
|
||||||
<div class="center p-24" perfect-scrollbar>
|
<div class="center p-24" perfect-scrollbar>
|
||||||
|
|
||||||
<!-- CONTENT -->
|
<!-- CONTENT -->
|
||||||
<div class="content p-24 md-white-bg mat-elevation-z4">
|
<div class="content md-white-bg mat-elevation-z4">
|
||||||
|
|
||||||
<fuse-contacts-contact-list></fuse-contacts-contact-list>
|
<fuse-contacts-contact-list></fuse-contacts-contact-list>
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
@import "src/app/core/scss/fuse";
|
@import "src/app/core/scss/fuse";
|
||||||
|
|
||||||
|
#contacts {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,26 +1,38 @@
|
||||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||||
import { ContactsService } from './contacts.service';
|
import { ContactsService } from './contacts.service';
|
||||||
|
import { Animations } from '../../../../core/animations';
|
||||||
|
import { FormControl } from '@angular/forms';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-contacts',
|
selector : 'fuse-contacts',
|
||||||
templateUrl : './contacts.component.html',
|
templateUrl : './contacts.component.html',
|
||||||
styleUrls : ['./contacts.component.scss'],
|
styleUrls : ['./contacts.component.scss'],
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None,
|
||||||
|
animations : [Animations.slideInTop]
|
||||||
})
|
})
|
||||||
export class ContactsComponent implements OnInit
|
export class ContactsComponent implements OnInit
|
||||||
{
|
{
|
||||||
|
hasSelectedContacts: boolean;
|
||||||
selected: any;
|
searchInput: FormControl;
|
||||||
|
|
||||||
constructor(private contactsService: ContactsService)
|
constructor(private contactsService: ContactsService)
|
||||||
{
|
{
|
||||||
|
this.searchInput = new FormControl('');
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit()
|
ngOnInit()
|
||||||
{
|
{
|
||||||
this.contactsService.onContactSelected.subscribe(selected => {
|
|
||||||
this.selected = selected;
|
this.contactsService.onSelectedContactsChanged
|
||||||
|
.subscribe(selectedContacts => {
|
||||||
|
this.hasSelectedContacts = selectedContacts.length > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.searchInput.valueChanges
|
||||||
|
.debounceTime(300)
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.subscribe(searchText => {
|
||||||
|
this.contactsService.onSearchTextChanged.next(searchText);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { MainSidenavComponent } from './sidenavs/main/main.component';
|
||||||
import { ContactsComponent } from './contacts.component';
|
import { ContactsComponent } from './contacts.component';
|
||||||
import { ContactsService } from './contacts.service';
|
import { ContactsService } from './contacts.service';
|
||||||
import { ContactListComponent } from './contact-list/contact-list.component';
|
import { ContactListComponent } from './contact-list/contact-list.component';
|
||||||
|
import { SelectedBarComponent } from './selected-bar/selected-bar.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
|
@ -25,6 +26,7 @@ const routes: Routes = [
|
||||||
declarations: [
|
declarations: [
|
||||||
ContactsComponent,
|
ContactsComponent,
|
||||||
ContactListComponent,
|
ContactListComponent,
|
||||||
|
SelectedBarComponent,
|
||||||
MainSidenavComponent
|
MainSidenavComponent
|
||||||
],
|
],
|
||||||
providers : [
|
providers : [
|
||||||
|
|
|
@ -3,12 +3,24 @@ import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/r
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Http } from '@angular/http';
|
import { Http } from '@angular/http';
|
||||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||||
|
import { Contact } from './contact.model';
|
||||||
|
import { FuseUtils } from '../../../../core/fuseUtils';
|
||||||
|
import { Subject } from 'rxjs/Subject';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ContactsService implements Resolve<any>
|
export class ContactsService implements Resolve<any>
|
||||||
{
|
{
|
||||||
onContactsChanged: BehaviorSubject<any> = new BehaviorSubject({});
|
onContactsChanged: BehaviorSubject<any> = new BehaviorSubject({});
|
||||||
onContactSelected: BehaviorSubject<any> = new BehaviorSubject({});
|
|
||||||
|
onSelectedContactsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
|
||||||
|
|
||||||
|
onUserDataChanged: BehaviorSubject<any> = new BehaviorSubject([]);
|
||||||
|
|
||||||
|
onSearchTextChanged: Subject<any> = new Subject();
|
||||||
|
|
||||||
|
contacts: Contact[];
|
||||||
|
user: any;
|
||||||
|
selectedContacts: string[] = [];
|
||||||
|
|
||||||
constructor(private http: Http)
|
constructor(private http: Http)
|
||||||
{
|
{
|
||||||
|
@ -26,26 +38,159 @@ export class ContactsService implements Resolve<any>
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
Promise.all([
|
Promise.all([
|
||||||
this.getContacts()
|
this.getContacts(),
|
||||||
|
this.getUserData()
|
||||||
]).then(
|
]).then(
|
||||||
([files]) => {
|
([files]) => {
|
||||||
|
|
||||||
|
this.onSearchTextChanged.subscribe(searchText => {
|
||||||
|
this.getContacts(searchText);
|
||||||
|
});
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
|
|
||||||
},
|
},
|
||||||
reject
|
reject
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getContacts(): Promise<any>
|
getContacts(searchText?): Promise<any>
|
||||||
{
|
{
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.http.get('api/contacts-contacts')
|
this.http.get('api/contacts-contacts')
|
||||||
.subscribe(response => {
|
.subscribe(response => {
|
||||||
this.onContactsChanged.next(response.json().data);
|
|
||||||
this.onContactSelected.next(response.json().data[0]);
|
this.contacts = response.json().data;
|
||||||
resolve(response.json().data);
|
|
||||||
|
if ( searchText && searchText !== '' )
|
||||||
|
{
|
||||||
|
this.contacts = FuseUtils.filterArrayByString(this.contacts, searchText);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.contacts = this.contacts.map(contact => {
|
||||||
|
return new Contact(contact);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.onContactsChanged.next(this.contacts);
|
||||||
|
resolve(this.contacts);
|
||||||
}, reject);
|
}, reject);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserData(): Promise<any>
|
||||||
|
{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.http.get('api/contacts-user/5725a6802d10e277a0f35724')
|
||||||
|
.subscribe(response => {
|
||||||
|
this.user = response.json().data;
|
||||||
|
this.onUserDataChanged.next(this.user);
|
||||||
|
resolve(this.user);
|
||||||
|
}, reject);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle selected contact by id
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
toggleSelectedContact(id)
|
||||||
|
{
|
||||||
|
// First, check if we already have that todo as selected...
|
||||||
|
if ( this.selectedContacts.length > 0 )
|
||||||
|
{
|
||||||
|
const index = this.selectedContacts.indexOf(id);
|
||||||
|
|
||||||
|
if ( index !== -1 )
|
||||||
|
{
|
||||||
|
this.selectedContacts.splice(index, 1);
|
||||||
|
|
||||||
|
// Trigger the next event
|
||||||
|
this.onSelectedContactsChanged.next(this.selectedContacts);
|
||||||
|
|
||||||
|
// Return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we don't have it, push as selected
|
||||||
|
this.selectedContacts.push(id);
|
||||||
|
|
||||||
|
// Trigger the next event
|
||||||
|
this.onSelectedContactsChanged.next(this.selectedContacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle select all
|
||||||
|
*/
|
||||||
|
toggleSelectAll()
|
||||||
|
{
|
||||||
|
console.info(this.selectedContacts);
|
||||||
|
if ( this.selectedContacts.length > 0 )
|
||||||
|
{
|
||||||
|
this.deselectContacts();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.selectContacts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectContacts(filterParameter?, filterValue?)
|
||||||
|
{
|
||||||
|
this.selectedContacts = [];
|
||||||
|
|
||||||
|
// If there is no filter, select all todos
|
||||||
|
if ( filterParameter === undefined || filterValue === undefined )
|
||||||
|
{
|
||||||
|
this.selectedContacts = [];
|
||||||
|
this.contacts.map(contact => {
|
||||||
|
this.selectedContacts.push(contact.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* this.selectedContacts.push(...
|
||||||
|
this.contacts.filter(todo => {
|
||||||
|
return todo[filterParameter] === filterValue;
|
||||||
|
})
|
||||||
|
);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger the next event
|
||||||
|
this.onSelectedContactsChanged.next(this.selectedContacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateContact(contact)
|
||||||
|
{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
this.http.post('api/contacts-contacts/' + contact.id, {...contact})
|
||||||
|
.subscribe(response => {
|
||||||
|
resolve(response);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateUserData(userData)
|
||||||
|
{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.http.post('api/contacts-user/' + this.user.id, {...userData})
|
||||||
|
.subscribe(response => {
|
||||||
|
this.getUserData();
|
||||||
|
resolve(response);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deselectContacts()
|
||||||
|
{
|
||||||
|
this.selectedContacts = [];
|
||||||
|
|
||||||
|
// Trigger the next event
|
||||||
|
this.onSelectedContactsChanged.next(this.selectedContacts);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
<div fxFlex fxLayout="row" fxLayoutAlign="start center" class="p-24">
|
||||||
|
|
||||||
|
<div class="close-button-wrapper" fxFlex="220px" (click)="deselectAll()">
|
||||||
|
<button class="p-8" md-button fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<md-icon class="mr-8">arrow_back</md-icon>
|
||||||
|
<span class="text-uppercase">Back</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span class="selected-contacts-count">
|
||||||
|
<span>{{selectedContacts.length}}</span>
|
||||||
|
<span>selected</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<button md-icon-button [mdMenuTriggerFor]="selectMenu">
|
||||||
|
<md-icon>arrow_drop_down</md-icon>
|
||||||
|
</button>
|
||||||
|
<md-menu #selectMenu="mdMenu">
|
||||||
|
<button md-menu-item (click)="selectAll()">Select all</button>
|
||||||
|
<button md-menu-item (click)="deselectAll()">Deselect all</button>
|
||||||
|
</md-menu>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="multi-select-actions">
|
||||||
|
<button md-icon-button (click)="deleteSelectedContacts($event)"
|
||||||
|
aria-label="delete selected">
|
||||||
|
<md-icon>delete</md-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
|
@ -0,0 +1,11 @@
|
||||||
|
@import "src/app/core/scss/fuse";
|
||||||
|
|
||||||
|
:host {
|
||||||
|
flex: 1;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 120px;
|
||||||
|
z-index: 99;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ContactsService } from '../contacts.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector : 'fuse-selected-bar',
|
||||||
|
templateUrl: './selected-bar.component.html',
|
||||||
|
styleUrls : ['./selected-bar.component.scss']
|
||||||
|
})
|
||||||
|
export class SelectedBarComponent implements OnInit
|
||||||
|
{
|
||||||
|
selectedContacts: string[];
|
||||||
|
hasSelectedContacts: boolean;
|
||||||
|
isIndeterminate: boolean;
|
||||||
|
|
||||||
|
constructor(private contactsService: ContactsService)
|
||||||
|
{
|
||||||
|
this.contactsService.onSelectedContactsChanged
|
||||||
|
.subscribe(selectedContacts => {
|
||||||
|
this.selectedContacts = selectedContacts;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.hasSelectedContacts = selectedContacts.length > 0;
|
||||||
|
this.isIndeterminate = (selectedContacts.length !== this.contactsService.contacts.length && selectedContacts.length > 0);
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
selectAll()
|
||||||
|
{
|
||||||
|
this.contactsService.selectContacts();
|
||||||
|
}
|
||||||
|
|
||||||
|
deselectAll()
|
||||||
|
{
|
||||||
|
this.contactsService.deselectContacts();
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteSelectedContacts()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,54 +1,42 @@
|
||||||
<!-- SIDENAV HEADER -->
|
<div class="sidenav-content p-24 pr-4">
|
||||||
<div class="header p-24" fxLayout="column" fxLayoutAlign="space-between">
|
|
||||||
|
<div class="card md-white-bg mat-elevation-z4">
|
||||||
|
<!-- SIDENAV HEADER -->
|
||||||
|
<div class="header p-24" fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
|
||||||
|
<!-- USER -->
|
||||||
|
<img [src]="user.avatar" class="avatar mr-16" [alt]="user.name"/>
|
||||||
|
<span class="h5">{{user.name}}</span>
|
||||||
|
<!-- / USER -->
|
||||||
|
|
||||||
<div class="logo" fxLayout="row" fxLayoutAlign="start center">
|
|
||||||
<md-icon class="logo-icon mr-16">folder</md-icon>
|
|
||||||
<span class="logo-text h1">File Manager</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
<!-- / SIDENAV HEADER -->
|
||||||
|
|
||||||
</div>
|
<!-- SIDENAV CONTENT -->
|
||||||
<!-- / SIDENAV HEADER -->
|
<div class="content py-16" perfect-scrollbar>
|
||||||
|
|
||||||
<!-- SIDENAV CONTENT -->
|
|
||||||
<div class="content py-16" perfect-scrollbar>
|
|
||||||
|
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
|
|
||||||
<div class="nav-item" aria-label="inbox">
|
<div class="nav-item" aria-label="inbox">
|
||||||
<a class="nav-link" md-ripple>
|
<a class="nav-link" md-ripple>
|
||||||
<md-icon class="nav-link-icon">folder</md-icon>
|
<span class="title">All Contacts</span>
|
||||||
<span class="title">My Files</span>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-item" aria-label="starred">
|
<div class="nav-item" aria-label="starred">
|
||||||
<a class="nav-link" md-ripple>
|
<a class="nav-link" md-ripple>
|
||||||
<md-icon class="nav-link-icon">star</md-icon>
|
<div class="title">Freequently contacted</div>
|
||||||
<div class="title">Starred</div>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-item" aria-label="starred">
|
<div class="nav-item" aria-label="starred">
|
||||||
<a class="nav-link" md-ripple>
|
<a class="nav-link" md-ripple>
|
||||||
<md-icon class="nav-link-icon">folder_shared</md-icon>
|
<div class="title">Starred Contacts</div>
|
||||||
<div class="title">Sharred with me</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="nav-item" aria-label="starred">
|
|
||||||
<a class="nav-link" md-ripple>
|
|
||||||
<md-icon class="nav-link-icon">access_time</md-icon>
|
|
||||||
<div class="title">Recent</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="nav-item" aria-label="starred">
|
|
||||||
<a class="nav-link" md-ripple>
|
|
||||||
<md-icon class="nav-link-icon">not_interested</md-icon>
|
|
||||||
<div class="title">Offline</div>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- / SIDENAV CONTENT -->
|
<!-- / SIDENAV CONTENT -->
|
||||||
|
|
|
@ -4,8 +4,23 @@
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
.sidenav-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
|
||||||
> .header {
|
> .header {
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .content {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ContactsService } from '../../contacts.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-contacts-main-sidenav',
|
selector : 'fuse-contacts-main-sidenav',
|
||||||
|
@ -7,11 +8,13 @@ import { Component, OnInit } from '@angular/core';
|
||||||
})
|
})
|
||||||
export class MainSidenavComponent implements OnInit
|
export class MainSidenavComponent implements OnInit
|
||||||
{
|
{
|
||||||
selected: any;
|
user: any;
|
||||||
|
|
||||||
constructor()
|
constructor(private contactsService: ContactsService)
|
||||||
{
|
{
|
||||||
|
this.contactsService.onUserDataChanged.subscribe(user => {
|
||||||
|
this.user = user;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit()
|
ngOnInit()
|
||||||
|
|
|
@ -18,6 +18,7 @@ fuse-main {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
#wrapper {
|
#wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user