mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2025-01-10 04:25:08 +00:00
(Calendar App) Calendar app added.
This commit is contained in:
parent
0270405353
commit
ed06e26647
5
package-lock.json
generated
5
package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
|
@ -11,12 +11,14 @@ 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 : [
|
||||
FuseMdSidenavHelperDirective,
|
||||
FuseMdSidenavTogglerDirective
|
||||
FuseMdSidenavTogglerDirective,
|
||||
FuseConfirmDialogComponent
|
||||
],
|
||||
imports : [
|
||||
FlexLayoutModule,
|
||||
|
@ -25,7 +27,8 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
|||
FormsModule,
|
||||
FusePipesModule,
|
||||
PerfectScrollbarModule,
|
||||
ReactiveFormsModule
|
||||
ReactiveFormsModule,
|
||||
ColorPickerModule
|
||||
],
|
||||
exports : [
|
||||
FlexLayoutModule,
|
||||
|
@ -36,8 +39,10 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
|||
FuseMdSidenavTogglerDirective,
|
||||
FusePipesModule,
|
||||
PerfectScrollbarModule,
|
||||
ReactiveFormsModule
|
||||
]
|
||||
ReactiveFormsModule,
|
||||
ColorPickerModule
|
||||
],
|
||||
entryComponents: [FuseConfirmDialogComponent]
|
||||
})
|
||||
|
||||
export class SharedModule
|
||||
|
|
97
src/app/fuse-fake-db/calendar.ts
Normal file
97
src/app/fuse-fake-db/calendar.ts
Normal 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.'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
|
@ -1,6 +1,17 @@
|
|||
import { InMemoryDbService } from 'angular-in-memory-web-api';
|
||||
import { MailFakeDb } from './mail';
|
||||
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
|
||||
{
|
||||
|
@ -14,6 +25,7 @@ export class FuseFakeDbService implements InMemoryDbService
|
|||
'chat-contacts': ChatFakeDb.contacts,
|
||||
'chat-chats' : ChatFakeDb.chats,
|
||||
'chat-user' : ChatFakeDb.user,
|
||||
'calendar' : CalendarFakeDb.data
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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, {
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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) => {
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<p>
|
||||
event-detail works!
|
||||
</p>
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
|
@ -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">×</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>
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
139
src/app/main/apps/calendar/event-form/event-form.component.html
Normal file
139
src/app/main/apps/calendar/event-form/event-form.component.html
Normal 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>
|
|
@ -0,0 +1,12 @@
|
|||
.event-form-dialog {
|
||||
.mat-dialog-container {
|
||||
padding: 0;
|
||||
max-width: 720px;
|
||||
width: 720px;
|
||||
}
|
||||
}
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
75
src/app/main/apps/calendar/event.model.ts
Normal file
75
src/app/main/apps/calendar/event.model.ts
Normal 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 || ''
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user