(Calendar App) Calendar app added.

This commit is contained in:
mustafahlvc 2017-07-26 10:02:26 +03:00
parent 0270405353
commit ed06e26647
22 changed files with 890 additions and 175 deletions

5
package-lock.json generated
View File

@ -5929,6 +5929,11 @@
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=",
"dev": true
},
"ngx-color-picker": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-4.2.0.tgz",
"integrity": "sha512-xWFpvOc+0WOD2kppPDlN1q5p58jgQDgUSsier/xi1i0HaVuU+BgNCo7aFPAKHaovw0Gv1WWp5GPAdpjXdUe7KA=="
},
"ngx-perfect-scrollbar": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/ngx-perfect-scrollbar/-/ngx-perfect-scrollbar-4.5.2.tgz",

View File

@ -29,6 +29,7 @@
"core-js": "^2.4.1",
"firebase": "^4.1.3",
"hammerjs": "^2.0.8",
"ngx-color-picker": "^4.2.0",
"ngx-perfect-scrollbar": "^4.5.2",
"rxjs": "^5.4.2",
"zone.js": "^0.8.13"

View File

@ -0,0 +1,6 @@
<h1 md-dialog-title>Confirm</h1>
<div md-dialog-content>{{confirmMessage}}</div>
<div md-dialog-actions class="pt-24">
<button md-raised-button class="mat-accent mr-16" (click)="dialogRef.close(true)">Confirm</button>
<button md-button (click)="dialogRef.close(false)">Cancel</button>
</div>

View File

@ -0,0 +1,21 @@
import { Component, OnInit } from '@angular/core';
import { MdDialogRef } from '@angular/material';
@Component({
selector : 'fuse-confirm-dialog',
templateUrl: './confirm-dialog.component.html',
styleUrls : ['./confirm-dialog.component.scss']
})
export class FuseConfirmDialogComponent implements OnInit
{
public confirmMessage: string;
constructor(public dialogRef: MdDialogRef<FuseConfirmDialogComponent>)
{
}
ngOnInit()
{
}
}

View File

