add month calendar
This commit is contained in:
parent
bee08c2092
commit
51788f2194
5
customer/app/package-lock.json
generated
5
customer/app/package-lock.json
generated
@ -5937,6 +5937,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
||||||
|
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
|
||||||
|
},
|
||||||
"move-concurrently": {
|
"move-concurrently": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
"@fortawesome/fontawesome-svg-core": "^1.2.19",
|
"@fortawesome/fontawesome-svg-core": "^1.2.19",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.9.0",
|
"@fortawesome/free-solid-svg-icons": "^5.9.0",
|
||||||
"bootstrap": "^4.3.1",
|
"bootstrap": "^4.3.1",
|
||||||
|
"moment": "^2.24.0",
|
||||||
"ngx-bootstrap": "^5.0.0",
|
"ngx-bootstrap": "^5.0.0",
|
||||||
"rxjs": "~6.4.0",
|
"rxjs": "~6.4.0",
|
||||||
"tslib": "^1.9.0",
|
"tslib": "^1.9.0",
|
||||||
|
|||||||
@ -1,23 +1,22 @@
|
|||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import {
|
import {
|
||||||
HttpRequest,
|
HTTP_INTERCEPTORS,
|
||||||
HttpResponse,
|
|
||||||
HttpHandler,
|
|
||||||
HttpEvent,
|
HttpEvent,
|
||||||
|
HttpHandler,
|
||||||
HttpInterceptor,
|
HttpInterceptor,
|
||||||
HTTP_INTERCEPTORS
|
HttpRequest,
|
||||||
|
HttpResponse
|
||||||
} from '@angular/common/http';
|
} from '@angular/common/http';
|
||||||
import {Observable, of, throwError} from 'rxjs';
|
import {Observable, of, throwError} from 'rxjs';
|
||||||
import {delay, mergeMap, materialize, dematerialize} from 'rxjs/operators';
|
import {delay, dematerialize, materialize, mergeMap} from 'rxjs/operators';
|
||||||
import {Event, EventType, Trainer} from "../services/event.service";
|
import {DayToDisplay, Event, EventType, Trainer} from "../services/event.service";
|
||||||
import {identifierModuleUrl} from "@angular/compiler";
|
import * as moment from "moment";
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
FAKE BACKEND
|
FAKE BACKEND
|
||||||
|
|
||||||
This will serve as a standalone backend with delayed response so that it can imitate a real backend - using
|
This will serve as a standalone backend with delayed response so that it can imitate a real backend - using
|
||||||
DELAYED OBSERVABLE
|
DELAYED OBSERVABLE
|
||||||
|
|
||||||
1. It will check the user credentails that come from "Authentication Service" during login
|
1. It will check the user credentails that come from "Authentication Service" during login
|
||||||
@ -66,8 +65,7 @@ export class FakeBackendInterceptor implements HttpInterceptor {
|
|||||||
name: "weight lift Trainer"
|
name: "weight lift Trainer"
|
||||||
};
|
};
|
||||||
|
|
||||||
let events: Event[] = [
|
let events: Event[] = [];
|
||||||
];
|
|
||||||
|
|
||||||
let id = 1000;
|
let id = 1000;
|
||||||
for (let dayIndex = 0; dayIndex < 28; dayIndex++) {
|
for (let dayIndex = 0; dayIndex < 28; dayIndex++) {
|
||||||
@ -75,7 +73,7 @@ export class FakeBackendInterceptor implements HttpInterceptor {
|
|||||||
for (let itemIndex = 0; itemIndex < 3; itemIndex++) {
|
for (let itemIndex = 0; itemIndex < 3; itemIndex++) {
|
||||||
|
|
||||||
id = id + 1;
|
id = id + 1;
|
||||||
let reservedAt = id % 2 ? this.createEventDate(0,1) : null;
|
let reservedAt = id % 2 ? this.createEventDate(0, 1) : null;
|
||||||
events.push(
|
events.push(
|
||||||
{
|
{
|
||||||
id: id,
|
id: id,
|
||||||
@ -85,7 +83,7 @@ export class FakeBackendInterceptor implements HttpInterceptor {
|
|||||||
trainer: [trainer1, trainer2][id % 2],
|
trainer: [trainer1, trainer2][id % 2],
|
||||||
eventType: eventTypes[id % eventTypes.length],
|
eventType: eventTypes[id % eventTypes.length],
|
||||||
reservedAt: reservedAt,
|
reservedAt: reservedAt,
|
||||||
reservationCount: id% 11,
|
reservationCount: id % 11,
|
||||||
seatCount: 10,
|
seatCount: 10,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -113,7 +111,7 @@ export class FakeBackendInterceptor implements HttpInterceptor {
|
|||||||
firstName: testUser.firstName,
|
firstName: testUser.firstName,
|
||||||
lastName: testUser.lastName,
|
lastName: testUser.lastName,
|
||||||
token: '0000-fake-jwt-token-0000'
|
token: '0000-fake-jwt-token-0000'
|
||||||
}
|
};
|
||||||
|
|
||||||
return of(new HttpResponse({status: 200, body}))
|
return of(new HttpResponse({status: 200, body}))
|
||||||
} else {
|
} else {
|
||||||
@ -161,6 +159,60 @@ export class FakeBackendInterceptor implements HttpInterceptor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (request.url.endsWith('/events/available') && request.method === 'GET') {
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
days: [],
|
||||||
|
events: []
|
||||||
|
};
|
||||||
|
moment.locale("hu");
|
||||||
|
let _moment = moment();
|
||||||
|
const today = _moment.startOf('day');
|
||||||
|
|
||||||
|
const startOfWeek = _moment.clone().startOf("week").startOf('day');
|
||||||
|
|
||||||
|
const nextDays :DayToDisplay[] = [];
|
||||||
|
for (let i = 0; i < 21; i++) {
|
||||||
|
let active = false;
|
||||||
|
let nextDay = startOfWeek.clone().add(i, 'd').startOf("day");
|
||||||
|
if (nextDay.isAfter(today) || nextDay.isSameOrAfter(today)) {
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
nextDays.push(
|
||||||
|
{
|
||||||
|
date: nextDay.toDate().getTime(),
|
||||||
|
active: active
|
||||||
|
} as DayToDisplay
|
||||||
|
);
|
||||||
|
}
|
||||||
|
data.days = nextDays;
|
||||||
|
|
||||||
|
nextDays.forEach(value => {
|
||||||
|
value.events = [];
|
||||||
|
const startOfDay = value.date
|
||||||
|
const endOfDay = moment(startOfDay).add(1,'d').toDate().getTime();
|
||||||
|
events.forEach( event => {
|
||||||
|
if ( event.start >= value.date && event.start < endOfDay){
|
||||||
|
value.events.push(event);
|
||||||
|
}
|
||||||
|
} )
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// const until = nextDays[nextDays.length - 1].toDate().getTime();
|
||||||
|
// const availableEvents = events.filter(value => {
|
||||||
|
// return value.start < until;
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// nextDays.forEach(value => {
|
||||||
|
// data.days.push(value.toDate().getTime());
|
||||||
|
// });
|
||||||
|
|
||||||
|
// data.events = availableEvents;
|
||||||
|
|
||||||
|
return of(new HttpResponse({status: 200, body: data}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (request.url.indexOf('/events') >= 0 && request.method === 'GET') {
|
if (request.url.indexOf('/events') >= 0 && request.method === 'GET') {
|
||||||
@ -186,8 +238,8 @@ export class FakeBackendInterceptor implements HttpInterceptor {
|
|||||||
const length = GET_EVENT.length;
|
const length = GET_EVENT.length;
|
||||||
pos = pos + length;
|
pos = pos + length;
|
||||||
let idEvent = request.url.substr(pos);
|
let idEvent = request.url.substr(pos);
|
||||||
let event = events.find(value => value.id == +idEvent );
|
let event = events.find(value => value.id == +idEvent);
|
||||||
return of(new HttpResponse({status: 200, body: event }) );
|
return of(new HttpResponse({status: 200, body: event}));
|
||||||
} else {
|
} else {
|
||||||
// invalid JWT token found in request header
|
// invalid JWT token found in request header
|
||||||
return throwError({
|
return throwError({
|
||||||
@ -201,9 +253,9 @@ export class FakeBackendInterceptor implements HttpInterceptor {
|
|||||||
|
|
||||||
if (request.headers.get('Authorization') === 'Bearer 0000-fake-jwt-token-0000') {
|
if (request.headers.get('Authorization') === 'Bearer 0000-fake-jwt-token-0000') {
|
||||||
if (request.url.indexOf('event/register&id_event=') && request.method === 'POST') {
|
if (request.url.indexOf('event/register&id_event=') && request.method === 'POST') {
|
||||||
return of(new HttpResponse({status: 200, body: {} }) );
|
return of(new HttpResponse({status: 200, body: {}}));
|
||||||
}else if (request.url.indexOf('event/cancel&id_event=') && request.method === 'POST') {
|
} else if (request.url.indexOf('event/cancel&id_event=') && request.method === 'POST') {
|
||||||
return of(new HttpResponse({status: 200, body: {} }) );
|
return of(new HttpResponse({status: 200, body: {}}));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// invalid JWT token found in request header
|
// invalid JWT token found in request header
|
||||||
@ -232,7 +284,6 @@ export class FakeBackendInterceptor implements HttpInterceptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// creating a PROVIDER
|
// creating a PROVIDER
|
||||||
export let fakeBackendProvider = {
|
export let fakeBackendProvider = {
|
||||||
// use fake backend in place of Http service for backend-less development
|
// use fake backend in place of Http service for backend-less development
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
export * from './error.interceptor';
|
export * from './error.interceptor';
|
||||||
export * from './fake-backend';
|
export * from './fake-backend';
|
||||||
export * from './jwt.interceptor';
|
export * from './jwt.interceptor';
|
||||||
|
export {DayToDisplay} from "../services/event.service";
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import {LoginComponent} from "./pages/login/login.component";
|
|||||||
import {ProfileComponent} from "./pages/profile/profile.component";
|
import {ProfileComponent} from "./pages/profile/profile.component";
|
||||||
import {AuthGuard} from "./_guards";
|
import {AuthGuard} from "./_guards";
|
||||||
import {EventsComponent} from "./pages/events/events.component";
|
import {EventsComponent} from "./pages/events/events.component";
|
||||||
|
import {EventDetailsComponent} from "./pages/event-details/event-details.component";
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: 'home', component: HomeComponent },
|
{ path: 'home', component: HomeComponent },
|
||||||
@ -13,6 +14,7 @@ const routes: Routes = [
|
|||||||
{ path: 'logout', redirectTo: '/login' , pathMatch: 'full'},
|
{ path: 'logout', redirectTo: '/login' , pathMatch: 'full'},
|
||||||
{ path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] },
|
{ path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] },
|
||||||
{ path: 'events', component: EventsComponent, canActivate: [AuthGuard] },
|
{ path: 'events', component: EventsComponent, canActivate: [AuthGuard] },
|
||||||
|
{ path: 'event-details/:idEvent', component: EventDetailsComponent, canActivate: [AuthGuard] , pathMatch: 'full' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|||||||
@ -23,6 +23,11 @@ import {FontAwesomeModule} from "@fortawesome/angular-fontawesome";
|
|||||||
import { library } from '@fortawesome/fontawesome-svg-core';
|
import { library } from '@fortawesome/fontawesome-svg-core';
|
||||||
|
|
||||||
import { faUserPlus , faUserMinus } from '@fortawesome/free-solid-svg-icons';
|
import { faUserPlus , faUserMinus } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FitWeekdaySelectorComponent } from './components/fit-weekday-selector/fit-weekday-selector.component';
|
||||||
|
import { MonthCalendarComponent } from './components/month-calendar/month-calendar.component';
|
||||||
|
import { MonthCalendarDayComponent } from './components/month-calendar-day/month-calendar-day.component';
|
||||||
|
import { MonthCalendarEventComponent } from './components/month-calendar-event/month-calendar-event.component';
|
||||||
|
import { EventDetailsComponent } from './pages/event-details/event-details.component';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -40,6 +45,11 @@ registerLocaleData(localeHu, 'hu');
|
|||||||
ProfileComponent,
|
ProfileComponent,
|
||||||
EventsComponent,
|
EventsComponent,
|
||||||
FitEventTypesComponent,
|
FitEventTypesComponent,
|
||||||
|
FitWeekdaySelectorComponent,
|
||||||
|
MonthCalendarComponent,
|
||||||
|
MonthCalendarDayComponent,
|
||||||
|
MonthCalendarEventComponent,
|
||||||
|
EventDetailsComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
<p>fit-weekday-selector works!</p>
|
||||||
|
<div *ngIf="days" class="row">
|
||||||
|
<div class="col-md-3" *ngFor="let nextDay of days ">
|
||||||
|
<p>
|
||||||
|
{{ formatDayName( nextDay ) }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{{ formatDate( nextDay ) }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { FitWeekdaySelectorComponent } from './fit-weekday-selector.component';
|
||||||
|
|
||||||
|
describe('FitWeekdaySelectorComponent', () => {
|
||||||
|
let component: FitWeekdaySelectorComponent;
|
||||||
|
let fixture: ComponentFixture<FitWeekdaySelectorComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ FitWeekdaySelectorComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(FitWeekdaySelectorComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import {Component, Input, OnInit} from '@angular/core';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-fit-weekday-selector',
|
||||||
|
templateUrl: './fit-weekday-selector.component.html',
|
||||||
|
styleUrls: ['./fit-weekday-selector.component.scss']
|
||||||
|
})
|
||||||
|
export class FitWeekdaySelectorComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
days: number[] = [];
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
moment.locale("hu");
|
||||||
|
}
|
||||||
|
|
||||||
|
formatDayName(dateNum){
|
||||||
|
return moment(dateNum).format("dddd");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
formatDate(dateNum){
|
||||||
|
return moment(dateNum).format("YYYY-MM-DD");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
<h5 class="row align-items-center">
|
||||||
|
<span class="date col-1">{{getDateOfDay()}}</span>
|
||||||
|
<small class="col d-sm-none text-center text-muted">{{getDayOfWeekName()}}</small>
|
||||||
|
<span class="col-1"></span>
|
||||||
|
</h5>
|
||||||
|
<p *ngIf="!hasEvents()" class="d-sm-none">No events</p>
|
||||||
|
<ng-container *ngIf="hasEvents()">
|
||||||
|
|
||||||
|
<app-month-calendar-event
|
||||||
|
*ngFor="let event of day.events"
|
||||||
|
[event]="event"
|
||||||
|
(onEvent)="handleEvent($event)"
|
||||||
|
></app-month-calendar-event>
|
||||||
|
|
||||||
|
</ng-container>
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
@media (max-width:575px) {
|
||||||
|
.display-4 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
.day h5 {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 3px 5px 5px;
|
||||||
|
margin: -8px -8px 8px -8px;
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 576px) {
|
||||||
|
.day {
|
||||||
|
min-height: 14.2857vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MonthCalendarDayComponent } from './month-calendar-day.component';
|
||||||
|
|
||||||
|
describe('MonthCalendarDayComponent', () => {
|
||||||
|
let component: MonthCalendarDayComponent;
|
||||||
|
let fixture: ComponentFixture<MonthCalendarDayComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MonthCalendarDayComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MonthCalendarDayComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
import {Component, EventEmitter, HostBinding, Input, OnInit, Output} from '@angular/core';
|
||||||
|
import {dateToMoment, Day, MonthCalendarEvent} from "../month-calendar/month-calendar.component";
|
||||||
|
import {DayToDisplay} from "../../_helpers";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: '[app-month-calendar-day]',
|
||||||
|
templateUrl: './month-calendar-day.component.html',
|
||||||
|
styleUrls: ['./month-calendar-day.component.scss']
|
||||||
|
})
|
||||||
|
export class MonthCalendarDayComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
day: DayToDisplay;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
onEvent: EventEmitter<MonthCalendarEvent> = new EventEmitter<MonthCalendarEvent>();
|
||||||
|
|
||||||
|
oMoment: any;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if ( this.day ){
|
||||||
|
|
||||||
|
console.info(this.day);
|
||||||
|
this.oMoment = dateToMoment(this.day.date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDayOfWeekName(){
|
||||||
|
return this.oMoment.format('dddd');
|
||||||
|
}
|
||||||
|
|
||||||
|
getDateOfDay(){
|
||||||
|
return this.oMoment.format('DD');
|
||||||
|
}
|
||||||
|
|
||||||
|
hasEvents(){
|
||||||
|
return this.day.active && this.day.events && this.day.events.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostBinding('class') get styleClass(){
|
||||||
|
let styleClass = "day col-sm p-2 border border-left-0 border-top-0 text-truncate";
|
||||||
|
if ( !this.day.active ){
|
||||||
|
styleClass += " d-none d-sm-inline-block bg-light text-muted";
|
||||||
|
}
|
||||||
|
return styleClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEvent($event){
|
||||||
|
this.onEvent.emit($event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
<a
|
||||||
|
(click)="selectEvent()"
|
||||||
|
class="event d-block p-1 pl-2 pr-2 mb-1 rounded text-truncate small bg-success text-white" title="Test Event 2">
|
||||||
|
{{formatTime()}}:{{event.eventType.name}}
|
||||||
|
<ng-container *ngIf="hasTrainer()">
|
||||||
|
<br>
|
||||||
|
{{formatTrainer()}}
|
||||||
|
</ng-container>
|
||||||
|
</a>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MonthCalendarEventComponent } from './month-calendar-event.component';
|
||||||
|
|
||||||
|
describe('MonthCalendarEventComponent', () => {
|
||||||
|
let component: MonthCalendarEventComponent;
|
||||||
|
let fixture: ComponentFixture<MonthCalendarEventComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MonthCalendarEventComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MonthCalendarEventComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||||
|
import {Event} from "../../services/event.service";
|
||||||
|
import * as moment from "moment";
|
||||||
|
import {MonthCalendarEvent} from "../month-calendar/month-calendar.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-month-calendar-event',
|
||||||
|
templateUrl: './month-calendar-event.component.html',
|
||||||
|
styleUrls: ['./month-calendar-event.component.scss']
|
||||||
|
})
|
||||||
|
export class MonthCalendarEventComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
event: Event;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
onEvent = new EventEmitter<MonthCalendarEvent>();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
formatTime() {
|
||||||
|
return moment(this.event.start).format('HH:mm');
|
||||||
|
}
|
||||||
|
|
||||||
|
hasTrainer() {
|
||||||
|
return !!this.event.trainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatTrainer() {
|
||||||
|
const trainer = this.event.trainer;
|
||||||
|
return trainer.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectEvent() {
|
||||||
|
this.onEvent.emit({
|
||||||
|
type: 'SELECT_EVENT',
|
||||||
|
event: this.event
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
<div class="container-fluid">
|
||||||
|
<header>
|
||||||
|
<h4 class="display-4 mb-4 text-center">Naptár</h4>
|
||||||
|
<div class="row d-none d-sm-flex p-1 bg-dark text-white">
|
||||||
|
<h5 *ngFor="let dayOfWeek of daysOfWeek" class="col-sm p-1 text-center name-of-day-of-week">{{dayOfWeek.name}}</h5>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div *ngIf="eventsAvailableResponse" class="row border border-right-0 border-bottom-0">
|
||||||
|
<ng-container *ngFor="let day of eventsAvailableResponse.days; let i = index">
|
||||||
|
<div app-month-calendar-day [day]="day" (onEvent)="handleEvent($event)" ></div>
|
||||||
|
<div *ngIf="i > 0 && ( ((i+1) % 7) == 0)" class="w-100"></div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
@media (max-width:575px) {
|
||||||
|
.display-4 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
.day h5 {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 3px 5px 5px;
|
||||||
|
margin: -8px -8px 8px -8px;
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 576px) {
|
||||||
|
.day {
|
||||||
|
min-height: 14.2857vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.name-of-day-of-week{
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MonthCalendarComponent } from './month-calendar.component';
|
||||||
|
|
||||||
|
describe('MonthCalendarComponent', () => {
|
||||||
|
let component: MonthCalendarComponent;
|
||||||
|
let fixture: ComponentFixture<MonthCalendarComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MonthCalendarComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MonthCalendarComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges} from '@angular/core';
|
||||||
|
import {Event, EventsAvailableResponse} from "../../services/event.service";
|
||||||
|
import * as moment from "moment";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-month-calendar',
|
||||||
|
templateUrl: './month-calendar.component.html',
|
||||||
|
styleUrls: ['./month-calendar.component.scss']
|
||||||
|
})
|
||||||
|
export class MonthCalendarComponent implements OnInit, OnChanges {
|
||||||
|
|
||||||
|
minDate: number;
|
||||||
|
maxDate: number;
|
||||||
|
daysOfWeek: DayOfWeek[];
|
||||||
|
days: Day[];
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
eventsAvailableResponse: EventsAvailableResponse;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
onEvent: EventEmitter<MonthCalendarEvent> = new EventEmitter<MonthCalendarEvent>();
|
||||||
|
|
||||||
|
constructor( ) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
moment.locale('hu');
|
||||||
|
//
|
||||||
|
this.fillDaysOfWeek();
|
||||||
|
//
|
||||||
|
// let firstDay = moment().startOf('week');
|
||||||
|
//
|
||||||
|
// this.days = [];
|
||||||
|
// if ( this.eventsAvailableResponse ){
|
||||||
|
//
|
||||||
|
// for ( let i = 0; i < this.eventsAvailableResponse.days.length; i++){
|
||||||
|
// this.days.push({
|
||||||
|
// date: this.eventsAvailableResponse.days[i],
|
||||||
|
// events: [],
|
||||||
|
// active: true
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fillDaysOfWeek(){
|
||||||
|
this.daysOfWeek = [];
|
||||||
|
let startOfWeek = moment().startOf("week");
|
||||||
|
|
||||||
|
for ( let i = 0; i < 7 ; i++ ){
|
||||||
|
let momWeekDay = startOfWeek.clone().add(i,'d');
|
||||||
|
const dayOfWeek = {
|
||||||
|
name: momWeekDay.format("dddd"),
|
||||||
|
};
|
||||||
|
this.daysOfWeek.push(dayOfWeek);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
console.info(changes);
|
||||||
|
if ( changes.hasOwnProperty('eventsAvailableResponse')){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEvent($event){
|
||||||
|
this.onEvent.emit($event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Day {
|
||||||
|
date: number;
|
||||||
|
events: Event[];
|
||||||
|
active: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DayOfWeek {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dateToMoment(date: number) {
|
||||||
|
return moment(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MonthCalendarEvent {
|
||||||
|
type: string; // type of the month calendar event
|
||||||
|
event: Event; // the fitness event
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
<div class="container" *ngIf="event">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-3 col-sm-12"><span class="title">Edzés típusa</span></div>
|
||||||
|
<div class="col-lg-9 col-sm-12"><span>{{event.eventType.name}}</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="row" *ngIf="event.trainer">
|
||||||
|
<div class="col-lg-3 col-sm-12"><span class="title">Edző</span></div>
|
||||||
|
<div class="col-lg-9 col-sm-12"><span>{{event.trainer.name}}</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-3 col-sm-12"><span class="title">Edzés kezdési időpontja</span></div>
|
||||||
|
<div class="col-lg-9 col-sm-12"><span>{{event.start | date:'yyyy.MM.dd HH:mm'}}</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-3 col-sm-12"><span class="title">Edzés vége</span></div>
|
||||||
|
<div class="col-lg-9 col-sm-12"><span>{{event.end | date:'yyyy.MM.dd HH:mm'}}</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-3 col-sm-12"><span class="title">Férőhelyek száma</span></div>
|
||||||
|
<div class="col-lg-9 col-sm-12"><span>{{event.seatCount }}</span></div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="row">-->
|
||||||
|
<!-- <div class="col-lg-3 col-sm-12"><span class="title">Szabad helyek száma</span></div>-->
|
||||||
|
<!-- <div class="col-lg-9 col-sm-12"><span>{{event.seatCount - event.reservationCount }}</span></div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-9 col-sm-12 pt-2">
|
||||||
|
<a *ngIf="mayRegister(event)" class="btn btn-primary " (click)="register(event)" >Foglalás</a>
|
||||||
|
<a *ngIf="mayCancel(event)" class="btn btn-primary" (click)="cancel(event)" >Lemondás</a>
|
||||||
|
<span *ngIf="!mayCancel(event) && noFreeSeat(event)">Már nincs szabad hely</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-3 text-lg-right col-sm-12 pt-2">
|
||||||
|
<a class="btn btn-primary " (click)="goBack(event)" >Vissza</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { EventDetailsComponent } from './event-details.component';
|
||||||
|
|
||||||
|
describe('EventDetailsComponent', () => {
|
||||||
|
let component: EventDetailsComponent;
|
||||||
|
let fixture: ComponentFixture<EventDetailsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ EventDetailsComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(EventDetailsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import {Event, EventService} from "../../services/event.service";
|
||||||
|
import {ActivatedRoute, RouterState} from "@angular/router";
|
||||||
|
import {NavigationService} from "../../services/navigation.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-event-details',
|
||||||
|
templateUrl: './event-details.component.html',
|
||||||
|
styleUrls: ['./event-details.component.scss']
|
||||||
|
})
|
||||||
|
export class EventDetailsComponent implements OnInit {
|
||||||
|
|
||||||
|
event: Event;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private eventService: EventService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private navigationService: NavigationService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
let idEvent = +this.route.snapshot.paramMap.get('idEvent');
|
||||||
|
this.eventService.findEvent(idEvent).subscribe(
|
||||||
|
value => this.event = value
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mayRegister(event: Event) {
|
||||||
|
return event.reservedAt == null && event.reservationCount < event.seatCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
mayCancel(event: Event) {
|
||||||
|
return event.reservedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
noFreeSeat(event: Event) {
|
||||||
|
return event.reservedAt == null && event.reservationCount >= event.seatCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
goBack(event: Event) {
|
||||||
|
this.navigationService.navigateToHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
register(event: Event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel(event: Event) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -1 +1,9 @@
|
|||||||
<p>home works!</p>
|
<div class="container">
|
||||||
|
<!-- <app-fit-weekday-selector [days]="(availableEvents | async)?.days" ></app-fit-weekday-selector>-->
|
||||||
|
<ng-container *ngIf="availableEvents | async">
|
||||||
|
<app-month-calendar
|
||||||
|
(onEvent)="handleEvent($event)"
|
||||||
|
[eventsAvailableResponse]="availableEvents | async "></app-month-calendar>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import {EventsAvailableResponse, EventService} from "../../services/event.service";
|
||||||
|
import {Observable} from "rxjs";
|
||||||
|
import {MonthCalendarEvent} from "../../components/month-calendar/month-calendar.component";
|
||||||
|
import {NavigationService} from "../../services/navigation.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
@ -7,9 +11,20 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
})
|
})
|
||||||
export class HomeComponent implements OnInit {
|
export class HomeComponent implements OnInit {
|
||||||
|
|
||||||
constructor() { }
|
availableEvents: Observable<EventsAvailableResponse>;
|
||||||
|
|
||||||
|
constructor(private eventService: EventService,
|
||||||
|
private navigationService: NavigationService) { }
|
||||||
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.availableEvents = this.eventService.findEventsAvailable();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleEvent($event: MonthCalendarEvent) {
|
||||||
|
console.info($event);
|
||||||
|
this.navigationService.navigateToEventDetails($event.event.id);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,4 +29,9 @@ export class Endpoints {
|
|||||||
return `${this.baseUrl}/event-type`;
|
return `${this.baseUrl}/event-type`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static GET_EVENTS_AVAILABLE(){
|
||||||
|
return `${this.baseUrl}/events/available`;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {HttpClient} from "@angular/common/http";
|
import {HttpClient} from "@angular/common/http";
|
||||||
import {Endpoints} from "./endpoints";
|
import {Endpoints} from "./endpoints";
|
||||||
import {Observable} from "rxjs";
|
import {Observable} from "rxjs";
|
||||||
|
import {DayToDisplay} from "../_helpers";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -31,6 +32,10 @@ export class EventService {
|
|||||||
return this.http.post(Endpoints.POST_EVENT_CANCEL( idEvent ),{}) as Observable<Event>;
|
return this.http.post(Endpoints.POST_EVENT_CANCEL( idEvent ),{}) as Observable<Event>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findEventsAvailable(): Observable<EventsAvailableResponse>{
|
||||||
|
return this.http.get(Endpoints.GET_EVENTS_AVAILABLE()) as Observable<EventsAvailableResponse>;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Trainer {
|
export interface Trainer {
|
||||||
@ -55,4 +60,14 @@ export interface EventType {
|
|||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DayToDisplay {
|
||||||
|
date: number;
|
||||||
|
active: true;
|
||||||
|
events: Event[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EventsAvailableResponse {
|
||||||
|
days: DayToDisplay[];
|
||||||
|
events: Event[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
12
customer/app/src/app/services/navigation.service.spec.ts
Normal file
12
customer/app/src/app/services/navigation.service.spec.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { NavigationService } from './navigation.service';
|
||||||
|
|
||||||
|
describe('NavigationService', () => {
|
||||||
|
beforeEach(() => TestBed.configureTestingModule({}));
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
const service: NavigationService = TestBed.get(NavigationService);
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
24
customer/app/src/app/services/navigation.service.ts
Normal file
24
customer/app/src/app/services/navigation.service.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {NavigationExtras, Router} from "@angular/router";
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class NavigationService {
|
||||||
|
|
||||||
|
constructor(private navigation: Router) { }
|
||||||
|
|
||||||
|
public navigate(commands: any[], extras?: NavigationExtras){
|
||||||
|
this.navigation.navigate( commands,extras );
|
||||||
|
}
|
||||||
|
|
||||||
|
public navigateToEventDetails(idEvent: number){
|
||||||
|
this.navigate(['/event-details/'+idEvent ])
|
||||||
|
}
|
||||||
|
|
||||||
|
public navigateToHome(){
|
||||||
|
this.navigate(['/home' ])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -36,7 +36,7 @@ body{
|
|||||||
background: #e5ce48;
|
background: #e5ce48;
|
||||||
border: 1px solid #e5ce48;
|
border: 1px solid #e5ce48;
|
||||||
color: #000; }
|
color: #000; }
|
||||||
.btn.btn-primary:hover {
|
.btn.btn-primary:hover,.btn.btn-primary:active, .btn-primary:not(:disabled):not(.disabled):active {
|
||||||
border: 1px solid #e5ce48;
|
border: 1px solid #e5ce48;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: #e5ce48; }
|
color: #e5ce48; }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user