Improving the codebase (wip)

This commit is contained in:
Sercan Yemen 2018-05-21 15:42:34 +03:00
parent 0039f44936
commit 742da904da
124 changed files with 3174 additions and 1491 deletions

View File

@ -3,6 +3,7 @@ import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule, Routes } from '@angular/router';
import { MatMomentDateModule } from '@angular/material-moment-adapter';
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { TranslateModule } from '@ngx-translate/core';
import 'hammerjs';
@ -64,6 +65,9 @@ const appRoutes: Routes = [
passThruUnknownUrl: true
}),
// Material moment date module
MatMomentDateModule,
// Fuse modules
FuseModule.forRoot(fuseConfig),
FuseSharedModule,

View File

@ -6,7 +6,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
@Injectable()
export class AcademyCourseService implements Resolve<any>
{
onCourseChanged: BehaviorSubject<any> = new BehaviorSubject({});
onCourseChanged: BehaviorSubject<any>;
/**
* Constructor
@ -17,6 +17,8 @@ export class AcademyCourseService implements Resolve<any>
private _httpClient: HttpClient
)
{
// Set the defaults
this.onCourseChanged = new BehaviorSubject({});
}
// -----------------------------------------------------------------------------------------------------

View File

@ -6,8 +6,8 @@ import { BehaviorSubject, Observable } from 'rxjs';
@Injectable()
export class AcademyCoursesService implements Resolve<any>
{
onCategoriesChanged: BehaviorSubject<any> = new BehaviorSubject({});
onCoursesChanged: BehaviorSubject<any> = new BehaviorSubject({});
onCategoriesChanged: BehaviorSubject<any>;
onCoursesChanged: BehaviorSubject<any>;
/**
* Constructor
@ -18,6 +18,9 @@ export class AcademyCoursesService implements Resolve<any>
private _httpClient: HttpClient
)
{
// Set the defaults
this.onCategoriesChanged = new BehaviorSubject({});
this.onCoursesChanged = new BehaviorSubject({});
}
// -----------------------------------------------------------------------------------------------------

View File

@ -14,7 +14,7 @@ const routes = [
},
{
path : 'mail',
loadChildren: './mail/mail.module#FuseMailModule'
loadChildren: './mail/mail.module#MailModule'
},
{
path : 'mail-ngrx',

View File

@ -1,6 +1,6 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { MatButtonModule, MatDatepickerModule, MatFormFieldModule, MatIconModule, MatInputModule, MatSlideToggleModule, MatToolbarModule } from '@angular/material';
import { MatButtonModule, MatDatepickerModule, MatDialogModule, MatFormFieldModule, MatIconModule, MatInputModule, MatSlideToggleModule, MatToolbarModule } from '@angular/material';
import { ColorPickerModule } from 'ngx-color-picker';
import { CalendarModule as AngularCalendarModule } from 'angular-calendar';
@ -32,6 +32,7 @@ const routes: Routes = [
MatButtonModule,
MatDatepickerModule,
MatDialogModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,

View File

@ -7,7 +7,7 @@ import { Observable, Subject } from 'rxjs';
export class CalendarService implements Resolve<any>
{
events: any;
onEventsUpdated = new Subject<any>();
onEventsUpdated: Subject<any>;
/**
* Constructor
@ -18,7 +18,8 @@ export class CalendarService implements Resolve<any>
private _httpClient: HttpClient
)
{
// Set the defaults
this.onEventsUpdated = new Subject();
}
// -----------------------------------------------------------------------------------------------------

View File

@ -2,7 +2,7 @@
<mat-toolbar class="mat-accent m-0">
<mat-toolbar-row fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<span class="title dialog-title">{{dialogTitle}}</span>
<button mat-icon-button (click)="dialogRef.close()" aria-label="Close dialog">
<button mat-icon-button (click)="_matDialogRef.close()" aria-label="Close dialog">
<mat-icon>close</mat-icon>
</button>
</mat-toolbar-row>
@ -117,7 +117,7 @@
<button *ngIf="action !=='edit'"
mat-raised-button
(click)="dialogRef.close(eventForm)"
(click)="_matDialogRef.close(eventForm)"
class="save-button mat-accent"
[disabled]="eventForm.invalid"
aria-label="SAVE">
@ -126,7 +126,7 @@
<button *ngIf="action ==='edit'"
mat-raised-button
(click)="dialogRef.close(['save',eventForm])"
(click)="_matDialogRef.close(['save',eventForm])"
class="save-button mat-accent"
[disabled]="eventForm.invalid"
aria-label="SAVE">
@ -135,7 +135,7 @@
<button *ngIf="action ==='edit'"
mat-icon-button
(click)="dialogRef.close(['delete',eventForm])"
(click)="_matDialogRef.close(['delete',eventForm])"
aria-label="Delete"
matTooltip="Delete">
<mat-icon>delete</mat-icon>

View File

@ -8,7 +8,7 @@ import { MatColors } from '@fuse/mat-colors';
import { CalendarEventModel } from 'app/main/apps/calendar/event.model';
@Component({
selector : 'fuse-calendar-event-form-dialog',
selector : 'calendar-event-form-dialog',
templateUrl : './event-form.component.html',
styleUrls : ['./event-form.component.scss'],
encapsulation: ViewEncapsulation.None
@ -25,12 +25,12 @@ export class CalendarEventFormDialogComponent
/**
* Constructor
*
* @param {MatDialogRef<CalendarEventFormDialogComponent>} dialogRef
* @param {MatDialogRef<CalendarEventFormDialogComponent>} _matDialogRef
* @param _data
* @param {FormBuilder} _formBuilder
*/
constructor(
public dialogRef: MatDialogRef<CalendarEventFormDialogComponent>,
private _matDialogRef: MatDialogRef<CalendarEventFormDialogComponent>,
@Inject(MAT_DIALOG_DATA) private _data: any,
private _formBuilder: FormBuilder
)

View File

@ -11,23 +11,64 @@ 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>();
onChatSelected: BehaviorSubject<any>;
onContactSelected: BehaviorSubject<any>;
onChatsUpdated: Subject<any>;
onUserUpdated: Subject<any>;
onLeftSidenavViewChanged: Subject<any>;
onRightSidenavViewChanged: Subject<any>;
constructor(private http: HttpClient)
/**
* Constructor
*
* @param {HttpClient} _httpClient
*/
constructor(
private _httpClient: HttpClient
)
{
// Set the defaults
this.onChatSelected = new BehaviorSubject(null);
this.onContactSelected = new BehaviorSubject(null);
this.onChatsUpdated = new Subject();
this.onUserUpdated = new Subject();
this.onLeftSidenavViewChanged = new Subject();
this.onRightSidenavViewChanged = new Subject();
}
/**
* 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 chat
*
* @param contactId
* @returns {Promise<any>}
*/
getChat(contactId)
getChat(contactId): Promise<any>
{
const chatItem = this.user.chatList.find((item) => {
return item.contactId === contactId;
@ -45,7 +86,7 @@ export class ChatService implements Resolve<any>
}
return new Promise((resolve, reject) => {
this.http.get('api/chat-chats/' + chatItem.id)
this._httpClient.get('api/chat-chats/' + chatItem.id)
.subscribe((response: any) => {
const chat = response;
@ -68,11 +109,12 @@ export class ChatService implements Resolve<any>
}
/**
* Create New Chat
* Create new chat
*
* @param contactId
* @returns {Promise<any>}
*/
createNewChat(contactId)
createNewChat(contactId): Promise<any>
{
return new Promise((resolve, reject) => {
@ -103,13 +145,13 @@ export class ChatService implements Resolve<any>
/**
* Post the created chat
*/
this.http.post('api/chat-chats', {...chat})
this._httpClient.post('api/chat-chats', {...chat})
.subscribe((response: any) => {
/**
* Post the new the user data
*/
this.http.post('api/chat-user/' + this.user.id, this.user)
this._httpClient.post('api/chat-user/' + this.user.id, this.user)
.subscribe(newUserData => {
/**
@ -125,30 +167,33 @@ export class ChatService implements Resolve<any>
}
/**
* Select Contact
* Select contact
*
* @param contact
*/
selectContact(contact)
selectContact(contact): void
{
this.onContactSelected.next(contact);
}
/**
* Set user status
*
* @param status
*/
setUserStatus(status)
setUserStatus(status): void
{
this.user.status = status;
}
/**
* Update user data
*
* @param userData
*/
updateUserData(userData)
updateUserData(userData): void
{
this.http.post('api/chat-user/' + this.user.id, userData)
this._httpClient.post('api/chat-user/' + this.user.id, userData)
.subscribe((response: any) => {
this.user = userData;
}
@ -157,6 +202,7 @@ export class ChatService implements Resolve<any>
/**
* Update the chat dialog
*
* @param chatId
* @param dialog
* @returns {Promise<any>}
@ -170,7 +216,7 @@ export class ChatService implements Resolve<any>
dialog: dialog
};
this.http.post('api/chat-chats/' + chatId, newData)
this._httpClient.post('api/chat-chats/' + chatId, newData)
.subscribe(updatedChat => {
resolve(updatedChat);
}, reject);
@ -178,38 +224,14 @@ export class ChatService implements Resolve<any>
}
/**
* The Chat 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
* Get contacts
*
* @returns {Promise<any>}
*/
getContacts(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/chat-contacts')
this._httpClient.get('api/chat-contacts')
.subscribe((response: any) => {
resolve(response);
}, reject);
@ -217,13 +239,14 @@ export class ChatService implements Resolve<any>
}
/**
* Get Chats
* Get chats
*
* @returns {Promise<any>}
*/
getChats(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/chat-chats')
this._httpClient.get('api/chat-chats')
.subscribe((response: any) => {
resolve(response);
}, reject);
@ -231,13 +254,14 @@ export class ChatService implements Resolve<any>
}
/**
* Get User
* Get user
*
* @returns {Promise<any>}
*/
getUser(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/chat-user')
this._httpClient.get('api/chat-user')
.subscribe((response: any) => {
resolve(response[0]);
}, reject);

View File

@ -2,7 +2,7 @@
<mat-toolbar matDialogTitle class="mat-accent m-0">
<mat-toolbar-row fxLayout="row" fxLayoutAlign="space-between center">
<span class="title dialog-title">{{dialogTitle}}</span>
<button mat-icon-button (click)="dialogRef.close()" aria-label="Close dialog">
<button mat-icon-button (click)="_matDialogRef.close()" aria-label="Close dialog">
<mat-icon>close</mat-icon>
</button>
</mat-toolbar-row>
@ -98,7 +98,7 @@
<button *ngIf="action !=='edit'"
mat-raised-button
(click)="dialogRef.close(contactForm)"
(click)="_matDialogRef.close(contactForm)"
class="save-button mat-accent"
[disabled]="contactForm.invalid"
aria-label="SAVE">
@ -107,7 +107,7 @@
<button *ngIf="action ==='edit'"
mat-raised-button
(click)="dialogRef.close(['save',contactForm])"
(click)="_matDialogRef.close(['save',contactForm])"
class="save-button mat-accent"
[disabled]="contactForm.invalid"
aria-label="SAVE">
@ -116,7 +116,7 @@
<button *ngIf="action ==='edit'"
mat-icon-button
(click)="dialogRef.close(['delete',contactForm])"
(click)="_matDialogRef.close(['delete',contactForm])"
aria-label="Delete"
matTooltip="Delete">
<mat-icon>delete</mat-icon>

View File

@ -21,16 +21,17 @@ export class ContactsContactFormDialogComponent
/**
* Constructor
*
* @param {MatDialogRef<ContactsContactFormDialogComponent>} _dialogRef
* @param {MatDialogRef<ContactsContactFormDialogComponent>} _matDialogRef
* @param _data
* @param {FormBuilder} _formBuilder
*/
constructor(
private _dialogRef: MatDialogRef<ContactsContactFormDialogComponent>,
private _matDialogRef: MatDialogRef<ContactsContactFormDialogComponent>,
@Inject(MAT_DIALOG_DATA) private _data: any,
private _formBuilder: FormBuilder
)
{
// Set the defaults
this.action = _data.action;
if ( this.action === 'edit' )

View File

@ -33,7 +33,7 @@ export class ContactsComponent implements OnInit, OnDestroy
*/
constructor(
private _contactsService: ContactsService,
public _matDialog: MatDialog
private _matDialog: MatDialog
)
{
// Set the defaults

View File

@ -10,11 +10,11 @@ import { Contact } from 'app/main/apps/contacts/contact.model';
@Injectable()
export class ContactsService implements Resolve<any>
{
onContactsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onSelectedContactsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onUserDataChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onSearchTextChanged: Subject<any> = new Subject();
onFilterChanged: Subject<any> = new Subject();
onContactsChanged: BehaviorSubject<any>;
onSelectedContactsChanged: BehaviorSubject<any>;
onUserDataChanged: BehaviorSubject<any>;
onSearchTextChanged: Subject<any>;
onFilterChanged: Subject<any>;
contacts: Contact[];
user: any;
@ -32,6 +32,12 @@ export class ContactsService implements Resolve<any>
private _httpClient: HttpClient
)
{
// Set the defaults
this.onContactsChanged = new BehaviorSubject([]);
this.onSelectedContactsChanged = new BehaviorSubject([]);
this.onUserDataChanged = new BehaviorSubject([]);
this.onSearchTextChanged = new Subject();
this.onFilterChanged = new Subject();
}
// -----------------------------------------------------------------------------------------------------

View File

@ -10,7 +10,7 @@ import { Order } from 'app/main/apps/e-commerce/order/order.model';
import { EcommerceOrderService } from 'app/main/apps/e-commerce/order/order.service';
@Component({
selector : 'fuse-e-commerce-order',
selector : 'e-commerce-order',
templateUrl : './order.component.html',
styleUrls : ['./order.component.scss'],
encapsulation: ViewEncapsulation.None,

View File

@ -8,7 +8,7 @@ export class EcommerceOrderService implements Resolve<any>
{
routeParams: any;
order: any;
onOrderChanged: BehaviorSubject<any> = new BehaviorSubject({});
onOrderChanged: BehaviorSubject<any>;
/**
* Constructor
@ -19,6 +19,8 @@ export class EcommerceOrderService implements Resolve<any>
private _httpClient: HttpClient
)
{
// Set the defaults
this.onOrderChanged = new BehaviorSubject({});
}
/**

View File

@ -7,7 +7,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
export class EcommerceOrdersService implements Resolve<any>
{
orders: any[];
onOrdersChanged: BehaviorSubject<any> = new BehaviorSubject({});
onOrdersChanged: BehaviorSubject<any>;
/**
* Constructor
@ -18,6 +18,8 @@ export class EcommerceOrdersService implements Resolve<any>
private _httpClient: HttpClient
)
{
// Set the defaults
this.onOrdersChanged = new BehaviorSubject({});
}
/**

View File

@ -8,7 +8,7 @@ export class EcommerceProductService implements Resolve<any>
{
routeParams: any;
product: any;
onProductChanged: BehaviorSubject<any> = new BehaviorSubject({});
onProductChanged: BehaviorSubject<any>;
/**
* Constructor
@ -19,6 +19,8 @@ export class EcommerceProductService implements Resolve<any>
private _httpClient: HttpClient
)
{
// Set the defaults
this.onProductChanged = new BehaviorSubject({});
}
/**

View File

@ -7,7 +7,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
export class EcommerceProductsService implements Resolve<any>
{
products: any[];
onProductsChanged: BehaviorSubject<any> = new BehaviorSubject({});
onProductsChanged: BehaviorSubject<any>;
/**
* Constructor
@ -18,6 +18,8 @@ export class EcommerceProductsService implements Resolve<any>
private _httpClient: HttpClient
)
{
// Set the defaults
this.onProductsChanged = new BehaviorSubject({});
}
/**

View File

@ -6,8 +6,8 @@ import { Observable, BehaviorSubject } from 'rxjs';
@Injectable()
export class FileManagerService implements Resolve<any>
{
onFilesChanged: BehaviorSubject<any> = new BehaviorSubject({});
onFileSelected: BehaviorSubject<any> = new BehaviorSubject({});
onFilesChanged: BehaviorSubject<any>;
onFileSelected: BehaviorSubject<any>;
/**
* Constructor
@ -18,6 +18,9 @@ export class FileManagerService implements Resolve<any>
private _httpClient: HttpClient
)
{
// Set the defaults
this.onFilesChanged = new BehaviorSubject({});
this.onFileSelected = new BehaviorSubject({});
}
/**

View File

@ -2,7 +2,7 @@
<mat-toolbar class="mat-accent m-0">
<mat-toolbar-row fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<span class="title dialog-title">New Message</span>
<button mat-icon-button (click)="dialogRef.close()" aria-label="Close dialog">
<button mat-icon-button (click)="_matDialogRef.close()" aria-label="Close dialog">
<mat-icon>close</mat-icon>
</button>
</mat-toolbar-row>
@ -86,7 +86,7 @@
<div mat-dialog-actions class="m-0 p-16" fxLayout="row" fxLayoutAlign="space-between center">
<div>
<button mat-raised-button
(click)="dialogRef.close(['send',composeForm])"
(click)="_matDialogRef.close(['send',composeForm])"
class="save-button mat-accent"
[disabled]="composeForm.invalid"
aria-label="SAVE">
@ -98,7 +98,7 @@
</button>
</div>
<button mat-icon-button (click)="dialogRef.close(['delete',composeForm])" aria-label="Delete"
<button mat-icon-button (click)="_matDialogRef.close(['delete',composeForm])" aria-label="Delete"
matTooltip="Delete">
<mat-icon>delete</mat-icon>
</button>

View File

@ -3,27 +3,44 @@ import { FormBuilder, FormGroup } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
@Component({
selector : 'fuse-mail-compose',
selector : 'mail-compose',
templateUrl : './compose.component.html',
styleUrls : ['./compose.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseMailNgrxComposeDialogComponent
export class MailNgrxComposeDialogComponent
{
composeForm: FormGroup;
/**
* Constructor
*
* @param {MatDialogRef<MailNgrxComposeDialogComponent>} _matDialogRef
* @param _data
* @param {FormBuilder} _formBuilder
*/
constructor(
public dialogRef: MatDialogRef<FuseMailNgrxComposeDialogComponent>,
@Inject(MAT_DIALOG_DATA) private data: any,
private formBuilder: FormBuilder
private _matDialogRef: MatDialogRef<MailNgrxComposeDialogComponent>,
@Inject(MAT_DIALOG_DATA) private _data: any,
private _formBuilder: FormBuilder
)
{
// Set the defaults
this.composeForm = this.createComposeForm();
}
createComposeForm()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Create compose form
*
* @returns {FormGroup}
*/
createComposeForm(): FormGroup
{
return this.formBuilder.group({
return this._formBuilder.group({
from : {
value : ['johndoe@creapond.com'],
disabled: [true]

View File

@ -2,38 +2,62 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { Mail } from '../mail.model';
import * as fromStore from '../store';
import { MailNgrxService } from '../mail.service';
import { Mail } from 'app/main/apps/mail-ngrx/mail.model';
import * as fromStore from 'app/main/apps/mail-ngrx/store';
import { MailNgrxService } from 'app/main/apps/mail-ngrx/mail.service';
@Component({
selector : 'fuse-mail-details',
selector : 'mail-details',
templateUrl : './mail-details.component.html',
styleUrls : ['./mail-details.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseMailNgrxDetailsComponent implements OnChanges
export class MailNgrxDetailsComponent implements OnChanges
{
labels$: Observable<any>;
@Input('mail') mailInput: Mail;
mail: Mail;
showDetails = false;
@Input('mail')
mailInput: Mail;
labels$: Observable<any>;
mail: Mail;
showDetails: boolean;
/**
* Constructor
*
* @param {MailNgrxService} _mailNgrxService
* @param {Store<MailAppState>} _store
*/
constructor(
private mailService: MailNgrxService,
private store: Store<fromStore.MailAppState>
private _mailNgrxService: MailNgrxService,
private _store: Store<fromStore.MailAppState>
)
{
this.labels$ = this.store.select(fromStore.getLabelsArr);
// Set the defaults
this.labels$ = this._store.select(fromStore.getLabelsArr);
this.showDetails = false;
}
ngOnChanges()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*/
ngOnChanges(): void
{
this.updateModel(this.mailInput);
this.markAsRead();
}
markAsRead()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Mark as read
*/
markAsRead(): void
{
if ( this.mail && !this.mail.read )
{
@ -42,28 +66,46 @@ export class FuseMailNgrxDetailsComponent implements OnChanges
}
}
toggleStar(event)
/**
* Toggle star
*
* @param event
*/
toggleStar(event): void
{
event.stopPropagation();
this.mail.toggleStar();
this.updateMail();
}
toggleImportant(event)
/**
* Toggle important
*
* @param event
*/
toggleImportant(event): void
{
event.stopPropagation();
this.mail.toggleImportant();
this.updateMail();
}
updateModel(data)
/**
* Update model
*
* @param data
*/
updateModel(data): void
{
this.mail = !data ? null : new Mail({...data});
}
updateMail()
/**
* Update the mail
*/
updateMail(): void
{
this.store.dispatch(new fromStore.UpdateMail(this.mail));
this._store.dispatch(new fromStore.UpdateMail(this.mail));
this.updateModel(this.mail);
}
}

View File

@ -7,12 +7,12 @@ import { Mail } from '../../mail.model';
import * as fromStore from '../../store';
@Component({
selector : 'fuse-mail-list-item',
selector : 'mail-list-item',
templateUrl : './mail-list-item.component.html',
styleUrls : ['./mail-list-item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseMailNgrxListItemComponent implements OnInit
export class MailNgrxListItemComponent implements OnInit
{
@Input() mail: Mail;
@HostBinding('class.selected') selected: boolean;

View File

@ -3,7 +3,7 @@
</div>
<div class="mail-list">
<fuse-mail-list-item matRipple *ngFor="let mail of mails" [mail]="mail" (click)="readMail(mail.id)"
<mail-list-item matRipple *ngFor="let mail of mails" [mail]="mail" (click)="readMail(mail.id)"
[ngClass]="{'current-mail':mail?.id == currentMail?.id}">
</fuse-mail-list-item>
</mail-list-item>
</div>

View File

@ -1,49 +1,64 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Mail } from '../mail.model';
import { MailNgrxService } from '../mail.service';
import { Mail } from 'app/main/apps/mail-ngrx/mail.model';
import { MailNgrxService } from 'app/main/apps/mail-ngrx/mail.service';
@Component({
selector : 'fuse-mail-list',
selector : 'mail-list',
templateUrl : './mail-list.component.html',
styleUrls : ['./mail-list.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseMailNgrxListComponent
export class MailNgrxListComponent
{
@Input() mails: Mail[];
@Input() currentMail: Mail[];
@Input()
mails: Mail[];
@Input()
currentMail: Mail[];
/**
* Constructor
*
* @param {ActivatedRoute} _activatedRoute
* @param {MailNgrxService} _mailNgrxService
* @param {Router} _router
*/
constructor(
private route: ActivatedRoute,
private mailService: MailNgrxService,
private router: Router
private _activatedRoute: ActivatedRoute,
private _mailNgrxService: MailNgrxService,
private _router: Router
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Read mail
*
* @param mailId
*/
readMail(mailId)
readMail(mailId): void
{
const labelHandle = this.route.snapshot.params.labelHandle,
filterHandle = this.route.snapshot.params.filterHandle,
folderHandle = this.route.snapshot.params.folderHandle;
const labelHandle = this._activatedRoute.snapshot.params.labelHandle,
filterHandle = this._activatedRoute.snapshot.params.filterHandle,
folderHandle = this._activatedRoute.snapshot.params.folderHandle;
if ( labelHandle )
{
this.router.navigate(['apps/mail-ngrx/label/' + labelHandle + '/' + mailId]);
this._router.navigate(['apps/mail-ngrx/label/' + labelHandle + '/' + mailId]);
}
else if ( filterHandle )
{
this.router.navigate(['apps/mail-ngrx/filter/' + filterHandle + '/' + mailId]);
this._router.navigate(['apps/mail-ngrx/filter/' + filterHandle + '/' + mailId]);
}
else
{
this.router.navigate(['apps/mail-ngrx/' + folderHandle + '/' + mailId]);
this._router.navigate(['apps/mail-ngrx/' + folderHandle + '/' + mailId]);
}
}
}

View File

@ -9,7 +9,7 @@
<!-- SIDENAV -->
<mat-sidenav class="sidenav mat-sidenav-opened" position="start" mode="side" opened="true"
fuseMatSidenavHelper="carded-left-sidenav" mat-is-locked-open="gt-md">
<fuse-mail-main-sidenav></fuse-mail-main-sidenav>
<mail-main-sidenav></mail-main-sidenav>
</mat-sidenav>
<!-- / SIDENAV -->
@ -88,7 +88,7 @@
</div>
<div *ngIf="currentMail$ | async" fxHide.gt-xs>
<button mat-icon-button (click)="deSelectCurrentMail()">
<button mat-icon-button (click)="deselectCurrentMail()">
<mat-icon>arrow_back</mat-icon>
</button>
</div>
@ -98,8 +98,8 @@
<!-- CONTENT -->
<div class="content" fxLayout="row">
<fuse-mail-list fusePerfectScrollbar fxFlex [mails]="mails$ | async" [currentMail]="currentMail$ | async"></fuse-mail-list>
<fuse-mail-details [mail]="currentMail$ | async" fusePerfectScrollbar fxFlex></fuse-mail-details>
<mail-list fusePerfectScrollbar fxFlex [mails]="mails$ | async" [currentMail]="currentMail$ | async"></mail-list>
<mail-details [mail]="currentMail$ | async" fusePerfectScrollbar fxFlex></mail-details>
</div>
<!-- / CONTENT -->

View File

@ -40,16 +40,16 @@
@include media-breakpoint(xs) {
fuse-mail-list {
mail-list {
border-right: none;
}
fuse-mail-list,
fuse-mail-details {
mail-list,
mail-details {
flex: 1 0 100%;
}
fuse-mail-details {
mail-details {
display: none !important;
}
@ -65,11 +65,11 @@
.content {
fuse-mail-list {
mail-list {
display: none !important;
}
fuse-mail-details {
mail-details {
display: flex !important;
}
}

View File

@ -10,16 +10,17 @@ import { FuseConfigService } from '@fuse/services/config.service';
import { Mail } from 'app/main/apps/mail-ngrx/mail.model';
import { MailNgrxService } from 'app/main/apps/mail-ngrx/mail.service';
import * as fromStore from 'app/main/apps/mail-ngrx/store';
import { locale as english } from 'app/main/apps/mail-ngrx/i18n/en';
import { locale as turkish } from 'app/main/apps/mail-ngrx/i18n/tr';
@Component({
selector : 'fuse-mail',
selector : 'mail-ngrx',
templateUrl : './mail.component.html',
styleUrls : ['./mail.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseMailNgrxComponent implements OnInit, OnDestroy
export class MailNgrxComponent implements OnInit, OnDestroy
{
hasSelectedMails: boolean;
isIndeterminate: boolean;
@ -33,31 +34,49 @@ export class FuseMailNgrxComponent implements OnInit, OnDestroy
mails: Mail[];
selectedMailIds: string[];
/**
* Constructor
*
* @param {FuseConfigService} _fuseConfigService
* @param {MailNgrxService} _mailNgrxService
* @param {FuseTranslationLoaderService} _fuseTranslationLoaderService
* @param {Store<MailAppState>} _store
* @param {ChangeDetectorRef} _changeDetectorRef
*/
constructor(
private configService: FuseConfigService,
private mailService: MailNgrxService,
private translationLoader: FuseTranslationLoaderService,
private store: Store<fromStore.MailAppState>,
private cd: ChangeDetectorRef
private _fuseConfigService: FuseConfigService,
private _mailNgrxService: MailNgrxService,
private _fuseTranslationLoaderService: FuseTranslationLoaderService,
private _store: Store<fromStore.MailAppState>,
private _changeDetectorRef: ChangeDetectorRef
)
{
this.searchInput = new FormControl('');
this.translationLoader.loadTranslations(english, turkish);
this.currentMail$ = this.store.select(fromStore.getCurrentMail);
this.mails$ = this.store.select(fromStore.getMailsArr);
this.folders$ = this.store.select(fromStore.getFoldersArr);
this.labels$ = this.store.select(fromStore.getLabelsArr);
this.selectedMailIds$ = this.store.select(fromStore.getSelectedMailIds);
this.searchText$ = this.store.select(fromStore.getSearchText);
this.mails = [];
this.selectedMailIds = [];
this.configService.config = {
// Configure the layout
this._fuseConfigService.config = {
routerAnimation: 'none'
};
// Set the defaults
this.searchInput = new FormControl('');
this._fuseTranslationLoaderService.loadTranslations(english, turkish);
this.currentMail$ = this._store.select(fromStore.getCurrentMail);
this.mails$ = this._store.select(fromStore.getMailsArr);
this.folders$ = this._store.select(fromStore.getFoldersArr);
this.labels$ = this._store.select(fromStore.getLabelsArr);
this.selectedMailIds$ = this._store.select(fromStore.getSelectedMailIds);
this.searchText$ = this._store.select(fromStore.getSearchText);
this.mails = [];
this.selectedMailIds = [];
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.mails$.subscribe(mails => {
this.mails = mails;
@ -79,16 +98,28 @@ export class FuseMailNgrxComponent implements OnInit, OnDestroy
debounceTime(300),
distinctUntilChanged()
).subscribe(searchText => {
this.store.dispatch(new fromStore.SetSearchText(searchText));
this._store.dispatch(new fromStore.SetSearchText(searchText));
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.cd.detach();
this._changeDetectorRef.detach();
}
toggleSelectAll(ev)
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle select all
*
* @param ev
*/
toggleSelectAll(ev): void
{
ev.preventDefault();
@ -102,41 +133,69 @@ export class FuseMailNgrxComponent implements OnInit, OnDestroy
}
}
selectAllMails()
/**
* Select all mails
*/
selectAllMails(): void
{
this.store.dispatch(new fromStore.SelectAllMails());
this._store.dispatch(new fromStore.SelectAllMails());
}
deselectAllMails()
/**
* Deselect all mails
*/
deselectAllMails(): void
{
this.store.dispatch(new fromStore.DeselectAllMails());
this._store.dispatch(new fromStore.DeselectAllMails());
}
selectMailsByParameter(parameter, value)
/**
* Select mails by parameter
*
* @param parameter
* @param value
*/
selectMailsByParameter(parameter, value): void
{
this.store.dispatch(new fromStore.SelectMailsByParameter({
this._store.dispatch(new fromStore.SelectMailsByParameter({
parameter,
value
}));
}
toggleLabelOnSelectedMails(labelId)
/**
* Toggle label on selected mails
*
* @param labelId
*/
toggleLabelOnSelectedMails(labelId): void
{
this.store.dispatch(new fromStore.AddLabelOnSelectedMails(labelId));
this._store.dispatch(new fromStore.AddLabelOnSelectedMails(labelId));
}
setFolderOnSelectedMails(folderId)
/**
* Set folder on selected mails
*
* @param folderId
*/
setFolderOnSelectedMails(folderId): void
{
this.store.dispatch(new fromStore.SetFolderOnSelectedMails(folderId));
this._store.dispatch(new fromStore.SetFolderOnSelectedMails(folderId));
}
deSelectCurrentMail()
/**
* Deselect current mail
*/
deselectCurrentMail(): void
{
this.store.dispatch(new fromStore.SetCurrentMail(''));
this._store.dispatch(new fromStore.SetCurrentMail(''));
}
refresh()
/**
* Refresh
*/
refresh(): void
{
this.cd.markForCheck();
this._changeDetectorRef.markForCheck();
}
}

View File

@ -27,6 +27,11 @@ export class Mail
labels: string[];
folder: string;
/**
* Constructor
*
* @param mail
*/
constructor(mail)
{
this.id = mail.id;
@ -44,22 +49,34 @@ export class Mail
this.folder = mail.folder;
}
toggleStar()
/**
* Toggle star
*/
toggleStar(): void
{
this.starred = !this.starred;
}
toggleImportant()
/**
* Toggle important
*/
toggleImportant(): void
{
this.important = !this.important;
}
markRead()
/**
* Mark as read
*/
markRead(): void
{
this.read = true;
}
markUnRead()
/**
* Mark as unread
*/
markUnread(): void
{
this.read = false;
}

View File

@ -5,45 +5,45 @@ import { TranslateModule } from '@ngx-translate/core';
import { FuseSharedModule } from '@fuse/shared.module';
import { MailAppStoreModule } from 'app/main/apps/mail-ngrx/store/store.module';
import * as fromGuards from 'app/main/apps/mail-ngrx/store/guards/index';
import { FuseMailNgrxComponent } from 'app/main/apps/mail-ngrx/mail.component';
import { FuseMailNgrxListComponent } from 'app/main/apps/mail-ngrx/mail-list/mail-list.component';
import { FuseMailNgrxListItemComponent } from 'app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component';
import { FuseMailNgrxDetailsComponent } from 'app/main/apps/mail-ngrx/mail-details/mail-details.component';
import { FuseMailNgrxMainSidenavComponent } from 'app/main/apps/mail-ngrx/sidenavs/main/main-sidenav.component';
import { FuseMailNgrxComposeDialogComponent } from 'app/main/apps/mail-ngrx/dialogs/compose/compose.component';
import { MailNgrxStoreModule } from 'app/main/apps/mail-ngrx/store/store.module';
import { MailNgrxComponent } from 'app/main/apps/mail-ngrx/mail.component';
import { MailNgrxListComponent } from 'app/main/apps/mail-ngrx/mail-list/mail-list.component';
import { MailNgrxListItemComponent } from 'app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component';
import { MailNgrxDetailsComponent } from 'app/main/apps/mail-ngrx/mail-details/mail-details.component';
import { MailNgrxMainSidenavComponent } from 'app/main/apps/mail-ngrx/sidenavs/main/main-sidenav.component';
import { MailNgrxComposeDialogComponent } from 'app/main/apps/mail-ngrx/dialogs/compose/compose.component';
import { MailNgrxService } from 'app/main/apps/mail-ngrx/mail.service';
const routes: Routes = [
{
path : 'label/:labelHandle',
component : FuseMailNgrxComponent,
component : MailNgrxComponent,
canActivate: [fromGuards.ResolveGuard]
},
{
path : 'label/:labelHandle/:mailId',
component : FuseMailNgrxComponent,
component : MailNgrxComponent,
canActivate: [fromGuards.ResolveGuard]
},
{
path : 'filter/:filterHandle',
component: FuseMailNgrxComponent,
component : MailNgrxComponent,
canActivate: [fromGuards.ResolveGuard]
},
{
path : 'filter/:filterHandle/:mailId',
component: FuseMailNgrxComponent,
component : MailNgrxComponent,
canActivate: [fromGuards.ResolveGuard]
},
{
path : ':folderHandle',
component: FuseMailNgrxComponent,
component : MailNgrxComponent,
canActivate: [fromGuards.ResolveGuard]
},
{
path : ':folderHandle/:mailId',
component: FuseMailNgrxComponent,
component : MailNgrxComponent,
canActivate: [fromGuards.ResolveGuard]
},
{
@ -54,12 +54,12 @@ const routes: Routes = [
@NgModule({
declarations : [
FuseMailNgrxComponent,
FuseMailNgrxListComponent,
FuseMailNgrxListItemComponent,
FuseMailNgrxDetailsComponent,
FuseMailNgrxMainSidenavComponent,
FuseMailNgrxComposeDialogComponent
MailNgrxComponent,
MailNgrxListComponent,
MailNgrxListItemComponent,
MailNgrxDetailsComponent,
MailNgrxMainSidenavComponent,
MailNgrxComposeDialogComponent
],
imports : [
RouterModule.forChild(routes),
@ -80,13 +80,13 @@ const routes: Routes = [
FuseSharedModule,
MailAppStoreModule
MailNgrxStoreModule
],
providers : [
MailNgrxService,
fromGuards.ResolveGuard
],
entryComponents: [FuseMailNgrxComposeDialogComponent]
entryComponents: [MailNgrxComposeDialogComponent]
})
export class FuseMailNgrxModule
{

View File

@ -16,72 +16,108 @@ export class MailNgrxService
selectedMails: Mail[];
mails: Mail[];
/**
* Constructor
*
* @param {HttpClient} _httpClient
* @param {Store<MailAppState>} _store
*/
constructor(
private http: HttpClient,
private store: Store<MailAppState>
private _httpClient: HttpClient,
private _store: Store<MailAppState>
)
{
this.store.select(getFoldersArr).subscribe(folders => {
this._store.select(getFoldersArr).subscribe(folders => {
this.foldersArr = folders;
});
this.store.select(getFiltersArr).subscribe(filters => {
this._store.select(getFiltersArr).subscribe(filters => {
this.filtersArr = filters;
});
this.store.select(getLabelsArr).subscribe(labels => {
this._store.select(getLabelsArr).subscribe(labels => {
this.labelsArr = labels;
});
this.store.select(getMailsArr).subscribe(mails => {
this._store.select(getMailsArr).subscribe(mails => {
this.mails = mails;
});
this.selectedMails = [];
}
/**
* Get all mails
*
* @returns {Observable<Mail[]>}
*/
getAllMails(): Observable<Mail[]>
{
return this.http.get<Mail[]>('api/mail-mails');
return this._httpClient.get<Mail[]>('api/mail-mails');
}
/**
* Get folders
*
* @returns {Observable<any>}
*/
getFolders(): Observable<any>
{
return this.http.get('api/mail-folders');
return this._httpClient.get('api/mail-folders');
}
/**
* Get filters
*
* @returns {Observable<any>}
*/
getFilters(): Observable<any>
{
return this.http.get('api/mail-filters');
return this._httpClient.get('api/mail-filters');
}
/**
* Get labels
*
* @returns {Observable<any>}
*/
getLabels(): Observable<any>
{
return this.http.get('api/mail-labels');
return this._httpClient.get('api/mail-labels');
}
/**
* Get mails
*
* @param handle
* @returns {Observable<Mail[]>}
*/
getMails(handle): Observable<Mail[]>
{
if ( handle.id === 'labelHandle' )
{
const labelId = this.labelsArr.find(label => label.handle === handle.value).id;
return this.http.get<Mail[]>('api/mail-mails?labels=' + labelId);
return this._httpClient.get<Mail[]>('api/mail-mails?labels=' + labelId);
}
else if ( handle.id === 'filterHandle' )
{
return this.http.get<Mail[]>('api/mail-mails?' + handle.value + '=true');
return this._httpClient.get<Mail[]>('api/mail-mails?' + handle.value + '=true');
}
else // folderHandle
{
const folderId = this.foldersArr.find(folder => folder.handle === handle.value).id;
return this.http.get<any>('api/mail-mails?folder=' + folderId);
return this._httpClient.get<any>('api/mail-mails?folder=' + folderId);
}
}
/**
* Update the mail
*
* @param mail
* @returns {Promise<any>}
*/
updateMail(mail)
updateMail(mail): any
{
return this.http.post('api/mail-mails/' + mail.id, {...mail});
return this._httpClient.post('api/mail-mails/' + mail.id, {...mail});
}
}

View File

@ -4,17 +4,17 @@ import { FormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { MailNgrxService } from '../../mail.service';
import * as fromStore from './../../store';
import { FuseMailNgrxComposeDialogComponent } from '../../dialogs/compose/compose.component';
import { MailNgrxService } from 'app/main/apps/mail-ngrx/mail.service';
import * as fromStore from 'app/main/apps/mail-ngrx/store';
import { MailNgrxComposeDialogComponent } from 'app/main/apps/mail-ngrx/dialogs/compose/compose.component';
@Component({
selector : 'fuse-mail-main-sidenav',
selector : 'mail-main-sidenav',
templateUrl : './main-sidenav.component.html',
styleUrls : ['./main-sidenav.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseMailNgrxMainSidenavComponent
export class MailNgrxMainSidenavComponent
{
labels: any[];
accounts: object;
@ -25,30 +25,43 @@ export class FuseMailNgrxMainSidenavComponent
filters$: Observable<any>;
labels$: Observable<any>;
/**
* Constructor
*
* @param {MailNgrxService} _mailNgrxService
* @param {MatDialog} _matDialog
* @param {Store<MailAppState>} _store
*/
constructor(
private mailService: MailNgrxService,
public dialog: MatDialog,
private store: Store<fromStore.MailAppState>
private _mailNgrxService: MailNgrxService,
private _matDialog: MatDialog,
private _store: Store<fromStore.MailAppState>
)
{
// Data
// Set the defaults
this.accounts = {
'creapond' : 'johndoe@creapond.com',
'withinpixels': 'johndoe@withinpixels.com'
};
this.selectedAccount = 'creapond';
this.folders$ = this.store.select(fromStore.getFoldersArr);
this.filters$ = this.store.select(fromStore.getFiltersArr);
this.labels$ = this.store.select(fromStore.getLabelsArr);
this.folders$ = this._store.select(fromStore.getFoldersArr);
this.filters$ = this._store.select(fromStore.getFiltersArr);
this.labels$ = this._store.select(fromStore.getLabelsArr);
}
composeDialog()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Compose dialog
*/
composeDialog(): void
{
this.dialogRef = this.dialog.open(FuseMailNgrxComposeDialogComponent, {
this.dialogRef = this._matDialog.open(MailNgrxComposeDialogComponent, {
panelClass: 'mail-compose-dialog'
});
this.dialogRef.afterClosed()
.subscribe(response => {
if ( !response )

View File

@ -16,11 +16,16 @@ export class ResolveGuard implements CanActivate
{
routerState: any;
/**
* Constructor
*
* @param {Store<MailAppState>} _store
*/
constructor(
private store: Store<MailAppState>
private _store: Store<MailAppState>
)
{
this.store.select(getRouterState).subscribe(routerState => {
this._store.select(getRouterState).subscribe(routerState => {
if ( routerState )
{
this.routerState = routerState.state;
@ -28,6 +33,13 @@ export class ResolveGuard implements CanActivate
});
}
/**
* Can activate
*
* @param {ActivatedRouteSnapshot} route
* @param {RouterStateSnapshot} state
* @returns {Observable<boolean>}
*/
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>
{
return this.checkStore().pipe(
@ -36,6 +48,11 @@ export class ResolveGuard implements CanActivate
);
}
/**
* Check store
*
* @returns {Observable<any>}
*/
checkStore(): Observable<any>
{
return forkJoin(
@ -44,24 +61,29 @@ export class ResolveGuard implements CanActivate
this.getLabels()
)
.pipe(
filter(([foldersLoaded, filtersLoaded, labelsLoaded]) => filtersLoaded && foldersLoaded && labelsLoaded),
filter(([foldersLoaded, filtersLoaded, labelsLoaded]) => !!(foldersLoaded && filtersLoaded && labelsLoaded)),
take(1),
switchMap(() =>
this.getMails()
),
take(1),
map(() => this.store.dispatch(new fromStore.SetCurrentMail(this.routerState.params.mailId)))
map(() => this._store.dispatch(new fromStore.SetCurrentMail(this.routerState.params.mailId)))
);
}
getFolders()
/**
* Get folders
*
* @returns {Observable<any>}
*/
getFolders(): any
{
return this.store.select(getFoldersLoaded)
return this._store.select(getFoldersLoaded)
.pipe(
tap(loaded => {
if ( !loaded )
{
this.store.dispatch(new fromStore.GetFolders([]));
this._store.dispatch(new fromStore.GetFolders([]));
}
}),
filter(loaded => loaded),
@ -71,16 +93,17 @@ export class ResolveGuard implements CanActivate
/**
* Get Filters
*
* @returns {Observable<any>}
*/
getFilters()
getFilters(): any
{
return this.store.select(getFiltersLoaded)
return this._store.select(getFiltersLoaded)
.pipe(
tap(loaded => {
if ( !loaded )
{
this.store.dispatch(new fromStore.GetFilters([]));
this._store.dispatch(new fromStore.GetFilters([]));
}
}),
filter(loaded => loaded),
@ -92,14 +115,14 @@ export class ResolveGuard implements CanActivate
* Get Labels
* @returns {Observable<any>}
*/
getLabels()
getLabels(): any
{
return this.store.select(getLabelsLoaded)
return this._store.select(getLabelsLoaded)
.pipe(
tap(loaded => {
if ( !loaded )
{
this.store.dispatch(new fromStore.GetLabels([]));
this._store.dispatch(new fromStore.GetLabels([]));
}
}),
filter(loaded => loaded),
@ -109,19 +132,20 @@ export class ResolveGuard implements CanActivate
/**
* Get Mails
*
* @returns {Observable<any>}
*/
getMails()
getMails(): any
{
return this.store.select(getMailsLoaded)
return this._store.select(getMailsLoaded)
.pipe(
tap((loaded: any) => {
if ( !this.routerState.params[loaded.id] || this.routerState.params[loaded.id] !== loaded.value )
{
this.store.dispatch(new fromStore.GetMails());
this.store.dispatch(new fromStore.SetSearchText(''));
this.store.dispatch(new fromStore.DeselectAllMails());
this._store.dispatch(new fromStore.GetMails());
this._store.dispatch(new fromStore.SetSearchText(''));
this._store.dispatch(new fromStore.DeselectAllMails());
}
}),
filter((loaded: any) => {

View File

@ -2,7 +2,7 @@ import * as FiltersActions from 'app/main/apps/mail-ngrx/store/actions/filters.a
export interface FiltersState
{
entities: { [id: number]: any };
entities?: { [id: number]: any };
loading: boolean;
loaded: boolean;
}

View File

@ -2,7 +2,7 @@ import * as FoldersActions from 'app/main/apps/mail-ngrx/store/actions/folders.a
export interface FoldersState
{
entities: { [id: number]: any };
entities?: { [id: number]: any };
loading: boolean;
loaded: boolean;
}

View File

@ -2,7 +2,7 @@ import * as LabelsActions from 'app/main/apps/mail-ngrx/store/actions/labels.act
export interface LabelsState
{
entities: { [id: number]: any };
entities?: { [id: number]: any };
loading: boolean;
loaded: boolean;
}

View File

@ -3,7 +3,7 @@ import { Mail } from 'app/main/apps/mail-ngrx/mail.model';
export interface MailsState
{
entities: { [id: number]: Mail };
entities?: { [id: number]: Mail };
currentMail: any;
selectedMailIds: string[];
searchText: string;

View File

@ -12,6 +12,6 @@ import { effects } from 'app/main/apps/mail-ngrx/store/effects';
],
providers: []
})
export class MailAppStoreModule
export class MailNgrxStoreModule
{
}

View File

@ -2,7 +2,7 @@
<mat-toolbar class="mat-accent m-0">
<mat-toolbar-row fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<span class="title dialog-title">New Message</span>
<button mat-icon-button (click)="dialogRef.close()" aria-label="Close dialog">
<button mat-icon-button (click)="_matDialogRef.close()" aria-label="Close dialog">
<mat-icon>close</mat-icon>
</button>
</mat-toolbar-row>
@ -91,7 +91,7 @@
<div mat-dialog-actions class="m-0 p-16" fxLayout="row" fxLayoutAlign="space-between center">
<div>
<button mat-raised-button
(click)="dialogRef.close(['send',composeForm])"
(click)="_matDialogRef.close(['send',composeForm])"
class="save-button mat-accent"
[disabled]="composeForm.invalid"
aria-label="SAVE">
@ -103,7 +103,7 @@
</button>
</div>
<button mat-icon-button (click)="dialogRef.close(['delete',composeForm])"
<button mat-icon-button (click)="_matDialogRef.close(['delete',composeForm])"
aria-label="Delete"
matTooltip="Delete">
<mat-icon>delete</mat-icon>

View File

@ -3,25 +3,42 @@ import { FormControl, FormGroup } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
@Component({
selector : 'fuse-mail-compose',
selector : 'mail-compose',
templateUrl : './compose.component.html',
styleUrls : ['./compose.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseMailComposeDialogComponent
export class MailComposeDialogComponent
{
showExtraToFields = false;
showExtraToFields: boolean;
composeForm: FormGroup;
/**
* Constructor
*
* @param {MatDialogRef<MailComposeDialogComponent>} _matDialogRef
* @param _data
*/
constructor(
public dialogRef: MatDialogRef<FuseMailComposeDialogComponent>,
@Inject(MAT_DIALOG_DATA) private data: any
private _matDialogRef: MatDialogRef<MailComposeDialogComponent>,
@Inject(MAT_DIALOG_DATA) private _data: any
)
{
// Set the defaults
this.composeForm = this.createComposeForm();
this.showExtraToFields = false;
}
createComposeForm()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Create compose form
*
* @returns {FormGroup}
*/
createComposeForm(): FormGroup
{
return new FormGroup({
from : new FormControl({
@ -36,7 +53,10 @@ export class FuseMailComposeDialogComponent
});
}
toggleExtraToFields()
/**
* Toggle extra to fields
*/
toggleExtraToFields(): void
{
this.showExtraToFields = !this.showExtraToFields;
}

View File

@ -1,70 +1,106 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations';
import { Mail } from '../mail.model';
import { MailService } from '../mail.service';
import { Mail } from 'app/main/apps/mail/mail.model';
import { MailService } from 'app/main/apps/mail/mail.service';
@Component({
selector : 'fuse-mail-details',
selector : 'mail-details',
templateUrl: './mail-details.component.html',
styleUrls : ['./mail-details.component.scss'],
animations : fuseAnimations
})
export class FuseMailDetailsComponent implements OnInit, OnDestroy
export class MailDetailsComponent implements OnInit, OnDestroy
{
mail: Mail;
labels: any[];
showDetails = false;
showDetails: boolean;
onCurrentMailChanged: Subscription;
onLabelsChanged: Subscription;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {MailService} _mailService
*/
constructor(
private mailService: MailService
private _mailService: MailService
)
{
// Set the defaults
this.showDetails = false;
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to update the current mail
this.onCurrentMailChanged =
this.mailService.onCurrentMailChanged
this._mailService.onCurrentMailChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(currentMail => {
this.mail = currentMail;
});
// Subscribe to update on label change
this.onLabelsChanged =
this.mailService.onLabelsChanged
this._mailService.onLabelsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(labels => {
this.labels = labels;
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onCurrentMailChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
toggleStar(event)
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle star
*
* @param event
*/
toggleStar(event): void
{
event.stopPropagation();
this.mail.toggleStar();
this.mailService.updateMail(this.mail);
this._mailService.updateMail(this.mail);
}
toggleImportant(event)
/**
* Toggle important
*
* @param event
*/
toggleImportant(event): void
{
event.stopPropagation();
this.mail.toggleImportant();
this.mailService.updateMail(this.mail);
this._mailService.updateMail(this.mail);
}
}

View File

@ -1,37 +1,54 @@
import { Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Mail } from '../../mail.model';
import { MailService } from '../../mail.service';
import { Mail } from 'app/main/apps/mail/mail.model';
import { MailService } from 'app/main/apps/mail/mail.service';
@Component({
selector : 'fuse-mail-list-item',
selector : 'mail-list-item',
templateUrl: './mail-list-item.component.html',
styleUrls : ['./mail-list-item.component.scss']
})
export class FuseMailListItemComponent implements OnInit, OnDestroy
export class MailListItemComponent implements OnInit, OnDestroy
{
@Input() mail: Mail;
labels: any[];
@HostBinding('class.selected') selected: boolean;
onSelectedMailsChanged: Subscription;
onLabelsChanged: Subscription;
@HostBinding('class.selected')
selected: boolean;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {MailService} _mailService
*/
constructor(
private mailService: MailService
private _mailService: MailService
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Set the initial values
this.mail = new Mail(this.mail);
// Subscribe to update on selected mail change
this.onSelectedMailsChanged =
this.mailService.onSelectedMailsChanged
this._mailService.onSelectedMailsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(selectedMails => {
this.selected = false;
@ -49,46 +66,60 @@ export class FuseMailListItemComponent implements OnInit, OnDestroy
});
// Subscribe to update on label change
this.onLabelsChanged =
this.mailService.onLabelsChanged
this._mailService.onLabelsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(labels => {
this.labels = labels;
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onSelectedMailsChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
onSelectedChange()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* On selected change
*/
onSelectedChange(): void
{
this.mailService.toggleSelectedMail(this.mail.id);
this._mailService.toggleSelectedMail(this.mail.id);
}
/**
* Toggle star
*
* @param event
*/
toggleStar(event)
toggleStar(event): void
{
event.stopPropagation();
this.mail.toggleStar();
this.mailService.updateMail(this.mail);
this._mailService.updateMail(this.mail);
}
/**
* Toggle Important
*
* @param event
*/
toggleImportant(event)
toggleImportant(event): void
{
event.stopPropagation();
this.mail.toggleImportant();
this.mailService.updateMail(this.mail);
this._mailService.updateMail(this.mail);
}
}

View File

@ -3,8 +3,8 @@
</div>
<div class="mail-list" *fuseIfOnDom [@animateStagger]="{value:'50'}">
<fuse-mail-list-item matRipple *ngFor="let mail of mails" [mail]="mail" (click)="readMail(mail.id)"
<mail-list-item matRipple *ngFor="let mail of mails" [mail]="mail" (click)="readMail(mail.id)"
[ngClass]="{'current-mail':mail?.id == currentMail?.id}"
[@animate]="{value:'*',params:{y:'100%'}}">
</fuse-mail-list-item>
</mail-list-item>
</div>

View File

@ -1,47 +1,64 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Location } from '@angular/common';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations';
import { Mail } from '../mail.model';
import { MailService } from '../mail.service';
import { Mail } from 'app/main/apps/mail/mail.model';
import { MailService } from 'app/main/apps/mail/mail.service';
@Component({
selector : 'fuse-mail-list',
selector : 'mail-list',
templateUrl: './mail-list.component.html',
styleUrls : ['./mail-list.component.scss'],
animations : fuseAnimations
})
export class FuseMailListComponent implements OnInit, OnDestroy
export class MailListComponent implements OnInit, OnDestroy
{
mails: Mail[];
currentMail: Mail;
onMailsChanged: Subscription;
onCurrentMailChanged: Subscription;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {ActivatedRoute} _activatedRoute
* @param {MailService} _mailService
* @param {Location} _location
*/
constructor(
private route: ActivatedRoute,
private mailService: MailService,
private location: Location
private _activatedRoute: ActivatedRoute,
private _mailService: MailService,
private _location: Location
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to update mails on changes
this.onMailsChanged =
this.mailService.onMailsChanged
this._mailService.onMailsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(mails => {
this.mails = mails;
});
// Subscribe to update current mail on changes
this.onCurrentMailChanged =
this.mailService.onCurrentMailChanged
this._mailService.onCurrentMailChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(currentMail => {
if ( !currentMail )
{
@ -49,21 +66,21 @@ export class FuseMailListComponent implements OnInit, OnDestroy
this.currentMail = null;
// Handle the location changes
const labelHandle = this.route.snapshot.params.labelHandle,
filterHandle = this.route.snapshot.params.filterHandle,
folderHandle = this.route.snapshot.params.folderHandle;
const labelHandle = this._activatedRoute.snapshot.params.labelHandle,
filterHandle = this._activatedRoute.snapshot.params.filterHandle,
folderHandle = this._activatedRoute.snapshot.params.folderHandle;
if ( labelHandle )
{
this.location.go('apps/mail/label/' + labelHandle);
this._location.go('apps/mail/label/' + labelHandle);
}
else if ( filterHandle )
{
this.location.go('apps/mail/filter/' + filterHandle);
this._location.go('apps/mail/filter/' + filterHandle);
}
else
{
this.location.go('apps/mail/' + folderHandle);
this._location.go('apps/mail/' + folderHandle);
}
}
else
@ -73,37 +90,45 @@ export class FuseMailListComponent implements OnInit, OnDestroy
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onMailsChanged.unsubscribe();
this.onCurrentMailChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Read mail
*
* @param mailId
*/
readMail(mailId)
readMail(mailId): void
{
const labelHandle = this.route.snapshot.params.labelHandle,
filterHandle = this.route.snapshot.params.filterHandle,
folderHandle = this.route.snapshot.params.folderHandle;
const labelHandle = this._activatedRoute.snapshot.params.labelHandle,
filterHandle = this._activatedRoute.snapshot.params.filterHandle,
folderHandle = this._activatedRoute.snapshot.params.folderHandle;
if ( labelHandle )
{
this.location.go('apps/mail/label/' + labelHandle + '/' + mailId);
this._location.go('apps/mail/label/' + labelHandle + '/' + mailId);
}
else if ( filterHandle )
{
this.location.go('apps/mail/filter/' + filterHandle + '/' + mailId);
this._location.go('apps/mail/filter/' + filterHandle + '/' + mailId);
}
else
{
this.location.go('apps/mail/' + folderHandle + '/' + mailId);
this._location.go('apps/mail/' + folderHandle + '/' + mailId);
}
// Set current mail
this.mailService.setCurrentMail(mailId);
this._mailService.setCurrentMail(mailId);
}
}

View File

@ -9,7 +9,7 @@
<!-- SIDENAV -->
<mat-sidenav class="sidenav" position="start" mode="side" opened="true"
fuseMatSidenavHelper="carded-left-sidenav" mat-is-locked-open="gt-md">
<fuse-mail-main-sidenav></fuse-mail-main-sidenav>
<mail-main-sidenav></mail-main-sidenav>
</mat-sidenav>
<!-- / SIDENAV -->
@ -86,7 +86,7 @@
</div>
<div *ngIf="currentMail" fxHide.gt-xs>
<button mat-icon-button (click)="deSelectCurrentMail()">
<button mat-icon-button (click)="deselectCurrentMail()">
<mat-icon>arrow_back</mat-icon>
</button>
</div>
@ -96,8 +96,8 @@
<!-- CONTENT -->
<div class="content" fxLayout="row">
<fuse-mail-list fusePerfectScrollbar fxFlex></fuse-mail-list>
<fuse-mail-details fusePerfectScrollbar fxFlex></fuse-mail-details>
<mail-list fusePerfectScrollbar fxFlex></mail-list>
<mail-details fusePerfectScrollbar fxFlex></mail-details>
</div>
<!-- / CONTENT -->

View File

@ -40,16 +40,16 @@
@include media-breakpoint(xs) {
fuse-mail-list {
mail-list {
border-right: none;
}
fuse-mail-list,
fuse-mail-details {
mail-list,
mail-details {
flex: 1 0 100%;
}
fuse-mail-details {
mail-details {
display: none !important;
}
@ -65,11 +65,11 @@
.content {
fuse-mail-list {
mail-list {
display: none !important;
}
fuse-mail-details {
mail-details {
display: flex !important;
}
}

View File

@ -1,22 +1,23 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { FuseTranslationLoaderService } from '@fuse/services/translation-loader.service';
import { Mail } from './mail.model';
import { MailService } from './mail.service';
import { locale as english } from './i18n/en';
import { locale as turkish } from './i18n/tr';
import { Mail } from 'app/main/apps/mail/mail.model';
import { MailService } from 'app/main/apps/mail/mail.service';
import { locale as english } from 'app/main/apps/mail//i18n/en';
import { locale as turkish } from 'app/main/apps/mail//i18n/tr';
import { FuseConfigService } from '@fuse/services/config.service';
@Component({
selector : 'fuse-mail',
selector : 'mail',
templateUrl: './mail.component.html',
styleUrls : ['./mail.component.scss']
})
export class FuseMailComponent implements OnInit, OnDestroy
export class MailComponent implements OnInit, OnDestroy
{
hasSelectedMails: boolean;
isIndeterminate: boolean;
@ -26,53 +27,75 @@ export class FuseMailComponent implements OnInit, OnDestroy
searchInput: FormControl;
currentMail: Mail;
onSelectedMailsChanged: Subscription;
onFoldersChanged: Subscription;
onFiltersChanged: Subscription;
onLabelsChanged: Subscription;
onCurrentMailChanged: Subscription;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {MailService} _mailService
* @param {FuseConfigService} _fuseConfigService
* @param {FuseTranslationLoaderService} _fuseTranslationLoaderService
*/
constructor(
private mailService: MailService,
private fuseTranslationLoader: FuseTranslationLoaderService
private _mailService: MailService,
private _fuseConfigService: FuseConfigService,
private _fuseTranslationLoaderService: FuseTranslationLoaderService
)
{
// Configure the layout
this._fuseConfigService.config = {
routerAnimation: 'none'
};
// Load the translations
this._fuseTranslationLoaderService.loadTranslations(english, turkish);
// Set the defaults
this.searchInput = new FormControl('');
this.fuseTranslationLoader.loadTranslations(english, turkish);
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
{
this.onSelectedMailsChanged =
this.mailService.onSelectedMailsChanged
.subscribe(selectedMails => {
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this._mailService.onSelectedMailsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(selectedMails => {
setTimeout(() => {
this.hasSelectedMails = selectedMails.length > 0;
this.isIndeterminate = (selectedMails.length !== this.mailService.mails.length && selectedMails.length > 0);
this.isIndeterminate = (selectedMails.length !== this._mailService.mails.length && selectedMails.length > 0);
}, 0);
});
this.onFoldersChanged =
this.mailService.onFoldersChanged
this._mailService.onFoldersChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(folders => {
this.folders = this.mailService.folders;
this.folders = this._mailService.folders;
});
this.onFiltersChanged =
this.mailService.onFiltersChanged
this._mailService.onFiltersChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(folders => {
this.filters = this.mailService.filters;
this.filters = this._mailService.filters;
});
this.onLabelsChanged =
this.mailService.onLabelsChanged
this._mailService.onLabelsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(labels => {
this.labels = this.mailService.labels;
this.labels = this._mailService.labels;
});
this.onCurrentMailChanged =
this.mailService.onCurrentMailChanged
this._mailService.onCurrentMailChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(currentMail => {
if ( !currentMail )
{
@ -85,51 +108,81 @@ export class FuseMailComponent implements OnInit, OnDestroy
});
this.searchInput.valueChanges.pipe(
takeUntil(this._unsubscribeAll),
debounceTime(300),
distinctUntilChanged()
)
.subscribe(searchText => {
this.mailService.onSearchTextChanged.next(searchText);
this._mailService.onSearchTextChanged.next(searchText);
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onSelectedMailsChanged.unsubscribe();
this.onFoldersChanged.unsubscribe();
this.onFiltersChanged.unsubscribe();
this.onLabelsChanged.unsubscribe();
this.onCurrentMailChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
toggleSelectAll()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle select all
*/
toggleSelectAll(): void
{
this.mailService.toggleSelectAll();
this._mailService.toggleSelectAll();
}
selectMails(filterParameter?, filterValue?)
/**
* Select mails
*
* @param filterParameter
* @param filterValue
*/
selectMails(filterParameter?, filterValue?): void
{
this.mailService.selectMails(filterParameter, filterValue);
this._mailService.selectMails(filterParameter, filterValue);
}
deselectMails()
/**
* Deselect mails
*/
deselectMails(): void
{
this.mailService.deselectMails();
this._mailService.deselectMails();
}
deSelectCurrentMail()
/**
* Deselect current mail
*/
deselectCurrentMail(): void
{
this.mailService.onCurrentMailChanged.next(null);
this._mailService.onCurrentMailChanged.next(null);
}
toggleLabelOnSelectedMails(labelId)
/**
* Toggle label on selected mails
*
* @param labelId
*/
toggleLabelOnSelectedMails(labelId): void
{
this.mailService.toggleLabelOnSelectedMails(labelId);
this._mailService.toggleLabelOnSelectedMails(labelId);
}
setFolderOnSelectedMails(folderId)
/**
* Set folder on selected mails
*
* @param folderId
*/
setFolderOnSelectedMails(folderId): void
{
this.mailService.setFolderOnSelectedMails(folderId);
this._mailService.setFolderOnSelectedMails(folderId);
}
}

View File

@ -27,6 +27,11 @@ export class Mail
labels: string[];
folder: string;
/**
* Constructor
*
* @param mail
*/
constructor(mail)
{
this.id = mail.id;

View File

@ -1,59 +1,57 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { MatButtonModule, MatCheckboxModule, MatDialogModule, MatFormFieldModule, MatIconModule, MatInputModule, MatMenuModule, MatRippleModule, MatSelectModule, MatSidenavModule, MatToolbarModule } from '@angular/material';
import { TranslateModule } from '@ngx-translate/core';
import { FuseSharedModule } from '@fuse/shared.module';
import { MailService } from './mail.service';
import { FuseMailComponent } from './mail.component';
import { FuseMailMainSidenavComponent } from './sidenavs/main/main-sidenav.component';
import { FuseMailListItemComponent } from './mail-list/mail-list-item/mail-list-item.component';
import { FuseMailListComponent } from './mail-list/mail-list.component';
import { FuseMailDetailsComponent } from './mail-details/mail-details.component';
import { FuseMailComposeDialogComponent } from './dialogs/compose/compose.component';
import { MailService } from 'app/main/apps/mail/mail.service';
import { MailComponent } from 'app/main/apps/mail/mail.component';
import { MailListComponent } from 'app/main/apps/mail/mail-list/mail-list.component';
import { MailListItemComponent } from 'app/main/apps/mail/mail-list/mail-list-item/mail-list-item.component';
import { MailDetailsComponent } from 'app/main/apps/mail/mail-details/mail-details.component';
import { MailMainSidenavComponent } from 'app/main/apps/mail/sidenavs/main/main-sidenav.component';
import { MailComposeDialogComponent } from 'app/main/apps/mail/dialogs/compose/compose.component';
const routes: Routes = [
{
path : 'label/:labelHandle',
component: FuseMailComponent,
component: MailComponent,
resolve : {
mail: MailService
}
},
{
path : 'label/:labelHandle/:mailId',
component: FuseMailComponent,
component: MailComponent,
resolve : {
mail: MailService
}
},
{
path : 'filter/:filterHandle',
component: FuseMailComponent,
component: MailComponent,
resolve : {
mail: MailService
}
},
{
path : 'filter/:filterHandle/:mailId',
component: FuseMailComponent,
component: MailComponent,
resolve : {
mail: MailService
}
},
{
path : ':folderHandle',
component: FuseMailComponent,
component: MailComponent,
resolve : {
mail: MailService
}
},
{
path : ':folderHandle/:mailId',
component: FuseMailComponent,
component: MailComponent,
resolve : {
mail: MailService
}
@ -66,12 +64,12 @@ const routes: Routes = [
@NgModule({
declarations : [
FuseMailComponent,
FuseMailListComponent,
FuseMailListItemComponent,
FuseMailDetailsComponent,
FuseMailMainSidenavComponent,
FuseMailComposeDialogComponent
MailComponent,
MailListComponent,
MailListItemComponent,
MailDetailsComponent,
MailMainSidenavComponent,
MailComposeDialogComponent
],
imports : [
RouterModule.forChild(routes),
@ -95,8 +93,10 @@ const routes: Routes = [
providers : [
MailService
],
entryComponents: [FuseMailComposeDialogComponent]
entryComponents: [
MailComposeDialogComponent
]
})
export class FuseMailModule
export class MailModule
{
}

View File

@ -5,7 +5,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
import { FuseUtils } from '@fuse/utils';
import { Mail } from './mail.model';
import { Mail } from 'app/main/apps/mail/mail.model';
@Injectable()
export class MailService implements Resolve<any>
@ -20,22 +20,37 @@ export class MailService implements Resolve<any>
labels: any[];
routeParams: any;
onMailsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onSelectedMailsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onCurrentMailChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onMailsChanged: BehaviorSubject<any>;
onSelectedMailsChanged: BehaviorSubject<any>;
onCurrentMailChanged: BehaviorSubject<any>;
onFoldersChanged: BehaviorSubject<any>;
onFiltersChanged: BehaviorSubject<any>;
onLabelsChanged: BehaviorSubject<any>;
onSearchTextChanged: BehaviorSubject<any>;
onFoldersChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onFiltersChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onLabelsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onSearchTextChanged: BehaviorSubject<any> = new BehaviorSubject('');
constructor(private http: HttpClient)
/**
* Constructor
*
* @param {HttpClient} _httpClient
*/
constructor(
private _httpClient: HttpClient
)
{
// Set the defaults
this.selectedMails = [];
this.onMailsChanged = new BehaviorSubject([]);
this.onSelectedMailsChanged = new BehaviorSubject([]);
this.onCurrentMailChanged = new BehaviorSubject([]);
this.onFoldersChanged = new BehaviorSubject([]);
this.onFiltersChanged = new BehaviorSubject([]);
this.onLabelsChanged = new BehaviorSubject([]);
this.onSearchTextChanged = new BehaviorSubject('');
}
/**
* Resolve
* Resolver
*
* @param {ActivatedRouteSnapshot} route
* @param {RouterStateSnapshot} state
* @returns {Observable<any> | Promise<any> | any}
@ -83,12 +98,13 @@ export class MailService implements Resolve<any>
/**
* Get all folders
*
* @returns {Promise<any>}
*/
getFolders(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/mail-folders')
this._httpClient.get('api/mail-folders')
.subscribe((response: any) => {
this.folders = response;
this.onFoldersChanged.next(this.folders);
@ -99,12 +115,13 @@ export class MailService implements Resolve<any>
/**
* Get all filters
*
* @returns {Promise<any>}
*/
getFilters(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/mail-filters')
this._httpClient.get('api/mail-filters')
.subscribe((response: any) => {
this.filters = response;
this.onFiltersChanged.next(this.filters);
@ -115,12 +132,13 @@ export class MailService implements Resolve<any>
/**
* Get all labels
*
* @returns {Promise<any>}
*/
getLabels(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/mail-labels')
this._httpClient.get('api/mail-labels')
.subscribe((response: any) => {
this.labels = response;
this.onLabelsChanged.next(this.labels);
@ -131,6 +149,7 @@ export class MailService implements Resolve<any>
/**
* Get all mails
*
* @returns {Promise<Mail[]>}
*/
getMails(): Promise<Mail[]>
@ -150,6 +169,7 @@ export class MailService implements Resolve<any>
/**
* Get mails by folder
*
* @param handle
* @returns {Promise<Mail[]>}
*/
@ -157,12 +177,12 @@ export class MailService implements Resolve<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/mail-folders?handle=' + handle)
this._httpClient.get('api/mail-folders?handle=' + handle)
.subscribe((folders: any) => {
const folderId = folders[0].id;
this.http.get('api/mail-mails?folder=' + folderId)
this._httpClient.get('api/mail-mails?folder=' + folderId)
.subscribe((mails: any) => {
this.mails = mails.map(mail => {
@ -182,6 +202,7 @@ export class MailService implements Resolve<any>
/**
* Get mails by filter
*
* @param handle
* @returns {Promise<Mail[]>}
*/
@ -189,7 +210,7 @@ export class MailService implements Resolve<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/mail-mails?' + handle + '=true')
this._httpClient.get('api/mail-mails?' + handle + '=true')
.subscribe((mails: any) => {
this.mails = mails.map(mail => {
@ -208,18 +229,19 @@ export class MailService implements Resolve<any>
/**
* Get mails by label
*
* @param handle
* @returns {Promise<Mail[]>}
*/
getMailsByLabel(handle): Promise<Mail[]>
{
return new Promise((resolve, reject) => {
this.http.get('api/mail-labels?handle=' + handle)
this._httpClient.get('api/mail-labels?handle=' + handle)
.subscribe((labels: any) => {
const labelId = labels[0].id;
this.http.get('api/mail-mails?labels=' + labelId)
this._httpClient.get('api/mail-mails?labels=' + labelId)
.subscribe((mails: any) => {
this.mails = mails.map(mail => {
@ -239,9 +261,10 @@ export class MailService implements Resolve<any>
/**
* Toggle selected mail by id
*
* @param id
*/
toggleSelectedMail(id)
toggleSelectedMail(id): void
{
// First, check if we already have that mail as selected...
if ( this.selectedMails.length > 0 )
@ -281,7 +304,7 @@ export class MailService implements Resolve<any>
/**
* Toggle select all
*/
toggleSelectAll()
toggleSelectAll(): void
{
if ( this.selectedMails.length > 0 )
{
@ -294,7 +317,13 @@ export class MailService implements Resolve<any>
}
selectMails(filterParameter?, filterValue?)
/**
* Select mails
*
* @param filterParameter
* @param filterValue
*/
selectMails(filterParameter?, filterValue?): void
{
this.selectedMails = [];
@ -316,7 +345,10 @@ export class MailService implements Resolve<any>
this.onSelectedMailsChanged.next(this.selectedMails);
}
deselectMails()
/**
* Deselect mails
*/
deselectMails(): void
{
this.selectedMails = [];
@ -326,9 +358,10 @@ export class MailService implements Resolve<any>
/**
* Set current mail by id
*
* @param id
*/
setCurrentMail(id)
setCurrentMail(id): void
{
this.currentMail = this.mails.find(mail => {
return mail.id === id;
@ -339,9 +372,10 @@ export class MailService implements Resolve<any>
/**
* Toggle label on selected mails
*
* @param labelId
*/
toggleLabelOnSelectedMails(labelId)
toggleLabelOnSelectedMails(labelId): void
{
this.selectedMails.map(mail => {
@ -362,9 +396,10 @@ export class MailService implements Resolve<any>
/**
* Set folder on selected mails
*
* @param folderId
*/
setFolderOnSelectedMails(folderId)
setFolderOnSelectedMails(folderId): void
{
this.selectedMails.map(mail => {
mail.folder = folderId;
@ -377,14 +412,15 @@ export class MailService implements Resolve<any>
/**
* Update the mail
*
* @param mail
* @returns {Promise<any>}
*/
updateMail(mail)
updateMail(mail): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.post('api/mail-mails/' + mail.id, {...mail})
this._httpClient.post('api/mail-mails/' + mail.id, {...mail})
.subscribe(response => {
this.getMails().then(mails => {
@ -400,5 +436,4 @@ export class MailService implements Resolve<any>
});
});
}
}

View File

@ -1,20 +1,21 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material';
import { Subscription } from 'rxjs';
import { fuseAnimations } from '@fuse/animations';
import { MailService } from '../../mail.service';
import { FuseMailComposeDialogComponent } from '../../dialogs/compose/compose.component';
import { MailService } from 'app/main/apps/mail/mail.service';
import { MailComposeDialogComponent } from 'app/main/apps/mail/dialogs/compose/compose.component';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector : 'fuse-mail-main-sidenav',
selector : 'mail-main-sidenav',
templateUrl: './main-sidenav.component.html',
styleUrls : ['./main-sidenav.component.scss'],
animations : fuseAnimations
})
export class FuseMailMainSidenavComponent implements OnInit, OnDestroy
export class MailMainSidenavComponent implements OnInit, OnDestroy
{
folders: any[];
filters: any[];
@ -23,55 +24,79 @@ export class FuseMailMainSidenavComponent implements OnInit, OnDestroy
selectedAccount: string;
dialogRef: any;
onFoldersChanged: Subscription;
onFiltersChanged: Subscription;
onLabelsChanged: Subscription;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {MailService} _mailService
* @param {MatDialog} _matDialog
*/
constructor(
private mailService: MailService,
public dialog: MatDialog
private _mailService: MailService,
public _matDialog: MatDialog
)
{
// Data
// Set the defaults
this.accounts = {
'creapond' : 'johndoe@creapond.com',
'withinpixels': 'johndoe@withinpixels.com'
};
this.selectedAccount = 'creapond';
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.onFoldersChanged =
this.mailService.onFoldersChanged
this._mailService.onFoldersChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(folders => {
this.folders = folders;
});
this.onFiltersChanged =
this.mailService.onFiltersChanged
this._mailService.onFiltersChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(filters => {
this.filters = filters;
});
this.onLabelsChanged =
this.mailService.onLabelsChanged
this._mailService.onLabelsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(labels => {
this.labels = labels;
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onFoldersChanged.unsubscribe();
this.onFiltersChanged.unsubscribe();
this.onLabelsChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
composeDialog()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Compose dialog
*/
composeDialog(): void
{
this.dialogRef = this.dialog.open(FuseMailComposeDialogComponent, {
this.dialogRef = this._matDialog.open(MailComposeDialogComponent, {
panelClass: 'mail-compose-dialog'
});
this.dialogRef.afterClosed()

View File

@ -67,6 +67,11 @@ export class Board
color: string
}[];
/**
* Constructor
*
* @param board
*/
constructor(board)
{
this.name = board.name || 'Untitled Board';

View File

@ -2,49 +2,77 @@ import { Component, EventEmitter, Output, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector : 'fuse-scrumboard-board-add-list',
selector : 'scrumboard-board-add-list',
templateUrl: './add-list.component.html',
styleUrls : ['./add-list.component.scss']
})
export class FuseScrumboardBoardAddListComponent
export class ScrumboardBoardAddListComponent
{
formActive = false;
formActive: boolean;
form: FormGroup;
@Output() onlistAdd = new EventEmitter();
@ViewChild('nameInput') nameInputField;
@Output()
onListAdd: EventEmitter<any>;
@ViewChild('nameInput')
nameInputField;
/**
* Constructor
*
* @param {FormBuilder} _formBuilder
*/
constructor(
private formBuilder: FormBuilder
private _formBuilder: FormBuilder
)
{
// Set the defaults
this.formActive = false;
this.onListAdd = new EventEmitter();
}
openForm()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Open form
*/
openForm(): void
{
this.form = this.formBuilder.group({
this.form = this._formBuilder.group({
name: ['']
});
this.formActive = true;
this.focusNameField();
}
closeForm()
/**
* Close form
*/
closeForm(): void
{
this.formActive = false;
}
focusNameField()
/**
* Focus to the name field
*/
focusNameField(): void
{
setTimeout(() => {
this.nameInputField.nativeElement.focus();
});
}
onFormSubmit()
/**
* On form submit
*/
onFormSubmit(): void
{
if ( this.form.valid )
{
this.onlistAdd.next(this.form.getRawValue().name);
this.onListAdd.next(this.form.getRawValue().name);
this.formActive = false;
}
}

View File

@ -26,10 +26,10 @@
fxFlex="1 0 100%" fxFlex.gt-xs="1 0 auto"
fxFlexOrder="1" fxFlexOrder.gt-xs="2">
<mat-icon *ngIf="board.settings.subscribed" class="board-subscribe s-16">remove_red_eye</mat-icon>
<fuse-scrumboard-edit-board-name
<scrumboard-edit-board-name
[board]="board"
(onNameChanged)="onBoardNameChanged($event)">
</fuse-scrumboard-edit-board-name>
</scrumboard-edit-board-name>
</div>
<!-- / BOARD NAME -->
@ -58,21 +58,21 @@
*fuseIfOnDom [@animateStagger]="{value:'50'}">
<!-- LIST -->
<fuse-scrumboard-board-list
<scrumboard-board-list
class="scrumboard-board-list list-wrapper ngx-dnd-item"
ngxDraggable
*ngFor="let list of board.lists"
[model]="list"
[list]="list"
[@animate]="{value:'*',params:{duration:'350ms',x:'100%'}}">
</fuse-scrumboard-board-list>
</scrumboard-board-list>
<!-- / LIST -->
<!-- NEW LIST BUTTON-->
<fuse-scrumboard-board-add-list class="new-list-wrapper" (onlistAdd)="onListAdd($event)"
<scrumboard-board-add-list class="new-list-wrapper" (onListAdd)="onListAdd($event)"
ngxDraggable [moves]="false"
[@animate]="{value:'*',params:{duration:'350ms',x:'100%'}}">
</fuse-scrumboard-board-add-list>
</scrumboard-board-add-list>
<!-- / NEW LIST BUTTON-->
</div>
@ -82,7 +82,7 @@
</div>
<mat-sidenav #settingsSidenav position="end">
<fuse-scrumboard-board-settings></fuse-scrumboard-board-settings>
<scrumboard-board-settings></scrumboard-board-settings>
</mat-sidenav>
</mat-sidenav-container>

View File

@ -1,65 +1,100 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Location } from '@angular/common';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations';
import { List } from '../list.model';
import { ScrumboardService } from '../scrumboard.service';
import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service';
import { List } from 'app/main/apps/scrumboard/list.model';
@Component({
selector : 'fuse-scrumboard-board',
selector : 'scrumboard-board',
templateUrl: './board.component.html',
styleUrls : ['./board.component.scss'],
animations : fuseAnimations
})
export class FuseScrumboardBoardComponent implements OnInit, OnDestroy
export class ScrumboardBoardComponent implements OnInit, OnDestroy
{
board: any;
onBoardChanged: Subscription;
// Private
private _unsubscribeAll: Subject<any>;
constructor(
private route: ActivatedRoute,
private location: Location,
private scrumboardService: ScrumboardService
private _activatedRoute: ActivatedRoute,
private _location: Location,
private _scrumboardService: ScrumboardService
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
this._scrumboardService.onBoardChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(board => {
this.board = board;
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onBoardChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
onListAdd(newListName)
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* On list add
*
* @param newListName
*/
onListAdd(newListName): void
{
if ( newListName === '' )
{
return;
}
this.scrumboardService.addList(new List({name: newListName}));
this._scrumboardService.addList(new List({name: newListName}));
}
onBoardNameChanged(newName)
/**
* On board name changed
*
* @param newName
*/
onBoardNameChanged(newName): void
{
this.scrumboardService.updateBoard();
this.location.go('/apps/scrumboard/boards/' + this.board.id + '/' + this.board.uri);
this._scrumboardService.updateBoard();
this._location.go('/apps/scrumboard/boards/' + this.board.id + '/' + this.board.uri);
}
onDrop(ev)
/**
* On drop
*
* @param ev
*/
onDrop(ev): void
{
this.scrumboardService.updateBoard();
this._scrumboardService.updateBoard();
}
}

View File

@ -35,8 +35,8 @@
<mat-menu #labelsMenu="matMenu" [overlapTrigger]="false" class="scrumboard-labels-menu">
<fuse-scrumboard-label-selector [card]="card"
(onCardLabelsChange)="updateCard()"></fuse-scrumboard-label-selector>
<scrumboard-label-selector [card]="card"
(onCardLabelsChange)="updateCard()"></scrumboard-label-selector>
</mat-menu>
</div>
@ -130,7 +130,7 @@
</div>
<!-- CLOSE DIALOG BUTTON -->
<button mat-icon-button (click)="dialogRef.close()" aria-label="Close Dialog">
<button mat-icon-button (click)="_matDialogRef.close()" aria-label="Close Dialog">
<mat-icon>close</mat-icon>
</button>
<!-- / CLOSE DIALOG BUTTON -->

View File

@ -1,74 +1,108 @@
import { Component, Inject, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { NgForm } from '@angular/forms/src/forms';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef, MatMenuTrigger } from '@angular/material';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { FuseConfirmDialogComponent } from '@fuse/components/confirm-dialog/confirm-dialog.component';
import { FuseUtils } from '@fuse/utils';
import { ScrumboardService } from '../../../scrumboard.service';
import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service';
import { takeUntil } from 'rxjs/operators';
@Component({
selector : 'fuse-scrumboard-board-card-dialog',
selector : 'scrumboard-board-card-dialog',
templateUrl : './card.component.html',
styleUrls : ['./card.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
export class ScrumboardCardDialogComponent implements OnInit, OnDestroy
{
card: any;
board: any;
list: any;
onBoardChanged: Subscription;
toggleInArray = FuseUtils.toggleInArray;
@ViewChild('checklistMenuTrigger') checklistMenu: MatMenuTrigger;
@ViewChild('newCheckListTitleField') newCheckListTitleField;
confirmDialogRef: MatDialogRef<FuseConfirmDialogComponent>;
@ViewChild('checklistMenuTrigger')
checklistMenu: MatMenuTrigger;
@ViewChild('newCheckListTitleField')
newCheckListTitleField;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {MatDialogRef<ScrumboardCardDialogComponent>} _matDialogRef
* @param _data
* @param {MatDialog} _matDialog
* @param {ScrumboardService} _scrumboardService
*/
constructor(
public dialogRef: MatDialogRef<FuseScrumboardCardDialogComponent>,
@Inject(MAT_DIALOG_DATA) private data: any,
public dialog: MatDialog,
private scrumboardService: ScrumboardService
private _matDialogRef: MatDialogRef<ScrumboardCardDialogComponent>,
@Inject(MAT_DIALOG_DATA) private _data: any,
private _matDialog: MatDialog,
private _scrumboardService: ScrumboardService
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
this._scrumboardService.onBoardChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(board => {
this.board = board;
this.card = this.board.cards.find((_card) => {
return this.data.cardId === _card.id;
return this._data.cardId === _card.id;
});
this.list = this.board.lists.find((_list) => {
return this.data.listId === _list.id;
return this._data.listId === _list.id;
});
});
}
/**
* Remove Due date
* On destroy
*/
removeDueDate()
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Remove due date
*/
removeDueDate(): void
{
this.card.due = '';
this.updateCard();
}
/**
* Toggle Subscribe
* Toggle subscribe
*/
toggleSubscribe()
toggleSubscribe(): void
{
this.card.subscribed = !this.card.subscribed;
@ -76,10 +110,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
}
/**
* Toggle Cover Image
* Toggle cover image
*
* @param attachmentId
*/
toggleCoverImage(attachmentId)
toggleCoverImage(attachmentId): void
{
if ( this.card.idAttachmentCover === attachmentId )
{
@ -94,10 +129,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
}
/**
* Remove Attachment
* Remove attachment
*
* @param attachment
*/
removeAttachment(attachment)
removeAttachment(attachment): void
{
if ( attachment.id === this.card.idAttachmentCover )
{
@ -110,10 +146,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
}
/**
* Remove Checklist
* Remove checklist
*
* @param checklist
*/
removeChecklist(checklist)
removeChecklist(checklist): void
{
this.card.checklists.splice(this.card.checklists.indexOf(checklist), 1);
@ -121,10 +158,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
}
/**
* Update Checked Count
* Update checked count
*
* @param list
*/
updateCheckedCount(list)
updateCheckedCount(list): void
{
const checkItems = list.checkItems;
let checkedItems = 0;
@ -154,11 +192,12 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
}
/**
* Remove Checklist Item
* Remove checklist item
*
* @param checkItem
* @param checklist
*/
removeChecklistItem(checkItem, checklist)
removeChecklistItem(checkItem, checklist): void
{
checklist.checkItems.splice(checklist.checkItems.indexOf(checkItem), 1);
@ -168,11 +207,12 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
}
/**
* Add Check Item
* Add check item
*
* @param {NgForm} form
* @param checkList
*/
addCheckItem(form: NgForm, checkList)
addCheckItem(form: NgForm, checkList): void
{
const checkItemVal = form.value.checkItem;
@ -196,10 +236,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
}
/**
* Add Checklist
* Add checklist
*
* @param {NgForm} form
*/
addChecklist(form: NgForm)
addChecklist(form: NgForm): void
{
this.card.checklists.push({
id : FuseUtils.generateGUID(),
@ -215,9 +256,9 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
}
/**
* On Checklist Menu Open
* On checklist menu open
*/
onChecklistMenuOpen()
onChecklistMenuOpen(): void
{
setTimeout(() => {
this.newCheckListTitleField.nativeElement.focus();
@ -225,10 +266,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
}
/**
* Add New Comment
* Add new comment
*
* @param {NgForm} form
*/
addNewComment(form: NgForm)
addNewComment(form: NgForm): void
{
const newCommentText = form.value.newComment;
@ -246,11 +288,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
}
/**
* Remove Card
* Remove card
*/
removeCard()
removeCard(): void
{
this.confirmDialogRef = this.dialog.open(FuseConfirmDialogComponent, {
this.confirmDialogRef = this._matDialog.open(FuseConfirmDialogComponent, {
disableClose: false
});
@ -259,22 +301,17 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy
this.confirmDialogRef.afterClosed().subscribe(result => {
if ( result )
{
this.dialogRef.close();
this.scrumboardService.removeCard(this.card.id, this.list.id);
this._matDialogRef.close();
this._scrumboardService.removeCard(this.card.id, this.list.id);
}
});
}
/**
* Update Card
* Update card
*/
updateCard()
updateCard(): void
{
this.scrumboardService.updateCard(this.card);
}
ngOnDestroy()
{
this.onBoardChanged.unsubscribe();
this._scrumboardService.updateCard(this.card);
}
}

View File

@ -1,68 +1,110 @@
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations';
import { FuseUtils } from '@fuse/utils';
import { ScrumboardService } from '../../../../scrumboard.service';
import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service';
@Component({
selector : 'fuse-scrumboard-label-selector',
selector : 'scrumboard-label-selector',
templateUrl : './label-selector.component.html',
styleUrls : ['./label-selector.component.scss'],
encapsulation: ViewEncapsulation.None,
animations : fuseAnimations
})
export class FuseScrumboardLabelSelectorComponent implements OnInit, OnDestroy
export class ScrumboardLabelSelectorComponent implements OnInit, OnDestroy
{
board: any;
@Input('card') card: any;
@Output() onCardLabelsChange = new EventEmitter();
@Input('card')
card: any;
labelsMenuView = 'labels';
@Output()
onCardLabelsChange: EventEmitter<any>;
board: any;
labelsMenuView: string;
selectedLabel: any;
newLabel = {
newLabel: any;
toggleInArray: any;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {ScrumboardService} _scrumboardService
*/
constructor(
private _scrumboardService: ScrumboardService
)
{
// Set the defaults
this.onCardLabelsChange = new EventEmitter();
this.labelsMenuView = 'labels';
this.newLabel = {
'id' : '',
'name' : '',
'color': 'mat-blue-400-bg'
};
toggleInArray = FuseUtils.toggleInArray;
this.toggleInArray = FuseUtils.toggleInArray;
onBoardChanged: Subscription;
constructor(
private scrumboardService: ScrumboardService
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
this._scrumboardService.onBoardChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(board => {
this.board = board;
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onBoardChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
cardLabelsChanged()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Card labels changed
*/
cardLabelsChanged(): void
{
this.onCardLabelsChange.next();
}
onLabelChange()
/**
* On label change
*/
onLabelChange(): void
{
this.scrumboardService.updateBoard();
this._scrumboardService.updateBoard();
}
addNewLabel()
/**
* Add new label
*/
addNewLabel(): void
{
this.newLabel.id = FuseUtils.generateGUID();
this.board.labels.push(Object.assign({}, this.newLabel));

View File

@ -2,25 +2,41 @@ import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector : 'fuse-scrumboard-edit-board-name',
selector : 'scrumboard-edit-board-name',
templateUrl: './edit-board-name.component.html',
styleUrls : ['./edit-board-name.component.scss']
})
export class FuseScrumboardEditBoardNameComponent
export class ScrumboardEditBoardNameComponent
{
formActive = false;
formActive: boolean;
form: FormGroup;
@Input() board;
@Output() onNameChanged = new EventEmitter();
@ViewChild('nameInput') nameInputField;
@Input()
board;
@Output()
onNameChanged: EventEmitter<any>;
@ViewChild('nameInput')
nameInputField;
constructor(
private formBuilder: FormBuilder
)
{
// Set the defaults
this.formActive = false;
this.onNameChanged = new EventEmitter();
}
openForm()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Open form
*/
openForm(): void
{
this.form = this.formBuilder.group({
name: [this.board.name]
@ -29,19 +45,28 @@ export class FuseScrumboardEditBoardNameComponent
this.focusNameField();
}
closeForm()
/**
* Close form
*/
closeForm(): void
{
this.formActive = false;
}
focusNameField()
/**
* Focus to the name field
*/
focusNameField(): void
{
setTimeout(() => {
this.nameInputField.nativeElement.focus();
});
}
onFormSubmit()
/**
* On form submit
*/
onFormSubmit(): void
{
if ( this.form.valid )
{
@ -52,5 +77,4 @@ export class FuseScrumboardEditBoardNameComponent
this.formActive = false;
}
}
}

View File

@ -2,45 +2,73 @@ import { Component, EventEmitter, Output, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector : 'fuse-scrumboard-board-add-card',
selector : 'scrumboard-board-add-card',
templateUrl: './add-card.component.html',
styleUrls : ['./add-card.component.scss']
})
export class FuseScrumboardBoardAddCardComponent
export class ScrumboardBoardAddCardComponent
{
formActive = false;
formActive: boolean;
form: FormGroup;
@Output() onCardAdd = new EventEmitter();
@ViewChild('nameInput') nameInputField;
@Output()
onCardAdd: EventEmitter<any>;
@ViewChild('nameInput')
nameInputField;
/**
* Constructor
*
* @param {FormBuilder} _formBuilder
*/
constructor(
private formBuilder: FormBuilder
private _formBuilder: FormBuilder
)
{
// Set the defaults
this.formActive = false;
this.onCardAdd = new EventEmitter();
}
openForm()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Open the form
*/
openForm(): void
{
this.form = this.formBuilder.group({
this.form = this._formBuilder.group({
name: ''
});
this.formActive = true;
this.focusNameField();
}
closeForm()
/**
* Close the form
*/
closeForm(): void
{
this.formActive = false;
}
focusNameField()
/**
* Focus to the name field
*/
focusNameField(): void
{
setTimeout(() => {
this.nameInputField.nativeElement.focus();
});
}
onFormSubmit()
/**
* On form submit
*/
onFormSubmit(): void
{
if ( this.form.valid )
{

View File

@ -3,40 +3,57 @@ import { ActivatedRoute } from '@angular/router';
import * as moment from 'moment';
@Component({
selector : 'fuse-scrumboard-board-card',
selector : 'scrumboard-board-card',
templateUrl : './card.component.html',
styleUrls : ['./card.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseScrumboardBoardCardComponent implements OnInit
export class ScrumboardBoardCardComponent implements OnInit
{
@Input() cardId;
@Input()
cardId;
card: any;
board: any;
/**
* Constructor
*
* @param {ActivatedRoute} _activatedRoute
*/
constructor(
private route: ActivatedRoute,
private _activatedRoute: ActivatedRoute
)
{
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.board = this.route.snapshot.data.board;
this.board = this._activatedRoute.snapshot.data.board;
this.card = this.board.cards.filter((card) => {
return this.cardId === card.id;
})[0];
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Is the card overdue?
*
* @param cardDate
* @returns {boolean}
*/
isOverdue(cardDate)
isOverdue(cardDate): boolean
{
return moment() > moment(new Date(cardDate));
}
}

View File

@ -2,46 +2,76 @@ import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector : 'fuse-scrumboard-board-edit-list-name',
selector : 'scrumboard-board-edit-list-name',
templateUrl: './edit-list-name.component.html',
styleUrls : ['./edit-list-name.component.scss']
})
export class FuseScrumboardBoardEditListNameComponent
export class ScrumboardBoardEditListNameComponent
{
formActive = false;
formActive: boolean;
form: FormGroup;
@Input() list;
@Output() onNameChanged = new EventEmitter();
@ViewChild('nameInput') nameInputField;
@Input()
list;
@Output()
onNameChanged: EventEmitter<any>;
@ViewChild('nameInput')
nameInputField;
/**
* Constructor
*
* @param {FormBuilder} _formBuilder
*/
constructor(
private formBuilder: FormBuilder
private _formBuilder: FormBuilder
)
{
// Set the defaults
this.formActive = false;
this.onNameChanged = new EventEmitter();
}
openForm()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Open the form
*/
openForm(): void
{
this.form = this.formBuilder.group({
this.form = this._formBuilder.group({
name: [this.list.name]
});
this.formActive = true;
this.focusNameField();
}
closeForm()
/**
* Close the form
*/
closeForm(): void
{
this.formActive = false;
}
focusNameField()
/**
* Focus to the name field
*/
focusNameField(): void
{
setTimeout(() => {
this.nameInputField.nativeElement.focus();
});
}
onFormSubmit()
/**
* On form submit
*/
onFormSubmit(): void
{
if ( this.form.valid )
{
@ -50,5 +80,4 @@ export class FuseScrumboardBoardEditListNameComponent
this.formActive = false;
}
}
}

View File

@ -3,11 +3,11 @@
<!-- LIST HEADER -->
<div class="list-header" fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<fuse-scrumboard-board-edit-list-name
<scrumboard-board-edit-list-name
fxFlex="1 0 auto"
[list]="list"
(onNameChanged)="onListNameChanged($event)">
</fuse-scrumboard-board-edit-list-name>
</scrumboard-board-edit-list-name>
<div fxFlex="0 1 auto">
<button mat-icon-button class="list-header-option-button" [matMenuTriggerFor]="listMenu">
@ -27,21 +27,21 @@
<div class="list-cards ngx-dnd-container"
[model]="list.idCards" ngxDroppable="card" (out)="onDrop($event)"
fusePerfectScrollbar #listScroll>
<fuse-scrumboard-board-card ngxDraggable
<scrumboard-board-card ngxDraggable
(click)="openCardDialog(cardId)"
class="scrumboard-board-card mat-elevation-z2 ngx-dnd-item"
*ngFor="let cardId of list.idCards"
[model]="cardId"
[cardId]="cardId">
</fuse-scrumboard-board-card>
</scrumboard-board-card>
</div>
</div>
<!-- / LIST CONTENT -->
<!-- NEW CARD BUTTON-->
<div class="list-footer">
<fuse-scrumboard-board-add-card (onCardAdd)="onCardAdd($event)">
</fuse-scrumboard-board-add-card>
<scrumboard-board-add-card (onCardAdd)="onCardAdd($event)">
</scrumboard-board-add-card>
</div>
<!-- / NEW CARD BUTTON-->

View File

@ -1,78 +1,122 @@
import { Component, Input, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { MatDialog, MatDialogRef } from '@angular/material';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseConfirmDialogComponent } from '@fuse/components/confirm-dialog/confirm-dialog.component';
import { FusePerfectScrollbarDirective } from '@fuse/directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive';
import { Card } from '../../card.model';
import { ScrumboardService } from '../../scrumboard.service';
import { FuseScrumboardCardDialogComponent } from '../dialogs/card/card.component';
import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service';
import { Card } from 'app/main/apps/scrumboard/card.model';
import { ScrumboardCardDialogComponent } from 'app/main/apps/scrumboard/board/dialogs/card/card.component';
@Component({
selector : 'fuse-scrumboard-board-list',
selector : 'scrumboard-board-list',
templateUrl : './list.component.html',
styleUrls : ['./list.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseScrumboardBoardListComponent implements OnInit, OnDestroy
export class ScrumboardBoardListComponent implements OnInit, OnDestroy
{
board: any;
dialogRef: any;
@Input() list;
@ViewChild(FusePerfectScrollbarDirective) listScroll: FusePerfectScrollbarDirective;
@Input()
list;
@ViewChild(FusePerfectScrollbarDirective)
listScroll: FusePerfectScrollbarDirective;
onBoardChanged: Subscription;
confirmDialogRef: MatDialogRef<FuseConfirmDialogComponent>;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {ActivatedRoute} _activatedRoute
* @param {ScrumboardService} _scrumboardService
* @param {MatDialog} _matDialog
*/
constructor(
private route: ActivatedRoute,
private scrumboardService: ScrumboardService,
public dialog: MatDialog
private _activatedRoute: ActivatedRoute,
private _scrumboardService: ScrumboardService,
private _matDialog: MatDialog
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
this._scrumboardService.onBoardChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(board => {
this.board = board;
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onBoardChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
onListNameChanged(newListName)
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* On list name changed
*
* @param newListName
*/
onListNameChanged(newListName): void
{
this.list.name = newListName;
}
onCardAdd(newCardName)
/**
* On card added
*
* @param newCardName
*/
onCardAdd(newCardName): void
{
if ( newCardName === '' )
{
return;
}
this.scrumboardService.addCard(this.list.id, new Card({name: newCardName}));
this._scrumboardService.addCard(this.list.id, new Card({name: newCardName}));
setTimeout(() => {
this.listScroll.scrollToBottom(0, 400);
});
}
removeList(listId)
/**
* Remove list
*
* @param listId
*/
removeList(listId): void
{
this.confirmDialogRef = this.dialog.open(FuseConfirmDialogComponent, {
this.confirmDialogRef = this._matDialog.open(FuseConfirmDialogComponent, {
disableClose: false
});
@ -81,14 +125,19 @@ export class FuseScrumboardBoardListComponent implements OnInit, OnDestroy
this.confirmDialogRef.afterClosed().subscribe(result => {
if ( result )
{
this.scrumboardService.removeList(listId);
this._scrumboardService.removeList(listId);
}
});
}
openCardDialog(cardId)
/**
* Open card dialog
*
* @param cardId
*/
openCardDialog(cardId): void
{
this.dialogRef = this.dialog.open(FuseScrumboardCardDialogComponent, {
this.dialogRef = this._matDialog.open(ScrumboardCardDialogComponent, {
panelClass: 'scrumboard-card-dialog',
data : {
cardId: cardId,
@ -101,8 +150,13 @@ export class FuseScrumboardBoardListComponent implements OnInit, OnDestroy
});
}
onDrop(ev)
/**
* On drop
*
* @param ev
*/
onDrop(ev): void
{
this.scrumboardService.updateBoard();
this._scrumboardService.updateBoard();
}
}

View File

@ -1,46 +1,78 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { MatColors } from '@fuse/mat-colors';
import { ScrumboardService } from '../../../../scrumboard.service';
import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service';
@Component({
selector : 'fuse-scrumboard-board-color-selector',
selector : 'scrumboard-board-color-selector',
templateUrl: './board-color-selector.component.html',
styleUrls : ['./board-color-selector.component.scss']
})
export class FuseScrumboardBoardColorSelectorComponent implements OnInit, OnDestroy
export class ScrumboardBoardColorSelectorComponent implements OnInit, OnDestroy
{
colors: any;
board: any;
onBoardChanged: Subscription;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {ScrumboardService} _scrumboardService
*/
constructor(
private scrumboardService: ScrumboardService
private _scrumboardService: ScrumboardService
)
{
// Set the defaults
this.colors = MatColors.all;
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
this._scrumboardService.onBoardChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(board => {
this.board = board;
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onBoardChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
setColor(color)
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Set the color
*
* @param color
*/
setColor(color): void
{
this.board.settings.color = color;
this.scrumboardService.updateBoard();
this._scrumboardService.updateBoard();
}
}

View File

@ -28,7 +28,7 @@
</div>
<div class="nav-item">
<div class="nav-link" matRipple (click)="toggleSubcription()">
<div class="nav-link" matRipple (click)="toggleSubscription()">
<mat-icon class="nav-link-icon">remove_red_eye</mat-icon>
<p fxFlex class="title">Subscribe</p>
<mat-icon *ngIf="board.settings.subscribed" class="s-18">check</mat-icon>
@ -68,7 +68,7 @@
<!-- SIDENAV CONTENT -->
<div class="content p-8" fusePerfectScrollbar>
<fuse-scrumboard-board-color-selector></fuse-scrumboard-board-color-selector>
<scrumboard-board-color-selector></scrumboard-board-color-selector>
</div>
<!-- / SIDENAV CONTENT -->

View File

@ -1,50 +1,78 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { fuseAnimations } from '@fuse/animations';
import { ScrumboardService } from '../../../scrumboard.service';
import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector : 'fuse-scrumboard-board-settings',
selector : 'scrumboard-board-settings',
templateUrl: './settings.component.html',
styleUrls : ['./settings.component.scss'],
animations : fuseAnimations
})
export class FuseScrumboardBoardSettingsSidenavComponent implements OnInit, OnDestroy
export class ScrumboardBoardSettingsSidenavComponent implements OnInit, OnDestroy
{
board: any;
view = 'main';
onBoardChanged: Subscription;
view: string;
// Private
private _unsubscribeAll: Subject<any>;
constructor(
private scrumboardService: ScrumboardService
)
{
// Set the defaults
this.view = 'main';
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.onBoardChanged =
this.scrumboardService.onBoardChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(board => {
this.board = board;
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onBoardChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
toggleCardCover()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle card cover
*/
toggleCardCover(): void
{
this.board.settings.cardCoverImages = !this.board.settings.cardCoverImages;
this.scrumboardService.updateBoard();
}
toggleSubcription()
/**
* Toggle subscription
*/
toggleSubscription(): void
{
this.board.settings.subscribed = !this.board.settings.subscribed;
this.scrumboardService.updateBoard();

View File

@ -17,6 +17,11 @@ export class Card
activities: any[];
due: string;
/**
* Constructor
*
* @param card
*/
constructor(card)
{
this.id = card.id || FuseUtils.generateGUID();

View File

@ -6,6 +6,11 @@ export class List
name: string;
idCards: string[];
/**
* Constructor
*
* @param list
*/
constructor(list)
{
this.id = list.id || FuseUtils.generateGUID();

View File

@ -1,50 +1,79 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations';
import { Board } from './board.model';
import { ScrumboardService } from './scrumboard.service';
import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service';
import { Board } from 'app/main/apps/scrumboard/board.model';
@Component({
selector : 'fuse-scrumboard',
selector : 'scrumboard',
templateUrl: './scrumboard.component.html',
styleUrls : ['./scrumboard.component.scss'],
animations : fuseAnimations
})
export class FuseScrumboardComponent implements OnInit, OnDestroy
export class ScrumboardComponent implements OnInit, OnDestroy
{
boards: any[];
onBoardsChanged: Subscription;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {Router} _router
* @param {ScrumboardService} _scrumboardService
*/
constructor(
private router: Router,
private scrumboardService: ScrumboardService
private _router: Router,
private _scrumboardService: ScrumboardService
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.onBoardsChanged =
this.scrumboardService.onBoardsChanged
this._scrumboardService.onBoardsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(boards => {
this.boards = boards;
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onBoardsChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
newBoard()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* New board
*/
newBoard(): void
{
const newBoard = new Board({});
this.scrumboardService.createNewBoard(newBoard).then(() => {
this.router.navigate(['/apps/scrumboard/boards/' + newBoard.id + '/' + newBoard.uri]);
this._scrumboardService.createNewBoard(newBoard).then(() => {
this._router.navigate(['/apps/scrumboard/boards/' + newBoard.id + '/' + newBoard.uri]);
});
}
}

View File

@ -1,37 +1,36 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { MatButtonModule, MatCheckboxModule, MatChipsModule, MatDatepickerModule, MatDialogModule, MatFormFieldModule, MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatProgressBarModule, MatRippleModule, MatSidenavModule, MatToolbarModule, MatTooltipModule } from '@angular/material';
import { NgxDnDModule } from '@swimlane/ngx-dnd';
import { FuseSharedModule } from '@fuse/shared.module';
import { FuseConfirmDialogModule, FuseMaterialColorPickerModule } from '@fuse/components';
import { BoardResolve, ScrumboardService } from './scrumboard.service';
import { FuseScrumboardComponent } from './scrumboard.component';
import { FuseScrumboardBoardComponent } from './board/board.component';
import { FuseScrumboardBoardListComponent } from './board/list/list.component';
import { FuseScrumboardBoardCardComponent } from './board/list/card/card.component';
import { FuseScrumboardBoardEditListNameComponent } from './board/list/edit-list-name/edit-list-name.component';
import { FuseScrumboardBoardAddCardComponent } from './board/list/add-card/add-card.component';
import { FuseScrumboardBoardAddListComponent } from './board/add-list/add-list.component';
import { FuseScrumboardCardDialogComponent } from './board/dialogs/card/card.component';
import { FuseScrumboardLabelSelectorComponent } from './board/dialogs/card/label-selector/label-selector.component';
import { FuseScrumboardEditBoardNameComponent } from './board/edit-board-name/edit-board-name.component';
import { FuseScrumboardBoardSettingsSidenavComponent } from './board/sidenavs/settings/settings.component';
import { FuseScrumboardBoardColorSelectorComponent } from './board/sidenavs/settings/board-color-selector/board-color-selector.component';
import { NgxDnDModule } from '@swimlane/ngx-dnd';
import { BoardResolve, ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service';
import { ScrumboardComponent } from 'app/main/apps/scrumboard/scrumboard.component';
import { ScrumboardBoardComponent } from 'app/main/apps/scrumboard/board/board.component';
import { ScrumboardBoardListComponent } from 'app/main/apps/scrumboard/board/list/list.component';
import { ScrumboardBoardCardComponent } from 'app/main/apps/scrumboard/board/list/card/card.component';
import { ScrumboardBoardEditListNameComponent } from 'app/main/apps/scrumboard/board/list/edit-list-name/edit-list-name.component';
import { ScrumboardBoardAddCardComponent } from 'app/main/apps/scrumboard/board/list/add-card/add-card.component';
import { ScrumboardBoardAddListComponent } from 'app/main/apps/scrumboard/board/add-list/add-list.component';
import { ScrumboardCardDialogComponent } from 'app/main/apps/scrumboard/board/dialogs/card/card.component';
import { ScrumboardLabelSelectorComponent } from 'app/main/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component';
import { ScrumboardEditBoardNameComponent } from 'app/main/apps/scrumboard/board/edit-board-name/edit-board-name.component';
import { ScrumboardBoardSettingsSidenavComponent } from 'app/main/apps/scrumboard/board/sidenavs/settings/settings.component';
import { ScrumboardBoardColorSelectorComponent } from 'app/main/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component';
const routes: Routes = [
{
path : 'boards',
component: FuseScrumboardComponent,
component: ScrumboardComponent,
resolve : {
scrumboard: ScrumboardService
}
},
{
path : 'boards/:boardId/:boardUri',
component: FuseScrumboardBoardComponent,
component: ScrumboardBoardComponent,
resolve : {
board: BoardResolve
}
@ -44,18 +43,18 @@ const routes: Routes = [
@NgModule({
declarations : [
FuseScrumboardComponent,
FuseScrumboardBoardComponent,
FuseScrumboardBoardListComponent,
FuseScrumboardBoardCardComponent,
FuseScrumboardBoardEditListNameComponent,
FuseScrumboardBoardAddCardComponent,
FuseScrumboardBoardAddListComponent,
FuseScrumboardCardDialogComponent,
FuseScrumboardLabelSelectorComponent,
FuseScrumboardEditBoardNameComponent,
FuseScrumboardBoardSettingsSidenavComponent,
FuseScrumboardBoardColorSelectorComponent
ScrumboardComponent,
ScrumboardBoardComponent,
ScrumboardBoardListComponent,
ScrumboardBoardCardComponent,
ScrumboardBoardEditListNameComponent,
ScrumboardBoardAddCardComponent,
ScrumboardBoardAddListComponent,
ScrumboardCardDialogComponent,
ScrumboardLabelSelectorComponent,
ScrumboardEditBoardNameComponent,
ScrumboardBoardSettingsSidenavComponent,
ScrumboardBoardColorSelectorComponent
],
imports : [
RouterModule.forChild(routes),
@ -86,7 +85,7 @@ const routes: Routes = [
ScrumboardService,
BoardResolve
],
entryComponents: [FuseScrumboardCardDialogComponent]
entryComponents: [ScrumboardCardDialogComponent]
})
export class FuseScrumboardModule
{

View File

@ -1,7 +1,6 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { Observable, BehaviorSubject } from 'rxjs';
@Injectable()
@ -11,15 +10,26 @@ export class ScrumboardService implements Resolve<any>
routeParams: any;
board: any;
onBoardsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onBoardChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onBoardsChanged: BehaviorSubject<any>;
onBoardChanged: BehaviorSubject<any>;
constructor(private http: HttpClient)
/**
* Constructor
*
* @param {HttpClient} _httpClient
*/
constructor(
private _httpClient: HttpClient
)
{
// Set the defaults
this.onBoardsChanged = new BehaviorSubject([]);
this.onBoardChanged = new BehaviorSubject([]);
}
/**
* Resolve
* Resolver
*
* @param {ActivatedRouteSnapshot} route
* @param {RouterStateSnapshot} state
* @returns {Observable<any> | Promise<any> | any}
@ -40,10 +50,15 @@ export class ScrumboardService implements Resolve<any>
});
}
/**
* Get boards
*
* @returns {Promise<any>}
*/
getBoards(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/scrumboard-boards')
this._httpClient.get('api/scrumboard-boards')
.subscribe((response: any) => {
this.boards = response;
this.onBoardsChanged.next(this.boards);
@ -52,10 +67,16 @@ export class ScrumboardService implements Resolve<any>
});
}
/**
* Get board
*
* @param boardId
* @returns {Promise<any>}
*/
getBoard(boardId): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/scrumboard-boards/' + boardId)
this._httpClient.get('api/scrumboard-boards/' + boardId)
.subscribe((response: any) => {
this.board = response;
this.onBoardChanged.next(this.board);
@ -64,7 +85,14 @@ export class ScrumboardService implements Resolve<any>
});
}
addCard(listId, newCard)
/**
* Add card
*
* @param listId
* @param newCard
* @returns {Promise<any>}
*/
addCard(listId, newCard): Promise<any>
{
this.board.lists.map((list) => {
if ( list.id === listId )
@ -78,16 +106,26 @@ export class ScrumboardService implements Resolve<any>
return this.updateBoard();
}
addList(newList)
/**
* Add list
*
* @param newList
* @returns {Promise<any>}
*/
addList(newList): Promise<any>
{
this.board.lists.push(newList);
return this.updateBoard();
}
removeList(listId)
/**
* Remove list
*
* @param listId
* @returns {Promise<any>}
*/
removeList(listId): Promise<any>
{
const list = this.board.lists.find((_list) => {
return _list.id === listId;
@ -105,9 +143,14 @@ export class ScrumboardService implements Resolve<any>
return this.updateBoard();
}
removeCard(cardId, listId?)
/**
* Remove card
*
* @param cardId
* @param listId
*/
removeCard(cardId, listId?): void
{
const card = this.board.cards.find((_card) => {
return _card.id === cardId;
});
@ -125,10 +168,15 @@ export class ScrumboardService implements Resolve<any>
this.updateBoard();
}
updateBoard()
/**
* Update board
*
* @returns {Promise<any>}
*/
updateBoard(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.post('api/scrumboard-boards/' + this.board.id, this.board)
this._httpClient.post('api/scrumboard-boards/' + this.board.id, this.board)
.subscribe(response => {
this.onBoardChanged.next(this.board);
resolve(this.board);
@ -136,7 +184,12 @@ export class ScrumboardService implements Resolve<any>
});
}
updateCard(newCard)
/**
* Update card
*
* @param newCard
*/
updateCard(newCard): void
{
this.board.cards.map((_card) => {
if ( _card.id === newCard.id )
@ -148,10 +201,16 @@ export class ScrumboardService implements Resolve<any>
this.updateBoard();
}
createNewBoard(board)
/**
* Create new board
*
* @param board
* @returns {Promise<any>}
*/
createNewBoard(board): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.post('api/scrumboard-boards/' + board.id, board)
this._httpClient.post('api/scrumboard-boards/' + board.id, board)
.subscribe(response => {
resolve(board);
}, reject);
@ -162,12 +221,25 @@ export class ScrumboardService implements Resolve<any>
@Injectable()
export class BoardResolve implements Resolve<any>
{
constructor(private scrumboardService: ScrumboardService)
/**
* Constructor
*
* @param {ScrumboardService} _scrumboardService
*/
constructor(
private _scrumboardService: ScrumboardService
)
{
}
resolve(route: ActivatedRouteSnapshot)
/**
* Resolver
*
* @param {ActivatedRouteSnapshot} route
* @returns {Promise<any>}
*/
resolve(route: ActivatedRouteSnapshot): Promise<any>
{
return this.scrumboardService.getBoard(route.paramMap.get('boardId'));
return this._scrumboardService.getBoard(route.paramMap.get('boardId'));
}
}

View File

@ -1,18 +1,19 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations';
import { TodoService } from '../../todo.service';
import { TodoService } from 'app/main/apps/todo/todo.service';
@Component({
selector : 'fuse-todo-main-sidenav',
selector : 'todo-main-sidenav',
templateUrl: './main-sidenav.component.html',
styleUrls : ['./main-sidenav.component.scss'],
animations : fuseAnimations
})
export class FuseTodoMainSidenavComponent implements OnInit, OnDestroy
export class TodoMainSidenavComponent implements OnInit, OnDestroy
{
folders: any[];
filters: any[];
@ -20,46 +21,75 @@ export class FuseTodoMainSidenavComponent implements OnInit, OnDestroy
accounts: object;
selectedAccount: string;
onFiltersChanged: Subscription;
onTagsChanged: Subscription;
// Private
private _unsubscribeAll: Subject<any>;
constructor(private todoService: TodoService, private router: Router)
/**
* Constructor
*
* @param {TodoService} _todoService
* @param {Router} _router
*/
constructor(
private _todoService: TodoService,
private _router: Router
)
{
// Data
// Set the defaults
this.accounts = {
'creapond' : 'johndoe@creapond.com',
'withinpixels': 'johndoe@withinpixels.com'
};
this.selectedAccount = 'creapond';
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.onFiltersChanged =
this.todoService.onFiltersChanged
this._todoService.onFiltersChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(filters => {
this.filters = filters;
});
this.onTagsChanged =
this.todoService.onTagsChanged
this._todoService.onTagsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(tags => {
this.tags = tags;
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onFiltersChanged.unsubscribe();
this.onTagsChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
newTodo()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* New todo
*/
newTodo(): void
{
this.router.navigate(['/apps/todo/all']).then(() => {
this._router.navigate(['/apps/todo/all']).then(() => {
setTimeout(() => {
this.todoService.onNewTodoClicked.next('');
this._todoService.onNewTodoClicked.next('');
});
});
}

View File

@ -1,108 +1,132 @@
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { FuseUtils } from '@fuse/utils';
import { fuseAnimations } from '@fuse/animations';
import { Todo } from '../todo.model';
import { TodoService } from '../todo.service';
import { Todo } from 'app/main/apps/todo/todo.model';
import { TodoService } from 'app/main/apps/todo/todo.service';
@Component({
selector : 'fuse-todo-details',
selector : 'todo-details',
templateUrl: './todo-details.component.html',
styleUrls : ['./todo-details.component.scss'],
animations : fuseAnimations
})
export class FuseTodoDetailsComponent implements OnInit, OnDestroy
export class TodoDetailsComponent implements OnInit, OnDestroy
{
todo: Todo;
tags: any[];
formType: string;
todoForm: FormGroup;
@ViewChild('titleInput') titleInputField;
onFormChange: any;
onCurrentTodoChanged: Subscription;
onTagsChanged: Subscription;
onNewTodoClicked: Subscription;
@ViewChild('titleInput')
titleInputField;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {TodoService} _todoService
* @param {FormBuilder} _formBuilder
*/
constructor(
private todoService: TodoService,
private formBuilder: FormBuilder
private _todoService: TodoService,
private _formBuilder: FormBuilder
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to update the current todo
this.onCurrentTodoChanged =
this.todoService.onCurrentTodoChanged
this._todoService.onCurrentTodoChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(([todo, formType]) => {
if ( todo && formType === 'edit' )
{
this.formType = 'edit';
this.todo = todo;
this.todoForm = this.createTodoForm();
this.onFormChange =
this.todoForm.valueChanges.pipe(
this.todoForm.valueChanges
.pipe(
takeUntil(this._unsubscribeAll),
debounceTime(500),
distinctUntilChanged()
).subscribe(data => {
this.todoService.updateTodo(data);
)
.subscribe(data => {
this._todoService.updateTodo(data);
});
}
});
// Subscribe to update on tag change
this.onTagsChanged =
this.todoService.onTagsChanged
this._todoService.onTagsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(labels => {
this.tags = labels;
});
// Subscribe to update on tag change
this.onNewTodoClicked =
this.todoService.onNewTodoClicked
this._todoService.onNewTodoClicked
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
this.todo = new Todo({});
this.todo.id = FuseUtils.generateGUID();
this.formType = 'new';
this.todoForm = this.createTodoForm();
this.focusTitleField();
this.todoService.onCurrentTodoChanged.next([this.todo, 'new']);
this._todoService.onCurrentTodoChanged.next([this.todo, 'new']);
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
if ( this.onFormChange )
{
this.onFormChange.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
this.onCurrentTodoChanged.unsubscribe();
this.onNewTodoClicked.unsubscribe();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
focusTitleField()
/**
* Focus title field
*/
focusTitleField(): void
{
setTimeout(() => {
this.titleInputField.nativeElement.focus();
});
}
createTodoForm()
/**
* Create todo form
*
* @returns {FormGroup}
*/
createTodoForm(): FormGroup
{
return this.formBuilder.group({
return this._formBuilder.group({
'id' : [this.todo.id],
'title' : [this.todo.title],
'notes' : [this.todo.notes],
@ -116,54 +140,80 @@ export class FuseTodoDetailsComponent implements OnInit, OnDestroy
});
}
toggleStar(event)
/**
* Toggle star
*
* @param event
*/
toggleStar(event): void
{
event.stopPropagation();
this.todo.toggleStar();
this.todoService.updateTodo(this.todo);
this._todoService.updateTodo(this.todo);
}
toggleImportant(event)
/**
* Toggle important
*
* @param event
*/
toggleImportant(event): void
{
event.stopPropagation();
this.todo.toggleImportant();
this.todoService.updateTodo(this.todo);
this._todoService.updateTodo(this.todo);
}
/**
* Toggle Completed
*
* @param event
*/
toggleCompleted(event)
toggleCompleted(event): void
{
event.stopPropagation();
this.todo.toggleCompleted();
this.todoService.updateTodo(this.todo);
this._todoService.updateTodo(this.todo);
}
/**
* Toggle Deleted
*
* @param event
*/
toggleDeleted(event)
toggleDeleted(event): void
{
event.stopPropagation();
this.todo.toggleDeleted();
this.todoService.updateTodo(this.todo);
this._todoService.updateTodo(this.todo);
}
toggleTagOnTodo(tagId)
/**
* Toggle tag on todo
*
* @param tagId
*/
toggleTagOnTodo(tagId): void
{
this.todoService.toggleTagOnTodo(tagId, this.todo);
this._todoService.toggleTagOnTodo(tagId, this.todo);
}
hasTag(tagId)
/**
* Has tag?
*
* @param tagId
* @returns {any}
*/
hasTag(tagId): any
{
return this.todoService.hasTag(tagId, this.todo);
return this._todoService.hasTag(tagId, this.todo);
}
addTodo()
/**
* Add todo
*/
addTodo(): void
{
this.todoService.updateTodo(this.todoForm.getRawValue());
this._todoService.updateTodo(this.todoForm.getRawValue());
}
}

View File

@ -1,48 +1,72 @@
import { Component, HostBinding, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { Todo } from '../../todo.model';
import { TodoService } from '../../todo.service';
import { Subject, Subscription } from 'rxjs';
import { Todo } from 'app/main/apps/todo/todo.model';
import { TodoService } from 'app/main/apps/todo/todo.service';
import { takeUntil } from 'rxjs/operators';
@Component({
selector : 'fuse-todo-list-item',
selector : 'todo-list-item',
templateUrl : './todo-list-item.component.html',
styleUrls : ['./todo-list-item.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseTodoListItemComponent implements OnInit, OnDestroy
export class TodoListItemComponent implements OnInit, OnDestroy
{
@Input() todo: Todo;
tags: any[];
@HostBinding('class.selected') selected: boolean;
@HostBinding('class.completed') completed: boolean;
@HostBinding('class.move-disabled') moveDisabled: boolean;
onSelectedTodosChanged: Subscription;
onTagsChanged: Subscription;
@Input()
todo: Todo;
@HostBinding('class.selected')
selected: boolean;
@HostBinding('class.completed')
completed: boolean;
@HostBinding('class.move-disabled')
moveDisabled: boolean;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {TodoService} _todoService
* @param {ActivatedRoute} _activatedRoute
*/
constructor(
private todoService: TodoService,
private route: ActivatedRoute
private _todoService: TodoService,
private _activatedRoute: ActivatedRoute
)
{
// Disable move if path is not /all
if ( route.snapshot.url[0].path !== 'all' )
if ( _activatedRoute.snapshot.url[0].path !== 'all' )
{
this.moveDisabled = true;
}
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Set the initial values
this.todo = new Todo(this.todo);
this.completed = this.todo.completed;
// Subscribe to update on selected todo change
this.onSelectedTodosChanged =
this.todoService.onSelectedTodosChanged
this._todoService.onSelectedTodosChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(selectedTodos => {
this.selected = false;
@ -60,53 +84,65 @@ export class FuseTodoListItemComponent implements OnInit, OnDestroy
});
// Subscribe to update on tag change
this.onTagsChanged =
this.todoService.onTagsChanged
this._todoService.onTagsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(tags => {
this.tags = tags;
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onSelectedTodosChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
onSelectedChange()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* On selected change
*/
onSelectedChange(): void
{
this.todoService.toggleSelectedTodo(this.todo.id);
this._todoService.toggleSelectedTodo(this.todo.id);
}
/**
* Toggle star
*/
toggleStar(event)
toggleStar(event): void
{
event.stopPropagation();
this.todo.toggleStar();
this.todoService.updateTodo(this.todo);
this._todoService.updateTodo(this.todo);
}
/**
* Toggle Important
*/
toggleImportant(event)
toggleImportant(event): void
{
event.stopPropagation();
this.todo.toggleImportant();
this.todoService.updateTodo(this.todo);
this._todoService.updateTodo(this.todo);
}
/**
* Toggle Completed
*/
toggleCompleted(event)
toggleCompleted(event): void
{
event.stopPropagation();
this.todo.toggleCompleted();
this.todoService.updateTodo(this.todo);
this._todoService.updateTodo(this.todo);
}
}

View File

@ -2,7 +2,7 @@
<span class="no-todos-text hint-text">There are no todos!</span>
</div>
<div class="todo-list" ngxDroppable [model]="todos" (out)="onDrop($event)" *fuseIfOnDom [@animateStagger]="{value:'50'}">
<fuse-todo-list-item class="todo-list-item has-handle"
<todo-list-item class="todo-list-item has-handle"
*ngFor="let todo of todos" [todo]="todo"
ngxDraggable
[model]="todo"
@ -10,5 +10,5 @@
[ngClass]="{'current-todo':todo?.id == currentTodo?.id}"
matRipple
[@animate]="{value:'*',params:{y:'100%'}}">
</fuse-todo-list-item>
</todo-list-item>
</div>

View File

@ -1,47 +1,64 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Location } from '@angular/common';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { fuseAnimations } from '@fuse/animations';
import { Todo } from '../todo.model';
import { TodoService } from '../todo.service';
import { Todo } from 'app/main/apps/todo/todo.model';
import { TodoService } from 'app/main/apps/todo/todo.service';
import { takeUntil } from 'rxjs/operators';
@Component({
selector : 'fuse-todo-list',
selector : 'todo-list',
templateUrl: './todo-list.component.html',
styleUrls : ['./todo-list.component.scss'],
animations : fuseAnimations
})
export class FuseTodoListComponent implements OnInit, OnDestroy
export class TodoListComponent implements OnInit, OnDestroy
{
todos: Todo[];
currentTodo: Todo;
onTodosChanged: Subscription;
onCurrentTodoChanged: Subscription;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {ActivatedRoute} _activatedRoute
* @param {TodoService} _todoService
* @param {Location} _location
*/
constructor(
private route: ActivatedRoute,
private todoService: TodoService,
private location: Location
private _activatedRoute: ActivatedRoute,
private _todoService: TodoService,
private _location: Location
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to update todos on changes
this.onTodosChanged =
this.todoService.onTodosChanged
this._todoService.onTodosChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(todos => {
this.todos = todos;
});
// Subscribe to update current todo on changes
this.onCurrentTodoChanged =
this.todoService.onCurrentTodoChanged
this._todoService.onCurrentTodoChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(currentTodo => {
if ( !currentTodo )
{
@ -49,20 +66,20 @@ export class FuseTodoListComponent implements OnInit, OnDestroy
this.currentTodo = null;
// Handle the location changes
const tagHandle = this.route.snapshot.params.tagHandle,
filterHandle = this.route.snapshot.params.filterHandle;
const tagHandle = this._activatedRoute.snapshot.params.tagHandle,
filterHandle = this._activatedRoute.snapshot.params.filterHandle;
if ( tagHandle )
{
this.location.go('apps/todo/tag/' + tagHandle);
this._location.go('apps/todo/tag/' + tagHandle);
}
else if ( filterHandle )
{
this.location.go('apps/todo/filter/' + filterHandle);
this._location.go('apps/todo/filter/' + filterHandle);
}
else
{
this.location.go('apps/todo/all');
this._location.go('apps/todo/all');
}
}
else
@ -72,23 +89,37 @@ export class FuseTodoListComponent implements OnInit, OnDestroy
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onTodosChanged.unsubscribe();
this.onCurrentTodoChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Read todo
*
* @param todoId
*/
readTodo(todoId)
readTodo(todoId): void
{
// Set current todo
this.todoService.setCurrentTodo(todoId);
this._todoService.setCurrentTodo(todoId);
}
onDrop(ev)
/**
* On drop
*
* @param ev
*/
onDrop(ev): void
{
}

View File

@ -9,7 +9,7 @@
<!-- SIDENAV -->
<mat-sidenav class="sidenav" position="start" opened="true" mode="side"
fuseMatSidenavHelper="carded-left-sidenav" mat-is-locked-open="gt-md">
<fuse-todo-main-sidenav></fuse-todo-main-sidenav>
<todo-main-sidenav></todo-main-sidenav>
</mat-sidenav>
<!-- / SIDENAV -->
@ -73,7 +73,7 @@
</div>
<div *ngIf="currentTodo" fxHide.gt-lg>
<button mat-icon-button (click)="deSelectCurrentTodo()">
<button mat-icon-button (click)="deselectCurrentTodo()">
<mat-icon>arrow_back</mat-icon>
</button>
</div>
@ -84,9 +84,9 @@
<!-- CONTENT -->
<div class="content" fxFlexAlign="row">
<fuse-todo-list fusePerfectScrollbar fxFlex></fuse-todo-list>
<todo-list fusePerfectScrollbar fxFlex></todo-list>
<fuse-todo-details fusePerfectScrollbar fxFlex></fuse-todo-details>
<todo-details fusePerfectScrollbar fxFlex></todo-details>
</div>
<!-- / CONTENT -->

View File

@ -39,16 +39,16 @@
@include media-breakpoint-down(lg) {
fuse-todo-list {
todo-list {
border-right: 0;
}
fuse-todo-list,
fuse-todo-details {
todo-list,
todo-details {
flex: 1 0 100%;
}
fuse-todo-details {
todo-details {
display: none !important;
}
@ -64,11 +64,11 @@
.content {
fuse-todo-list {
todo-list {
display: none !important;
}
fuse-todo-details {
todo-details {
display: flex !important;
}
}

View File

@ -1,21 +1,20 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations';
import { Todo } from './todo.model';
import { TodoService } from './todo.service';
import { Todo } from 'app/main/apps/todo/todo.model';
import { TodoService } from 'app/main/apps/todo/todo.service';
@Component({
selector : 'fuse-todo',
selector : 'todo',
templateUrl: './todo.component.html',
styleUrls : ['./todo.component.scss'],
animations : fuseAnimations
})
export class FuseTodoComponent implements OnInit, OnDestroy
export class TodoComponent implements OnInit, OnDestroy
{
hasSelectedTodos: boolean;
isIndeterminate: boolean;
@ -24,49 +23,68 @@ export class FuseTodoComponent implements OnInit, OnDestroy
searchInput: FormControl;
currentTodo: Todo;
onSelectedTodosChanged: Subscription;
onFiltersChanged: Subscription;
onTagsChanged: Subscription;
onCurrentTodoChanged: Subscription;
// Private
private _unsubscribeAll: Subject<any>;
constructor(private todoService: TodoService)
/**
* Constructor
*
* @param {TodoService} _todoService
*/
constructor(
private _todoService: TodoService
)
{
// Set the defaults
this.searchInput = new FormControl('');
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.onSelectedTodosChanged =
this.todoService.onSelectedTodosChanged
this._todoService.onSelectedTodosChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(selectedTodos => {
setTimeout(() => {
this.hasSelectedTodos = selectedTodos.length > 0;
this.isIndeterminate = (selectedTodos.length !== this.todoService.todos.length && selectedTodos.length > 0);
this.isIndeterminate = (selectedTodos.length !== this._todoService.todos.length && selectedTodos.length > 0);
}, 0);
});
this.onFiltersChanged =
this.todoService.onFiltersChanged
this._todoService.onFiltersChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(folders => {
this.filters = this.todoService.filters;
this.filters = this._todoService.filters;
});
this.onTagsChanged =
this.todoService.onTagsChanged
this._todoService.onTagsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(tags => {
this.tags = this.todoService.tags;
this.tags = this._todoService.tags;
});
this.searchInput.valueChanges.pipe(
this.searchInput.valueChanges
.pipe(
takeUntil(this._unsubscribeAll),
debounceTime(300),
distinctUntilChanged()
).subscribe(searchText => {
this.todoService.onSearchTextChanged.next(searchText);
)
.subscribe(searchText => {
this._todoService.onSearchTextChanged.next(searchText);
});
this.onCurrentTodoChanged =
this.todoService.onCurrentTodoChanged
this._todoService.onCurrentTodoChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(([currentTodo, formType]) => {
if ( !currentTodo )
{
@ -79,36 +97,62 @@ export class FuseTodoComponent implements OnInit, OnDestroy
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onSelectedTodosChanged.unsubscribe();
this.onFiltersChanged.unsubscribe();
this.onTagsChanged.unsubscribe();
this.onCurrentTodoChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
deSelectCurrentTodo()
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Deselect current todo
*/
deselectCurrentTodo(): void
{
this.todoService.onCurrentTodoChanged.next([null, null]);
this._todoService.onCurrentTodoChanged.next([null, null]);
}
toggleSelectAll()
/**
* Toggle select all
*/
toggleSelectAll(): void
{
this.todoService.toggleSelectAll();
this._todoService.toggleSelectAll();
}
selectTodos(filterParameter?, filterValue?)
/**
* Select todos
*
* @param filterParameter
* @param filterValue
*/
selectTodos(filterParameter?, filterValue?): void
{
this.todoService.selectTodos(filterParameter, filterValue);
this._todoService.selectTodos(filterParameter, filterValue);
}
deselectTodos()
/**
* Deselect todos
*/
deselectTodos(): void
{
this.todoService.deselectTodos();
this._todoService.deselectTodos();
}
toggleTagOnSelectedTodos(tagId)
/**
* Toggle tag on selected todos
*
* @param tagId
*/
toggleTagOnSelectedTodos(tagId): void
{
this.todoService.toggleTagOnSelectedTodos(tagId);
this._todoService.toggleTagOnSelectedTodos(tagId);
}
}

View File

@ -18,6 +18,11 @@ export class Todo
}
];
/**
* Constructor
*
* @param todo
*/
constructor(todo)
{
{
@ -34,22 +39,34 @@ export class Todo
}
}
toggleStar()
/**
* Toggle star
*/
toggleStar(): void
{
this.starred = !this.starred;
}
toggleImportant()
/**
* Toggle important
*/
toggleImportant(): void
{
this.important = !this.important;
}
toggleCompleted()
/**
* Toggle completed
*/
toggleCompleted(): void
{
this.completed = !this.completed;
}
toggleDeleted()
/**
* Toggle deleted
*/
toggleDeleted(): void
{
this.deleted = !this.deleted;
}

View File

@ -1,58 +1,56 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { MatButtonModule, MatCheckboxModule, MatDatepickerModule, MatFormFieldModule, MatIconModule, MatInputModule, MatMenuModule, MatRippleModule, MatSelectModule, MatSidenavModule } from '@angular/material';
import { NgxDnDModule } from '@swimlane/ngx-dnd';
import { FuseSharedModule } from '@fuse/shared.module';
import { TodoService } from './todo.service';
import { FuseTodoComponent } from './todo.component';
import { FuseTodoMainSidenavComponent } from './sidenavs/main/main-sidenav.component';
import { FuseTodoListItemComponent } from './todo-list/todo-list-item/todo-list-item.component';
import { FuseTodoListComponent } from './todo-list/todo-list.component';
import { FuseTodoDetailsComponent } from './todo-details/todo-details.component';
import { TodoService } from 'app/main/apps/todo/todo.service';
import { TodoComponent } from 'app/main/apps/todo/todo.component';
import { TodoMainSidenavComponent } from 'app/main/apps/todo/sidenavs/main/main-sidenav.component';
import { TodoListItemComponent } from 'app/main/apps/todo/todo-list/todo-list-item/todo-list-item.component';
import { TodoListComponent } from 'app/main/apps/todo/todo-list/todo-list.component';
import { TodoDetailsComponent } from 'app/main/apps/todo/todo-details/todo-details.component';
const routes: Routes = [
{
path : 'all',
component: FuseTodoComponent,
component: TodoComponent,
resolve : {
todo: TodoService
}
},
{
path : 'all/:todoId',
component: FuseTodoComponent,
component: TodoComponent,
resolve : {
todo: TodoService
}
},
{
path : 'tag/:tagHandle',
component: FuseTodoComponent,
component: TodoComponent,
resolve : {
todo: TodoService
}
},
{
path : 'tag/:tagHandle/:todoId',
component: FuseTodoComponent,
component: TodoComponent,
resolve : {
todo: TodoService
}
},
{
path : 'filter/:filterHandle',
component: FuseTodoComponent,
component: TodoComponent,
resolve : {
todo: TodoService
}
},
{
path : 'filter/:filterHandle/:todoId',
component: FuseTodoComponent,
component: TodoComponent,
resolve : {
todo: TodoService
}
@ -65,11 +63,11 @@ const routes: Routes = [
@NgModule({
declarations: [
FuseTodoComponent,
FuseTodoMainSidenavComponent,
FuseTodoListItemComponent,
FuseTodoListComponent,
FuseTodoDetailsComponent
TodoComponent,
TodoMainSidenavComponent,
TodoListItemComponent,
TodoListComponent,
TodoDetailsComponent
],
imports : [
RouterModule.forChild(routes),
@ -87,7 +85,7 @@ const routes: Routes = [
NgxDnDModule,
FuseSharedModule,
FuseSharedModule
],
providers : [
TodoService

View File

@ -6,7 +6,7 @@ import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { FuseUtils } from '@fuse/utils';
import { Todo } from './todo.model';
import { Todo } from 'app/main/apps/todo/todo.model';
@Injectable()
export class TodoService implements Resolve<any>
@ -14,31 +14,45 @@ export class TodoService implements Resolve<any>
todos: Todo[];
selectedTodos: Todo[];
currentTodo: Todo;
searchText = '';
searchText: string;
filters: any[];
tags: any[];
routeParams: any;
onTodosChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onSelectedTodosChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onCurrentTodoChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onFiltersChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onTagsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onSearchTextChanged: BehaviorSubject<any> = new BehaviorSubject('');
onNewTodoClicked: Subject<any> = new Subject();
onTodosChanged: BehaviorSubject<any>;
onSelectedTodosChanged: BehaviorSubject<any>;
onCurrentTodoChanged: BehaviorSubject<any>;
onFiltersChanged: BehaviorSubject<any>;
onTagsChanged: BehaviorSubject<any>;
onSearchTextChanged: BehaviorSubject<any>;
onNewTodoClicked: Subject<any>;
/**
* Constructor
*
* @param {HttpClient} _httpClient
* @param {Location} _location
*/
constructor(
private http: HttpClient,
private location: Location // Set current todo
private _httpClient: HttpClient,
private _location: Location
)
{
// Set the defaults
this.selectedTodos = [];
this.searchText = '';
this.onTodosChanged = new BehaviorSubject([]);
this.onSelectedTodosChanged = new BehaviorSubject([]);
this.onCurrentTodoChanged = new BehaviorSubject([]);
this.onFiltersChanged = new BehaviorSubject([]);
this.onTagsChanged = new BehaviorSubject([]);
this.onSearchTextChanged = new BehaviorSubject('');
this.onNewTodoClicked = new Subject();
}
/**
* Resolve
* Resolver
*
* @param {ActivatedRouteSnapshot} route
* @param {RouterStateSnapshot} state
* @returns {Observable<any> | Promise<any> | any}
@ -85,12 +99,13 @@ export class TodoService implements Resolve<any>
/**
* Get all filters
*
* @returns {Promise<any>}
*/
getFilters(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/todo-filters')
this._httpClient.get('api/todo-filters')
.subscribe((response: any) => {
this.filters = response;
this.onFiltersChanged.next(this.filters);
@ -101,12 +116,13 @@ export class TodoService implements Resolve<any>
/**
* Get all tags
*
* @returns {Promise<any>}
*/
getTags(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/todo-tags')
this._httpClient.get('api/todo-tags')
.subscribe((response: any) => {
this.tags = response;
this.onTagsChanged.next(this.tags);
@ -117,6 +133,7 @@ export class TodoService implements Resolve<any>
/**
* Get todos
*
* @returns {Promise<Todo[]>}
*/
getTodos(): Promise<Todo[]>
@ -136,6 +153,7 @@ export class TodoService implements Resolve<any>
/**
* Get todos by params
*
* @param handle
* @returns {Promise<Todo[]>}
*/
@ -143,7 +161,7 @@ export class TodoService implements Resolve<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/todo-todos')
this._httpClient.get('api/todo-todos')
.subscribe((todos: any) => {
this.todos = todos.map(todo => {
return new Todo(todo);
@ -160,6 +178,7 @@ export class TodoService implements Resolve<any>
/**
* Get todos by filter
*
* @param handle
* @returns {Promise<Todo[]>}
*/
@ -175,7 +194,7 @@ export class TodoService implements Resolve<any>
return new Promise((resolve, reject) => {
this.http.get('api/todo-todos?' + param)
this._httpClient.get('api/todo-todos?' + param)
.subscribe((todos: any) => {
this.todos = todos.map(todo => {
@ -194,18 +213,19 @@ export class TodoService implements Resolve<any>
/**
* Get todos by tag
*
* @param handle
* @returns {Promise<Todo[]>}
*/
getTodosByTag(handle): Promise<Todo[]>
{
return new Promise((resolve, reject) => {
this.http.get('api/todo-tags?handle=' + handle)
this._httpClient.get('api/todo-tags?handle=' + handle)
.subscribe((tags: any) => {
const tagId = tags[0].id;
this.http.get('api/todo-todos?tags=' + tagId)
this._httpClient.get('api/todo-todos?tags=' + tagId)
.subscribe((todos: any) => {
this.todos = todos.map(todo => {
@ -225,9 +245,10 @@ export class TodoService implements Resolve<any>
/**
* Toggle selected todo by id
*
* @param id
*/
toggleSelectedTodo(id)
toggleSelectedTodo(id): void
{
// First, check if we already have that todo as selected...
if ( this.selectedTodos.length > 0 )
@ -267,7 +288,7 @@ export class TodoService implements Resolve<any>
/**
* Toggle select all
*/
toggleSelectAll()
toggleSelectAll(): void
{
if ( this.selectedTodos.length > 0 )
{
@ -280,7 +301,13 @@ export class TodoService implements Resolve<any>
}
selectTodos(filterParameter?, filterValue?)
/**
* Select todos
*
* @param filterParameter
* @param filterValue
*/
selectTodos(filterParameter?, filterValue?): void
{
this.selectedTodos = [];
@ -302,7 +329,10 @@ export class TodoService implements Resolve<any>
this.onSelectedTodosChanged.next(this.selectedTodos);
}
deselectTodos()
/**
* Deselect todos
*/
deselectTodos(): void
{
this.selectedTodos = [];
@ -312,9 +342,10 @@ export class TodoService implements Resolve<any>
/**
* Set current todo by id
*
* @param id
*/
setCurrentTodo(id)
setCurrentTodo(id): void
{
this.currentTodo = this.todos.find(todo => {
return todo.id === id;
@ -327,30 +358,37 @@ export class TodoService implements Resolve<any>
if ( tagHandle )
{
this.location.go('apps/todo/tag/' + tagHandle + '/' + id);
this._location.go('apps/todo/tag/' + tagHandle + '/' + id);
}
else if ( filterHandle )
{
this.location.go('apps/todo/filter/' + filterHandle + '/' + id);
this._location.go('apps/todo/filter/' + filterHandle + '/' + id);
}
else
{
this.location.go('apps/todo/all/' + id);
this._location.go('apps/todo/all/' + id);
}
}
/**
* Toggle tag on selected todos
*
* @param tagId
*/
toggleTagOnSelectedTodos(tagId)
toggleTagOnSelectedTodos(tagId): void
{
this.selectedTodos.map(todo => {
this.toggleTagOnTodo(tagId, todo);
});
}
toggleTagOnTodo(tagId, todo)
/**
* Toggle tag on todo
*
* @param tagId
* @param todo
*/
toggleTagOnTodo(tagId, todo): void
{
const index = todo.tags.indexOf(tagId);
@ -366,7 +404,14 @@ export class TodoService implements Resolve<any>
this.updateTodo(todo);
}
hasTag(tagId, todo)
/**
* Has tag?
*
* @param tagId
* @param todo
* @returns {boolean}
*/
hasTag(tagId, todo): any
{
if ( !todo.tags )
{
@ -378,14 +423,15 @@ export class TodoService implements Resolve<any>
/**
* Update the todo
*
* @param todo
* @returns {Promise<any>}
*/
updateTodo(todo)
updateTodo(todo): any
{
return new Promise((resolve, reject) => {
this.http.post('api/todo-todos/' + todo.id, {...todo})
this._httpClient.post('api/todo-todos/' + todo.id, {...todo})
.subscribe(response => {
this.getTodos().then(todos => {

View File

@ -91,8 +91,7 @@ const routes = [
FuseCountdownModule,
FuseHighlightModule,
FuseMaterialColorPickerModule,
FuseWidgetModule,
FuseAngularMaterialModule
FuseWidgetModule
]
})
export class ComponentsModule

View File

@ -90,7 +90,7 @@
templateUrl: './mail.component.html',
styleUrls : ['./mail.component.scss']
})
export class FuseMailComponent
export class MailComponent
{
constructor(private translationLoader: FuseTranslationLoaderService)
{

View File

@ -1,26 +1,38 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseConfigService } from '@fuse/services/config.service';
import { fuseAnimations } from '@fuse/animations';
@Component({
selector : 'fuse-coming-soon',
selector : 'coming-soon',
templateUrl: './coming-soon.component.html',
styleUrls : ['./coming-soon.component.scss'],
animations : fuseAnimations
})
export class FuseComingSoonComponent implements OnInit
export class ComingSoonComponent implements OnInit, OnDestroy
{
comingSoonForm: FormGroup;
comingSoonFormErrors: any;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {FuseConfigService} _fuseConfigService
* @param {FormBuilder} _formBuilder
*/
constructor(
private fuseConfig: FuseConfigService,
private formBuilder: FormBuilder
private _fuseConfigService: FuseConfigService,
private _formBuilder: FormBuilder
)
{
this.fuseConfig.config = {
// Configure the layout
this._fuseConfigService.config = {
layout: {
navigation: 'none',
toolbar : 'none',
@ -28,23 +40,53 @@ export class FuseComingSoonComponent implements OnInit
}
};
// Set the defaults
this.comingSoonFormErrors = {
email: {}
};
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.comingSoonForm = this.formBuilder.group({
this.comingSoonForm = this._formBuilder.group({
email: ['', [Validators.required, Validators.email]]
});
this.comingSoonForm.valueChanges.subscribe(() => {
this.comingSoonForm.valueChanges
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
this.onRegisterFormValuesChanged();
});
}
onRegisterFormValuesChanged()
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* On form values changed
*/
onRegisterFormValuesChanged(): void
{
for ( const field in this.comingSoonFormErrors )
{

View File

@ -6,18 +6,18 @@ import { MatButtonModule, MatFormFieldModule, MatInputModule } from '@angular/ma
import { FuseSharedModule } from '@fuse/shared.module';
import { FuseCountdownModule } from '@fuse/components';
import { FuseComingSoonComponent } from './coming-soon.component';
import { ComingSoonComponent } from 'app/main/pages/coming-soon/coming-soon.component';
const routes = [
{
path : 'coming-soon',
component: FuseComingSoonComponent
component: ComingSoonComponent
}
];
@NgModule({
declarations: [
FuseComingSoonComponent
ComingSoonComponent
],
imports : [
RouterModule.forChild(routes),

View File

@ -7,13 +7,19 @@ import { FuseConfigService } from '@fuse/services/config.service';
templateUrl: './error-404.component.html',
styleUrls : ['./error-404.component.scss']
})
export class FuseError404Component
export class Error404Component
{
/**
* Constructor
*
* @param {FuseConfigService} _fuseConfigService
*/
constructor(
private fuseConfig: FuseConfigService
private _fuseConfigService: FuseConfigService
)
{
this.fuseConfig.config = {
// Configure the layout
this._fuseConfigService.config = {
layout: {
navigation: 'none',
toolbar : 'none',

View File

@ -1,22 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { MatIconModule } from '@angular/material';
import { FuseSharedModule } from '@fuse/shared.module';
import { FuseError404Component } from './error-404.component';
import { Error404Component } from 'app/main/pages/errors/404/error-404.component';
const routes = [
{
path : 'errors/error-404',
component: FuseError404Component
component: Error404Component
}
];
@NgModule({
declarations: [
FuseError404Component
Error404Component
],
imports : [
RouterModule.forChild(routes),

View File

@ -3,16 +3,17 @@ import { Component } from '@angular/core';
import { FuseConfigService } from '@fuse/services/config.service';
@Component({
selector : 'fuse-error-500',
selector : 'error-500',
templateUrl: './error-500.component.html',
styleUrls : ['./error-500.component.scss']
})
export class FuseError500Component
export class Error500Component
{
constructor(
private fuseConfig: FuseConfigService
)
{
// Configure the layout
this.fuseConfig.config = {
layout: {
navigation: 'none',

View File

@ -3,18 +3,18 @@ import { RouterModule } from '@angular/router';
import { FuseSharedModule } from '@fuse/shared.module';
import { FuseError500Component } from './error-500.component';
import { Error500Component } from 'app/main/pages/errors/500/error-500.component';
const routes = [
{
path : 'errors/error-500',
component: FuseError500Component
component: Error500Component
}
];
@NgModule({
declarations: [
FuseError500Component
Error500Component
],
imports : [
RouterModule.forChild(routes),

View File

@ -1,64 +1,107 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { FuseUtils } from '@fuse/utils';
import { FaqService } from './faq.service';
import { FaqService } from 'app/main/pages/faq/faq.service';
@Component({
selector : 'fuse-faq',
selector : 'faq',
templateUrl: './faq.component.html',
styleUrls : ['./faq.component.scss']
})
export class FuseFaqComponent implements OnInit, OnDestroy
export class FaqComponent implements OnInit, OnDestroy
{
faqs: any;
faqsFiltered: any;
step = 0;
searchInput;
onFaqsChanged: Subscription;
step: number;
searchInput: any;
constructor(private faqService: FaqService)
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {FaqService} _faqService
*/
constructor(
private _faqService: FaqService
)
{
// Set the defaults
this.searchInput = new FormControl('');
this.step = 0;
// Set the private defaults
this._unsubscribeAll = new Subject();
}
ngOnInit()
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this.onFaqsChanged =
this.faqService.onFaqsChanged
this._faqService.onFaqsChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(response => {
this.faqs = response;
this.faqsFiltered = response;
});
this.searchInput.valueChanges.pipe(
this.searchInput.valueChanges
.pipe(
takeUntil(this._unsubscribeAll),
debounceTime(300),
distinctUntilChanged()
).subscribe(searchText => {
)
.subscribe(searchText => {
this.faqsFiltered = FuseUtils.filterArrayByString(this.faqs, searchText);
});
}
ngOnDestroy()
/**
* On destroy
*/
ngOnDestroy(): void
{
this.onFaqsChanged.unsubscribe();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
setStep(index: number)
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Set step
*
* @param {number} index
*/
setStep(index: number): void
{
this.step = index;
}
nextStep()
/**
* Next step
*/
nextStep(): void
{
this.step++;
}
prevStep()
/**
* Previous step
*/
prevStep(): void
{
this.step--;
}

View File

@ -5,13 +5,13 @@ import { MatExpansionModule, MatIconModule } from '@angular/material';
import { FuseSharedModule } from '@fuse/shared.module';
import { FaqService } from './faq.service';
import { FuseFaqComponent } from './faq.component';
import { FaqService } from 'app/main/pages/faq/faq.service';
import { FaqComponent } from 'app/main/pages/faq/faq.component';
const routes = [
{
path : 'faq',
component: FuseFaqComponent,
component: FaqComponent,
resolve : {
faq: FaqService
}
@ -20,7 +20,7 @@ const routes = [
@NgModule({
declarations: [
FuseFaqComponent
FaqComponent
],
imports : [
RouterModule.forChild(routes),

View File

@ -7,15 +7,24 @@ import { BehaviorSubject, Observable } from 'rxjs';
export class FaqService implements Resolve<any>
{
faqs: any;
onFaqsChanged: BehaviorSubject<any>;
onFaqsChanged: BehaviorSubject<any> = new BehaviorSubject({});
constructor(private http: HttpClient)
/**
* Constructor
*
* @param {HttpClient} _httpClient
*/
constructor(
private _httpClient: HttpClient
)
{
// Set the defaults
this.onFaqsChanged = new BehaviorSubject({});
}
/**
* Resolve
* Resolver
*
* @param {ActivatedRouteSnapshot} route
* @param {RouterStateSnapshot} state
* @returns {Observable<any> | Promise<any> | any}
@ -41,7 +50,7 @@ export class FaqService implements Resolve<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/faq')
this._httpClient.get('api/faq')
.subscribe((response: any) => {
this.faqs = response;
this.onFaqsChanged.next(this.faqs);

View File

@ -1,22 +1,52 @@
import { Component } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { InvoiceService } from '../invoice.service';
import { InvoiceService } from 'app/main/pages/invoices/invoice.service';
@Component({
selector : 'fuse-invoice-compact',
selector : 'invoice-compact',
templateUrl: './compact.component.html',
styleUrls : ['./compact.component.scss']
})
export class FuseInvoiceCompactComponent
export class InvoiceCompactComponent implements OnInit, OnDestroy
{
invoice: any;
constructor(private invoiceService: InvoiceService)
// Private
private _unsubscribeAll: Subject<any>;
constructor(
private _invoiceService: InvoiceService
)
{
this.invoiceService.invoiceOnChanged
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this._invoiceService.invoiceOnChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((invoice) => {
this.invoice = invoice;
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
}

View File

@ -3,13 +3,13 @@ import { RouterModule } from '@angular/router';
import { FuseSharedModule } from '@fuse/shared.module';
import { InvoiceService } from '../invoice.service';
import { FuseInvoiceCompactComponent } from './compact.component';
import { InvoiceService } from 'app/main/pages/invoices/invoice.service';
import { InvoiceCompactComponent } from 'app/main/pages/invoices/compact/compact.component';
const routes = [
{
path : 'invoices/compact',
component: FuseInvoiceCompactComponent,
component: InvoiceCompactComponent,
resolve : {
search: InvoiceService
}
@ -18,7 +18,7 @@ const routes = [
@NgModule({
declarations: [
FuseInvoiceCompactComponent
InvoiceCompactComponent
],
imports : [
RouterModule.forChild(routes),

View File

@ -3,19 +3,28 @@ import { HttpClient } from '@angular/common/http';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable()
export class InvoiceService implements Resolve<any>
{
invoice: any;
invoiceOnChanged: BehaviorSubject<any> = new BehaviorSubject({});
invoiceOnChanged: BehaviorSubject<any>;
constructor(private http: HttpClient)
/**
* Constructor
*
* @param {HttpClient} _httpClient
*/
constructor(
private _httpClient: HttpClient
)
{
// Set the defaults
this.invoiceOnChanged = new BehaviorSubject({});
}
/**
* Resolve
* Resolver
*
* @param {ActivatedRouteSnapshot} route
* @param {RouterStateSnapshot} state
* @returns {Observable<any> | Promise<any> | any}
@ -41,7 +50,7 @@ export class InvoiceService implements Resolve<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/invoice')
this._httpClient.get('api/invoice')
.subscribe((timeline: any) => {
this.invoice = timeline;
this.invoiceOnChanged.next(this.invoice);

View File

@ -1,22 +1,58 @@
import { Component } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { InvoiceService } from '../invoice.service';
import { InvoiceService } from 'app/main/pages/invoices/invoice.service';
@Component({
selector : 'fuse-invoice-modern',
selector : 'invoice-modern',
templateUrl: './modern.component.html',
styleUrls : ['./modern.component.scss']
})
export class FuseInvoiceModernComponent
export class InvoiceModernComponent implements OnInit, OnDestroy
{
invoice: any;
constructor(private invoiceService: InvoiceService)
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {InvoiceService} _invoiceService
*/
constructor(
private _invoiceService: InvoiceService
)
{
this.invoiceService.invoiceOnChanged
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this._invoiceService.invoiceOnChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((invoice) => {
this.invoice = invoice;
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
}

View File

@ -3,13 +3,13 @@ import { RouterModule } from '@angular/router';
import { FuseSharedModule } from '@fuse/shared.module';
import { InvoiceService } from '../invoice.service';
import { FuseInvoiceModernComponent } from './modern.component';
import { InvoiceService } from 'app/main/pages/invoices/invoice.service';
import { InvoiceModernComponent } from 'app/main/pages/invoices/modern/modern.component';
const routes = [
{
path : 'invoices/modern',
component: FuseInvoiceModernComponent,
component: InvoiceModernComponent,
resolve : {
search: InvoiceService
}
@ -18,7 +18,7 @@ const routes = [
@NgModule({
declarations: [
FuseInvoiceModernComponent
InvoiceModernComponent
],
imports : [
RouterModule.forChild(routes),

View File

@ -2,16 +2,16 @@
<mat-toolbar matDialogTitle class="mat-accent m-0">
<mat-toolbar-row>
<span class="title dialog-title">{{data.article.title}}</span>
<span class="title dialog-title">{{_data.article.title}}</span>
</mat-toolbar-row>
</mat-toolbar>
<div mat-dialog-content class="p-24 m-0" fusePerfectScrollbar>
<div [innerHTML]="data.article.content"></div>
<div [innerHTML]="_data.article.content"></div>
</div>
<div mat-dialog-actions class="m-0 p-16" fxLayout="row" fxLayoutAlign="end center">
<button mat-button (click)="dialogRef.close()" class="mat-accent" aria-label="Close">
<button mat-button (click)="_matDialogRef.close()" class="mat-accent" aria-label="Close">
CLOSE
</button>
</div>

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