@ -11,23 +11,26 @@ import {
FuseMdSidenavTogglerDirective
} from '../directives/md-sidenav-helper/md-sidenav-helper.directive';
import { FusePipesModule } from '../pipes/pipes.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ColorPickerModule } from 'ngx-color-picker';
import { FuseConfirmDialogComponent } from '../components/confirm-dialog/confirm-dialog.component';
@NgModule({
declarations: [
declarations : [
FuseMdSidenavHelperDirective,
FuseMdSidenavTogglerDirective
FuseMdSidenavTogglerDirective,
FuseConfirmDialogComponent
],
imports : [
imports : [
FlexLayoutModule,
MaterialModule,
CommonModule,
FormsModule,
FusePipesModule,
PerfectScrollbarModule,
ReactiveFormsModule
ReactiveFormsModule,
ColorPickerModule
],
exports : [
exports : [
FlexLayoutModule,
MaterialModule,
CommonModule,
@ -36,8 +39,10 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
FuseMdSidenavTogglerDirective,
FusePipesModule,
PerfectScrollbarModule,
ReactiveFormsModule
]
ReactiveFormsModule,
ColorPickerModule
],
entryComponents: [FuseConfirmDialogComponent]
})
export class SharedModule

View File

@ -0,0 +1,97 @@
import {
startOfDay,
endOfDay,
subDays,
addDays,
endOfMonth,
isSameDay,
isSameMonth,
addHours
} from 'date-fns';
export class CalendarFakeDb
{
public static data = [
{
id : 'events',
data: [
{
start : subDays(startOfDay(new Date()), 1),
end : addDays(new Date(), 1),
title : 'A 3 day event',
allDay : false,
color : {
primary : '#ad2121',
secondary: '#FAE3E3'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
},
{
start : startOfDay(new Date()),
title : 'An event with no end date',
allDay : false,
color : {
primary : '#e3bc08',
secondary: '#FDF1BA'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
},
{
start : subDays(endOfMonth(new Date()), 3),
end : addDays(endOfMonth(new Date()), 3),
title : 'A long event that spans 2 months',
allDay : false,
color : {
primary : '#1e90ff',
secondary: '#D1E8FF'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
},
{
start : addHours(startOfDay(new Date()), 2),
end : new Date(),
title : 'A draggable and resizable event',
allDay : false,
color : {
primary : '#e3bc08',
secondary: '#FDF1BA'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
}
]
}
];
}

View File

@ -1,19 +1,31 @@
import { InMemoryDbService } from 'angular-in-memory-web-api';
import { MailFakeDb } from './mail';
import {ChatFakeDb} from './chat';
import { ChatFakeDb } from './chat';
import { CalendarFakeDb } from './calendar';
import {
startOfDay,
endOfDay,
subDays,
addDays,
endOfMonth,
isSameDay,
isSameMonth,
addHours
} from 'date-fns';
export class FuseFakeDbService implements InMemoryDbService
{
createDb()
{
return {
'mail-mails' : MailFakeDb.mails,
'mail-folders': MailFakeDb.folders,
'mail-filters': MailFakeDb.filters,
'mail-labels' : MailFakeDb.labels,
'mail-mails' : MailFakeDb.mails,
'mail-folders' : MailFakeDb.folders,
'mail-filters' : MailFakeDb.filters,
'mail-labels' : MailFakeDb.labels,
'chat-contacts': ChatFakeDb.contacts,
'chat-chats' : ChatFakeDb.chats,
'chat-user' : ChatFakeDb.user,
'calendar' : CalendarFakeDb.data
};
}

View File

@ -25,7 +25,9 @@
<button md-button class="mat-icon-button"
mwlCalendarToday
[(viewDate)]="viewDate"
(viewDateChange)="selectedDay = {date:$event}"
aria-label="Today" md-tooltip="today">
<!--(click)="selectedDay = viewDate"-->
<md-icon>today</md-icon>
</button>
@ -54,19 +56,20 @@
mwlCalendarPreviousView
[view]="view"
[(viewDate)]="viewDate"
(viewDateChange)="selectedDay = {date:$event}"
aria-label="Previous">
<md-icon>chevron_left</md-icon>
</button>
<div class="title">
<h3>{{ viewDate | calendarDate:(view + 'ViewTitle'):'en' }}</h3>
<!--{{calendarView.title}}-->
{{ viewDate | calendarDate:(view + 'ViewTitle'):'en' }}
</div>
<button md-button class="mat-icon-button arrow"
mwlCalendarNextView
[view]="view"
[(viewDate)]="viewDate"
(viewDateChange)="selectedDay = {date:$event}"
aria-label="Next">
<md-icon>chevron_right</md-icon>
</button>
@ -92,23 +95,28 @@
[refresh]="refresh"
[activeDayIsOpen]="activeDayIsOpen"
(dayClicked)="dayClicked($event.day)"
(eventClicked)="handleEvent('Clicked', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
(eventClicked)="editEvent('edit', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)"
(beforeViewRender)="beforeMonthViewRender($event)">
</mwl-calendar-month-view>
<mwl-calendar-week-view
*ngSwitchCase="'week'"
[viewDate]="viewDate"
(viewDateChange)="selectedDay = {date:$event}"
[events]="events"
[refresh]="refresh"
(eventClicked)="handleEvent('Clicked', $event.event)"
(dayClicked)="dayClicked($event.day)"
(eventClicked)="editEvent('edit', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-week-view>
<mwl-calendar-day-view
*ngSwitchCase="'day'"
[viewDate]="viewDate"
(viewDateChange)="selectedDay = {date:$event}"
[events]="events"
[refresh]="refresh"
(eventClicked)="handleEvent('Clicked', $event.event)"
(dayClicked)="dayClicked($event.day)"
(eventClicked)="editEvent('edit', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-day-view>
</div>

View File

@ -1,5 +1,179 @@
@import "src/app/core/scss/fuse";
@import "node_modules/angular-calendar/scss/angular-calendar";
.cal-month-view {
.cal-header {
.cal-cell {
font-weight: 500;
}
}
.cal-day-cell {
&.cal-open {
@include mat-elevation(3);
}
}
.cal-open-day-events {
background: whitesmoke;
box-shadow: inset 0 0 15px 0 rgba(0, 0, 0, 0.13);
padding: 0;
display: flex;
flex-direction: column;
> div {
padding: 0 16px;
margin: 8px 16px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: start;
background-color: white;
@include mat-elevation(1);
transition: box-shadow 300ms ease;
&:first-of-type {
margin-top: 24px;
}
&:last-of-type {
margin-bottom: 24px;
}
&:hover {
@include mat-elevation(3);
}
.cal-event {
top: 0;
margin: 0;
}
mwl-calendar-event-title {
flex: 1;
.cal-event-title {
display: block;
padding: 21px 24px;
line-height: 1;
text-decoration: none;
color: black;
}
}
mwl-calendar-event-actions {
.cal-event-actions {
display: flex;
flex-direction: row;
align-items: center;
.cal-event-action {
display: block;
line-height: 1;
padding: 8px;
}
}
}
}
}
}
.cal-week-view {
.cal-header > b {
font-weight: 500;
}
.cal-event {
display: flex;
flex-direction: row;
align-items: center;
mwl-calendar-event-title {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
order: 0;
.cal-event-title {
display: block;
//padding: 21px 24px;
line-height: 1;
text-decoration: none;
color: black;
}
}
mwl-calendar-event-actions {
order: 1;
.cal-event-actions {
display: flex;
flex-direction: row;
align-items: center;
.cal-event-action {
display: block;
line-height: 1;
padding: 8px;
}
}
}
}
}
.cal-day-view {
.cal-time {
font-weight: 500;
}
.cal-event {
display: flex;
flex-direction: row;
mwl-calendar-event-title {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
order: 0;
.cal-event-title {
display: block;
height: 26px;
line-height: 26px;
text-decoration: none;
color: black;
}
}
mwl-calendar-event-actions {
order: 1;
.cal-event-actions {
display: flex;
flex-direction: row;
align-items: center;
.cal-event-action {
display: block;
line-height: 1;
padding: 4px;
}
}
}
}
}
#calendar {
background: #FFFFFF;
height: 100%;
@ -104,6 +278,7 @@
font-size: 20px;
min-width: 160px;
text-align: center;
font-weight: 500;
}
}
}
@ -121,6 +296,8 @@
}
.content {
flex: 1;
overflow: auto;
padding: 24px;
}
}

View File

@ -1,41 +1,18 @@
import {
ChangeDetectionStrategy,
Component,
Inject,
OnInit,
TemplateRef,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { startOfDay, endOfDay, subDays, addDays, endOfMonth, isSameDay, isSameMonth, addHours } from 'date-fns';
import { ChangeDetectionStrategy, Component, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { CalendarEvent, CalendarEventAction, CalendarEventTimesChangedEvent } from 'angular-calendar';
import { MD_DIALOG_DATA, MdDialog, MdDialogRef } from '@angular/material';
import { EventDialogComponent } from './event-dialog/event-dialog.component';
import { MdDialog, MdDialogRef } from '@angular/material';
import { EventFormDialogComponent } from './event-form/event-form.component';
import { FormGroup } from '@angular/forms';
import { CalendarEventModel } from './event.model';
import { CalendarService } from './calendar.service';
import {
startOfDay,
endOfDay,
subDays,
addDays,
endOfMonth,
isSameDay,
isSameMonth,
addHours
} from 'date-fns';
const colors: any = {
red : {
primary : '#ad2121',
secondary: '#FAE3E3'
},
blue : {
primary : '#1e90ff',
secondary: '#D1E8FF'
},
yellow: {
primary : '#e3bc08',
secondary: '#FDF1BA'
}
};
CalendarEvent,
CalendarEventAction,
CalendarEventTimesChangedEvent,
CalendarMonthViewDay
} from 'angular-calendar';
import { FuseConfirmDialogComponent } from '../../../core/components/confirm-dialog/confirm-dialog.component';
@Component({
selector : 'fuse-calendar',
@ -54,7 +31,7 @@ export class CalendarComponent implements OnInit
events: CalendarEvent[];
actions: CalendarEventAction[];
public actions: CalendarEventAction[];
activeDayIsOpen: boolean;
@ -62,75 +39,106 @@ export class CalendarComponent implements OnInit
dialogRef: any;
constructor(public dialog: MdDialog)
confirmDialogRef: MdDialogRef<FuseConfirmDialogComponent>;
selectedDay: any;
constructor(public dialog: MdDialog,
public calendarService: CalendarService)
{
this.view = 'month';
this.viewDate = new Date();
this.activeDayIsOpen = true;
this.selectedDay = {date: startOfDay(new Date())};
this.actions = [
{
label : '<i class="material-icons s-16">edit</i>',
onClick: ({event}: { event: CalendarEvent }): void => {
this.handleEvent('Edited', event);
this.editEvent('edit', event);
}
},
{
label : '<i class="material-icons s-16">close</i>',
label : '<i class="material-icons s-16">delete</i>',
onClick: ({event}: { event: CalendarEvent }): void => {
this.events = this.events.filter(iEvent => iEvent !== event);
this.handleEvent('Deleted', event);
this.deleteEvent(event);
}
}
];
this.events = [
{
start : subDays(startOfDay(new Date()), 1),
end : addDays(new Date(), 1),
title : 'A 3 day event',
color : colors.red,
actions: this.actions
},
{
start : startOfDay(new Date()),
title : 'An event with no end date',
color : colors.yellow,
actions: this.actions
},
{
start: subDays(endOfMonth(new Date()), 3),
end : addDays(endOfMonth(new Date()), 3),
title: 'A long event that spans 2 months',
color: colors.blue
},
{
start : addHours(startOfDay(new Date()), 2),
end : new Date(),
title : 'A draggable and resizable event',
color : colors.yellow,
actions : this.actions,
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true
}
];
/**
* Get events from service/server
*/
this.setEvents();
}
ngOnInit()
{
/**
* Watch re-render-refresh for updating db
*/
this.refresh.subscribe(updateDB => {
// console.warn('REFRESH');
if ( updateDB )
{
// console.warn('UPDATE DB');
this.calendarService.updateEvents(this.events);
}
});
this.calendarService.onEventsUpdated.subscribe(events => {
this.setEvents();
this.refresh.next();
});
}
dayClicked({date, events}: { date: Date; events: CalendarEvent[] }): void
setEvents()
{
this.events = this.calendarService.events.map(item => {
item.actions = this.actions;
return new CalendarEventModel(item);
});
}
/**
* Before View Renderer
* @param {any} header
* @param {any} body
*/
beforeMonthViewRender({header, body})
{
// console.info('beforeMonthViewRender');
/**
* Get the selected day
*/
const _selectedDay = body.find((_day) => {
return _day.date.getTime() === this.selectedDay.date.getTime();
});
if ( _selectedDay )
{
/**
* Set selectedday style
* @type {string}
*/
_selectedDay.cssClass = 'mat-elevation-z3';
}
}
/**
* Day clicked
* @param {MonthViewDay} day
*/
dayClicked(day: CalendarMonthViewDay): void
{
const date: Date = day.date;
const events: CalendarEvent[] = day.events;
if ( isSameMonth(date, this.viewDate) )
{
if (
(isSameDay(this.viewDate, date) && this.activeDayIsOpen === true) ||
events.length === 0
)
if ( (isSameDay(this.viewDate, date) && this.activeDayIsOpen === true) || events.length === 0 )
{
this.activeDayIsOpen = false;
}
@ -140,48 +148,120 @@ export class CalendarComponent implements OnInit
this.viewDate = date;
}
}
}
eventTimesChanged({
event,
newStart,
newEnd
}: CalendarEventTimesChangedEvent): void
{
event.start = newStart;
event.end = newEnd;
this.handleEvent('Dropped or resized', event);
this.selectedDay = day;
this.refresh.next();
}
handleEvent(action: string, event: CalendarEvent): void
/**
* Event times changed
* Event dropped or resized
* @param {CalendarEvent} event
* @param {Date} newStart
* @param {Date} newEnd
*/
eventTimesChanged({event, newStart, newEnd}: CalendarEventTimesChangedEvent): void
{
console.log(event, action);
this.dialogRef = this.dialog.open(EventDialogComponent, {
data: {
event.start = newStart;
event.end = newEnd;
// console.warn('Dropped or resized', event);
this.refresh.next(true);
}
/**
* Delete Event
* @param event
*/
deleteEvent(event)
{
this.confirmDialogRef = this.dialog.open(FuseConfirmDialogComponent, {
disableClose: false
});
this.confirmDialogRef.componentInstance.confirmMessage = 'Are you sure you want to delete?';
this.confirmDialogRef.afterClosed().subscribe(result => {
if ( result )
{
const eventIndex = this.events.indexOf(event);
this.events.splice(eventIndex, 1);
this.refresh.next(true);
}
this.confirmDialogRef = null;
});
}
/**
* Edit Event
* @param {string} action
* @param {CalendarEvent} event
*/
editEvent(action: string, event: CalendarEvent)
{
const eventIndex = this.events.indexOf(event);
this.dialogRef = this.dialog.open(EventFormDialogComponent, {
panelClass: 'event-form-dialog',
data : {
event : event,
action: action
}
});
this.dialogRef.afterClosed().subscribe(result => {
console.info(result);
});
this.dialogRef.afterClosed()
.subscribe(response => {
if ( !response )
{
return;
}
const actionType: string = response[0];
const formData: FormGroup = response[1];
switch ( actionType )
{
/**
* Save
*/
case 'save':
this.events[eventIndex] = Object.assign(this.events[eventIndex], formData.getRawValue());
this.refresh.next(true);
break;
/**
* Delete
*/
case 'delete':
this.deleteEvent(event);
break;
}
});
}
/**
* Add Event
*/
addEvent(): void
{
this.events.push({
title : 'New event',
start : startOfDay(new Date()),
end : endOfDay(new Date()),
color : colors.red,
draggable: true,
resizable: {
beforeStart: true,
afterEnd : true
this.dialogRef = this.dialog.open(EventFormDialogComponent, {
panelClass: 'event-form-dialog',
data : {
action: 'new',
date : this.selectedDay.date
}
});
this.refresh.next();
this.dialogRef.afterClosed()
.subscribe((response: FormGroup) => {
if ( !response )
{
return;
}
const newEvent = response.getRawValue();
newEvent.actions = this.actions;
this.events.push(newEvent);
this.refresh.next(true);
});
}
}

View File

@ -4,7 +4,8 @@ import { RouterModule, Routes } from '@angular/router';
import { CalendarComponent } from './calendar.component';
import { CalendarService } from './calendar.service';
import { CalendarModule } from 'angular-calendar';
import { EventDialogComponent } from './event-dialog/event-dialog.component';
import { EventFormDialogComponent } from './event-form/event-form.component';
import { EventDetailDialogComponent } from './event-detail/event-detail.component';
const routes: Routes = [
{
@ -23,12 +24,13 @@ const routes: Routes = [
],
declarations : [
CalendarComponent,
EventDialogComponent,
EventFormDialogComponent,
EventDetailDialogComponent,
],
providers : [
CalendarService
],
entryComponents: [EventDialogComponent]
entryComponents: [EventFormDialogComponent, EventDetailDialogComponent]
})
export class FuseCalendarModule
{

View File

@ -3,21 +3,52 @@ import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/r
import { Observable } from 'rxjs/Observable';
import { Http } from '@angular/http';
import { Subject } from 'rxjs/Subject';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class CalendarService implements Resolve<any>
{
events: any;
onEventsUpdated = new Subject<any>();
constructor(private http: Http)
{
}
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
{
return new Promise((resolve, reject) => {
resolve();
Promise.all([
this.getEvents()
]).then(
([events]: [any]) => {
resolve();
},
reject
);
});
}
getEvents()
{
return new Promise((resolve, reject) => {
this.http.get('api/calendar/events')
.subscribe(response => {
this.events = response.json().data.data;
this.onEventsUpdated.next(this.events);
resolve(this.events);
}, reject);
});
}
updateEvents(events)
{
return new Promise((resolve, reject) => {
this.http.post('api/calendar/events', {id: 'events', data: [...events]})
.subscribe(response => {
this.getEvents();
}, reject);
});
}

View File

@ -0,0 +1,3 @@
<p>
event-detail works!
</p>

View File

@ -0,0 +1,19 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector : 'fuse-calendar-event-detail-dialog',
templateUrl: './event-detail.component.html',
styleUrls : ['./event-detail.component.scss']
})
export class EventDetailDialogComponent implements OnInit
{
constructor()
{
}
ngOnInit()
{
}
}

View File

@ -1,20 +0,0 @@
<h1 md-dialog-title>
<h5 class="modal-title">Event action occurred</h5>
<button type="button" class="close" (click)="dialogRef.close()">
<span aria-hidden="true">&times;</span>
</button>
</h1>
<div md-dialog-content>
<div>
Action:
<pre>{{ data.action }}</pre>
</div>
<div>
Event:
<pre>{{ data.event | json }}</pre>
</div>
</div>
<div md-dialog-actions>
<button md-button class="dialog-button" (click)="dialogRef.close('Option 1')">OPTION 1</button>
<button md-button class="dialog-button" (click)="dialogRef.close('Option 2')">OPTION 2</button>
</div>

View File

@ -1,22 +0,0 @@
import { Component, Inject, OnInit } from '@angular/core';
import { MD_DIALOG_DATA, MdDialogRef } from '@angular/material';
@Component({
selector : 'fuse-calendar-event-dialog',
templateUrl: './event-dialog.component.html',
styleUrls : ['./event-dialog.component.scss']
})
export class EventDialogComponent implements OnInit
{
constructor(private dialogRef: MdDialogRef<EventDialogComponent>,
@Inject(MD_DIALOG_DATA) private data: any)
{
console.log(data);
}
ngOnInit()
{
}
}

View File

@ -0,0 +1,139 @@
<md-toolbar md-dialog-title class="mat-accent m-0">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<span class="title dialog-title">{{dialogTitle}}</span>
<button md-button class="mat-icon-button"
(click)="dialogRef.close()"
aria-label="Close dialog">
<md-icon>close</md-icon>
</button>
</div>
</md-toolbar>
<div md-dialog-content class="p-24 m-0" perfect-scrollbar>
<form name="eventForm" [formGroup]="eventForm" class="event-form" fxLayout="column" fxFlex>
<md-input-container>
<input mdInput
name="title"
formControlName="title"
placeholder="Title"
required>
</md-input-container>
<div class="py-16" fxFlex="1 0 auto" fxLayout="row">
<md-slide-toggle
name="allDay"
formControlName="allDay"
class="mr-24"
aria-label="All day">
All Day
</md-slide-toggle>
</div>
<div class="py-16" fxFlex="1 0 auto" fxLayout="row" formGroupName="color">
<md-input-container class="mr-24">
<input mdInput
name="primary color"
formControlName="primary"
placeholder="Primary color"
[(colorPicker)]="event.color.primary"
[style.background]="event.color.primary"
(colorPickerChange)="event.color.primary = $event; eventForm.patchValue({color:{primary:$event}})"/>
</md-input-container>
<md-input-container>
<input mdInput
name="secondary color"
formControlName="secondary"
placeholder="Secondary color"
[(colorPicker)]="event.color.secondary"
[style.background]="event.color.secondary"
(colorPickerChange)="event.color.secondary = $event; eventForm.patchValue({color:{secondary:$event}})"/>
</md-input-container>
</div>
<div fxFlex="1 0 auto" fxLayout="row">
<md-input-container class="mr-24">
<input mdInput
name="start"
formControlName="start"
[mdDatepicker]="startDatePicker"
placeholder="Start Date">
<button mdSuffix [mdDatepickerToggle]="startDatePicker"></button>
</md-input-container>
<md-datepicker #startDatePicker></md-datepicker>
<md-input-container class="no-errors-spacer" flex md-no-float>
<input mdInput ng-model="calendarEvent.startTime" placeholder="Start Time">
</md-input-container>
</div>
<div fxFlex="1 0 auto" fxLayout="row">
<md-input-container class="mr-24">
<input mdInput
name="end"
formControlName="end"
[mdDatepicker]="endDatePicker"
placeholder="End Date">
<button mdSuffix [mdDatepickerToggle]="endDatePicker"></button>
</md-input-container>
<md-datepicker #endDatePicker></md-datepicker>
<md-input-container class="no-errors-spacer" flex md-no-float>
<input mdInput ng-model="calendarEvent.endTime" placeholder="End Time">
</md-input-container>
</div>
<md-input-container formGroupName="meta">
<input mdInput
name="location"
formControlName="location"
placeholder="Location">
</md-input-container>
<md-input-container formGroupName="meta">
<textarea mdInput
formControlName="notes"
placeholder="Notes"
md-maxlength="250"
max-rows="4">
</textarea>
</md-input-container>
</form>
</div>
<div md-dialog-actions class="m-0 p-16" fxLayout="row" fxLayoutAlign="space-between center">
<button *ngIf="action !=='edit'"
md-raised-button
(click)="dialogRef.close(eventForm)"
class="save-button mat-accent"
aria-label="SAVE">
SAVE
</button>
<button *ngIf="action ==='edit'"
md-raised-button
(click)="dialogRef.close(['save',eventForm])"
class="save-button mat-accent"
aria-label="SAVE">
SAVE
</button>
<button *ngIf="action ==='edit'"
md-button
class="mat-icon-button"
(click)="dialogRef.close(['delete',eventForm])"
aria-label="Delete"
md-tooltip="Delete">
<md-icon>delete</md-icon>
</button>
</div>

View File

@ -0,0 +1,12 @@
.event-form-dialog {
.mat-dialog-container {
padding: 0;
max-width: 720px;
width: 720px;
}
}
:host {
display: flex;
flex-direction: column;
}

View File

@ -0,0 +1,64 @@
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MD_DIALOG_DATA, MdDialogRef } from '@angular/material';
import { CalendarEvent } from 'angular-calendar';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
import 'rxjs/Rx';
import { CalendarEventModel } from '../event.model';
@Component({
selector : 'fuse-calendar-event-form-dialog',
templateUrl : './event-form.component.html',
styleUrls : ['./event-form.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class EventFormDialogComponent implements OnInit
{
event: CalendarEvent;
dialogTitle: string;
eventForm: FormGroup;
action: string;
constructor(public dialogRef: MdDialogRef<EventFormDialogComponent>,
@Inject(MD_DIALOG_DATA) private data: any,
private formBuilder: FormBuilder)
{
this.event = data.event;
this.action = data.action;
if ( this.action === 'edit' )
{
this.dialogTitle = this.event.title;
}
else
{
this.dialogTitle = 'New Event';
this.event = new CalendarEventModel({start: data.date, end: data.date});
}
this.eventForm = this.createEventForm();
}
ngOnInit()
{
}
createEventForm()
{
return new FormGroup({
title : new FormControl(this.event.title),
start : new FormControl(this.event.start),
end : new FormControl(this.event.end),
allDay: new FormControl(this.event.allDay),
color : this.formBuilder.group({
primary : new FormControl(this.event.color.primary),
secondary: new FormControl(this.event.color.secondary)
}),
meta :
this.formBuilder.group({
location: new FormControl(this.event.meta.location),
notes : new FormControl(this.event.meta.notes)
})
});
}
}

View File

@ -0,0 +1,75 @@
import {
CalendarEventAction
} from 'angular-calendar';
import {
startOfDay,
endOfDay,
subDays,
addDays,
endOfMonth,
isSameDay,
isSameMonth,
addHours
} from 'date-fns';
// import { CalendarEvent } from 'calendar-utils/dist/calendar-utils';
/*
export interface EventAction
{
label: string;
cssClass?: string;
onClick({event}: {
event: CalendarEvent;
}): any;
}*/
export class CalendarEventModel
{
start: Date;
end?: Date;
title: string;
color: {
primary: string;
secondary: string;
};
actions?: CalendarEventAction[];
allDay?: boolean;
cssClass?: string;
resizable?: {
beforeStart?: boolean;
afterEnd?: boolean;
};
draggable?: boolean;
meta?: {
location: string,
notes: string
};
constructor(data?)
{
data = data || {};
this.start = new Date(data.start) || startOfDay(new Date());
this.end = new Date(data.end) || endOfDay(new Date());
this.title = data.title || '';
this.color = {
primary : data.color && data.color.primary || '#1e90ff',
secondary: data.color && data.color.secondary || '#D1E8FF'
};
this.draggable = data.draggable || true;
this.resizable = {
beforeStart: data.resizable && data.resizable.beforeStart || true,
afterEnd : data.resizable && data.resizable.afterEnd || true
};
this.actions = data.actions || [];
this.allDay = data.allDay || false;
this.cssClass = data.cssClass || '';
this.meta = {
location: data.meta && data.meta.location || '',
notes : data.meta && data.meta.notes || ''
};
}
}