improve customer api & gui

This commit is contained in:
Roland Schneider 2021-10-02 22:21:14 +02:00
parent 1d065cc729
commit f98dcb656f
44 changed files with 893 additions and 298 deletions

View File

@ -13,6 +13,7 @@ use yii\widgets\ActiveForm;
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'theme')->dropDownList(\common\models\EventType::themes()) ?>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? Yii::t('event-type', 'Create') : Yii::t('event-type', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>

View File

@ -26,7 +26,13 @@ $this->params['breadcrumbs'][] = $this->title;
'name',
'created_at:datetime',
'updated_at:datetime',
[
'attribute' => 'theme',
'label' => 'Színtéma',
'value' => function ($model, $key, $index, $column){
return isset($model['theme']) ? "Színtéma " . ($model['theme']+1) : "";
}
],
['class' => 'yii\grid\ActionColumn',
'template' => '{view} {update}'
],

View File

@ -30,6 +30,10 @@ $this->params['breadcrumbs'][] = $this->title;
'attributes' => [
'id',
'name',
[
'label'=> 'Színtéma',
'value' => ( isset($model->theme) ? 'Színtéma ' . ($model->theme+1) : '-' )
],
'created_at',
'updated_at',
],

View File

@ -400,6 +400,10 @@ class Helper {
return !Helper::isReceptionTransferListToday();
}
public static function getGroupTrainingUrl(){
return \Yii::$app->params['group_training.url'];
}
public static function getRealUserIp() {
$client = @$_SERVER ['HTTP_CLIENT_IP'];
$forward = @$_SERVER ['HTTP_X_FORWARDED_FOR'];

View File

@ -64,5 +64,6 @@ return [
'ticket_type_door_allowed_check_on' => false,
'warn_ticket_expire_in_days_count' => 3,
'warn_ticket_expire_in_usage_count' => 3,
'inventory.products.only.active' => true
'inventory.products.only.active' => true,
'group_training.url' => 'https://fitnessadmin.hu'
];

View File

@ -0,0 +1,40 @@
<?php
namespace common\helpers;
class AppArrayHelper
{
public static function objectArrayToMap($array, $funcGetId, $funcGetValue){
$result = [];
foreach ($array as $item ){
$id = $funcGetId($item);
$value = $funcGetValue($item);
$result[$id] = $value;
}
return $result;
}
/**
* Map an array of object by object id
* [obj1,obj2] => [obj1.id => obj1,obj2.id => obj2]
* @param $array
* @return array
*/
public static function objectArrayToMapById($array){
return AppArrayHelper::objectArrayToMap(
$array,
function ($item){
return $item->id;
},
function ($item){
return $item;
}
);
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace common\helpers;
class AppDateTimeHelper
{
public static function convertMySqlDatetimeToPhpInteger($dateString){
if (!isset($dateString) || empty($dateString)){
return null;
}
$unixTime = strtotime($dateString . " UTC");
return $unixTime;
}
}

View File

@ -1,21 +1,24 @@
<?php
use yii\helpers\Html;
use yii\helpers\Url;
use common\components\Helper;
use frontend\models\PasswordChangeModel;
/* @var $model PasswordChangeModel */
?>
<h1 style="font-size: 12px;">Kedves <?php echo $model->customer->name?>!</h1>
<p style="font-size: 12px;">
<div>Kedves <?php echo $model->customer->name ?>!</div>
<p>
Az Ön új jelszava:
</p>
<ul style="font-size: 12px;">
<li>
"<?php echo $model->plainPassword ?>"
</li>
</ul>
<p style="font-size: 12px;">
<p>
<?php echo $model->plainPassword ?>
</p>
<p>A bejelentkezéshez kattintson a következő linkre: <a
href="<?php echo $model->groupTrainingUrl ?>"><?php echo $model->groupTrainingUrl ?></a></p>
<p>
Üdvözlettel:
</p>
<p style="font-size: 12px;">
<p>
<?php echo $model->companyName ?>
</p>
<p>

View File

@ -161,7 +161,8 @@ class Event extends ActiveRecord
* @return EventRegistration[]|ActiveQuery
*/
public function getActiveEventRegistrations(){
return $this->hasMany(EventRegistration::class,['id_event' => 'id'])->andWhere(
return $this->hasMany(EventRegistration::class,['id_event' => 'id'])
->andWhere(
[
'event_registration.canceled_at' => null,
'event_registration.deleted_at' => null,
@ -169,19 +170,6 @@ class Event extends ActiveRecord
);
}
/**
* @return EventRegistration[]|ActiveQuery
*/
public function getActiveEventRegistrationsForCustomer(){
return $this->hasMany(EventRegistration::class,['id_event' => 'id'])->andWhere(
[
'event_registration.canceled_at' => null,
'event_registration.deleted_at' => null,
'event_registration.id_customer' => \Yii::$app->user->id
]
);
}
/**
* @return integer
*/

View File

@ -60,34 +60,41 @@ class EventRegistration extends \yii\db\ActiveRecord
return ArrayHelper::merge([
[
'class' => TimestampBehavior::className(),
'value' => function(){ return date('Y-m-d H:i:s' ); }
'value' => function () {
return date('Y-m-d H:i:s');
}
]
],
parent::behaviors());
}
public function getEvent(){
public function getEvent()
{
return $this->hasOne($this->getEventClass(), ['id' => 'id_event']);
}
public function getCustomer(){
public function getCustomer()
{
return $this->hasOne($this->getCustomerClass(), ['id' => 'id_customer']);
}
public function getEventClass(){
public function getEventClass()
{
return Event::class;
}
public function getCustomerClass(){
public function getCustomerClass()
{
return Customer::class;
}
/**
* @param EventRegistration $eventRegistration
*/
public static function isActive($eventRegistration){
public static function isActive($eventRegistration)
{
if (!isset($eventRegistration)) {
return false;
}
@ -105,7 +112,8 @@ class EventRegistration extends \yii\db\ActiveRecord
/**
* @param EventRegistration $eventRegistration
*/
public static function isForCustomer($eventRegistration,$idCustomer){
public static function isForCustomer($eventRegistration, $idCustomer)
{
if (!isset($eventRegistration)) {
return false;
}
@ -119,20 +127,27 @@ class EventRegistration extends \yii\db\ActiveRecord
/**
* @param EventRegistration[] $eventRegistrations
*/
public static function filterActive($eventRegistrations){
public static function filterActive($eventRegistrations)
{
if (!isset($eventRegistrations)) {
return [];
}
return array_filter($eventRegistrations, EventRegistration::class . '::isActive');
}
/**
* @param EventRegistration[] $eventRegistrations
*/
public static function filterForCustomer($eventRegistrations,$idCustomer){
public static function filterForCustomer($eventRegistrations, $idCustomer)
{
$result = [];
if (isset($eventRegistrations)) {
foreach ($eventRegistrations as $eventRegistration) {
if (EventRegistration::isForCustomer($eventRegistration, $idCustomer)) {
$result[] = $eventRegistration;
}
}
}
return $result;
}
}

View File

@ -11,6 +11,7 @@ use yii\helpers\ArrayHelper;
*
* @property integer $id
* @property string $name
* @property string $theme
* @property string $created_at
* @property string $updated_at
*/
@ -30,9 +31,10 @@ class EventType extends \yii\db\ActiveRecord
public function rules()
{
return [
[['name'], 'required'],
[['name','theme'], 'required'],
[['name'], 'unique'],
[['name'], 'string', 'max' => 255]
[['name'], 'string', 'max' => 255],
[['theme'], 'string', 'max' => 50]
];
}
@ -104,4 +106,12 @@ class EventType extends \yii\db\ActiveRecord
// TODO: implement bossiness logic to select ticket
return $possibleTickets[0];
}
static function themes() {
$themes = [];
for ($x = 0; $x < 10; $x++) {
$themes[$x] = "Színtéma " . ($x+1);
}
return $themes;
}
}

View File

@ -2,6 +2,7 @@
namespace common\models;
use common\helpers\AppArrayHelper;
use Yii;
use yii\behaviors\TimestampBehavior;
use yii\helpers\ArrayHelper;

View File

@ -3,10 +3,12 @@
namespace common\modules\event\manager;
use common\models\Event;
use common\models\EventRegistration;
use common\modules\event\models\timetable\TimeTableMonth;
use common\modules\event\models\timetable\TimeTableMonthDay;
use common\modules\event\models\timetable\TimeTableMonthWeek;
use customerapi\models\available\EventInterval;
use customerapi\models\details\EventRegistrationView;
use DateTime;
use Exception;
use yii\db\Query;
@ -23,7 +25,8 @@ class EventManager
* @throws \yii\base\Exception on any error
* @throws StaleObjectException
*/
public function deleteEvent($id){
public function deleteEvent($id)
{
$event = Event::findOne($id);
if (!isset($event)) {
throw new \yii\base\Exception("Event $id not found");
@ -158,10 +161,53 @@ class EventManager
return $this->getEvents($start, $to);
}
public function getEvent($id){
public function getEvent($id)
{
return Event::findOne($id);
}
public function findActiveRegistrations($idEvent, $idCustomer = null)
{
$registrations = EventRegistrationView::find()->andWhere(['id_event' => $idEvent, 'id_customer' => \Yii::$app->user->id])->all();
$allActiveRegistrations = EventRegistration::filterActive($registrations);
if (isset($idCustomer)) {
$allActiveRegistrations = EventRegistration::filterForCustomer($allActiveRegistrations, \Yii::$app->user->id);
}
return $allActiveRegistrations;
}
public function findActiveEvent($idEvent, $interval, $withRelatedObjects = false)
{
$paramEventStartMax = (clone $interval->lastActiveDate);
$paramEventStartMax = $paramEventStartMax->modify('+1 day');
$paramEventStartMax = $paramEventStartMax->getTimestamp();
$query = Event::find()
->andWhere(['event.id' => $idEvent])
->andWhere(['>=', 'event.start', $interval->firstActiveDate->getTimestamp()])
->andWhere(['<', 'event.start', $paramEventStartMax])
->andWhere(['event.active' => '1']);
if ($withRelatedObjects) {
$query = $query->innerJoinWith('trainer')
->innerJoinWith('eventType')
->innerJoinWith('room');
}
return $query->one();
}
public function findActiveEvents($interval)
{
$paramEventStartMax = (clone $interval->lastActiveDate);
$paramEventStartMax = $paramEventStartMax->modify('+1 day');
$paramEventStartMax = $paramEventStartMax->getTimestamp();
return Event::find()
->andWhere(['>=', 'event.start', $interval->firstActiveDate->getTimestamp()])
->andWhere(['<', 'event.start', $paramEventStartMax])
->andWhere(['event.active' => '1'])->all();
}
}

View File

@ -0,0 +1,42 @@
<?php
use yii\db\Migration;
/**
* Class m210930_101018_alter_table_event_type_add_field_color
*/
class m210930_101018_alter_table_event_type_add_field_color extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn("event_type",'theme',$this->string(50));
}
/**
* {@inheritdoc}
*/
public function safeDown()
{
echo "m210930_101018_alter_table_event_type_add_field_color cannot be reverted.\n";
return false;
}
/*
// Use up()/down() to run migration code without a transaction.
public function up()
{
}
public function down()
{
echo "m210930_101018_alter_table_event_type_add_field_color cannot be reverted.\n";
return false;
}
*/
}

View File

@ -47,11 +47,13 @@ export class FakeBackendInterceptor implements HttpInterceptor {
let eventTypes: EventType[] = [
{
id: 1,
name: 'Típus 1'
name: 'Típus 1',
theme: '0'
},
{
id: 2,
name: 'Típus 2'
name: 'Típus 2',
theme: '0'
}
];

View File

@ -39,6 +39,7 @@ import {environment} from "../environments/environment";
import {AppState} from "./state/app.state";
import {NgxsReduxDevtoolsPluginModule} from "@ngxs/devtools-plugin";
import {NgxsLoggerPluginModule} from "@ngxs/logger-plugin";
import { EventDatePipe } from './pipes/event-time.pipe';
@ -66,6 +67,7 @@ registerLocaleData(localeHu, 'hu');
GuestLayoutComponent,
SecuredLayoutComponent,
PasswordChangeComponent,
EventDatePipe,
],
imports: [

View File

@ -0,0 +1,26 @@
import { Injectable } from '@angular/core';
import * as moment from "moment";
@Injectable({
providedIn: 'root'
})
export class AppService {
constructor() { }
formatDateTime(datetime: number, date:boolean, time: boolean) {
let format ;
if ( date && time ){
format = 'YYYY.MM.DD HH:mm';
} else if (date){
format = 'YYYY.MM.DD';
} else {
format = 'HH:mm';
}
return this.dateToMoment(datetime).utc().format(format);
}
dateToMoment(date: number) {
return moment.unix(date);
}
}

View File

@ -1,6 +1,6 @@
import {Component, forwardRef, OnInit} from '@angular/core';
import {EventService, EventType} from "../../services/event.service";
import {ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR} from "@angular/forms";
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";
const FIT_EVENT_TYPES_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
@ -22,10 +22,8 @@ export class FitEventTypesComponent implements OnInit, ControlValueAccessor {
private onChange: Function;
private onTouched: Function;
public value: string;
constructor(private eventService: EventService) {
this.onChange = (_: any) => { };
this.onTouched = () => { };
@ -34,7 +32,7 @@ export class FitEventTypesComponent implements OnInit, ControlValueAccessor {
ngOnInit() {
this.eventService.findAllEventTypes()
.subscribe(value => {
this.types = [{ id: -1, name: 'Minden Típus'}].concat( value);
this.types = [{ id: -1, name: 'Minden Típus', theme: '' }].concat( value);
this._setValue(this.types[0].id);
}
);

View File

@ -6,7 +6,8 @@
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" [collapse]="isCollapsed" >
<div class="collapse navbar-collapse justify-content-end d-lg-flex"
[collapse]="isCollapsed" >
<ul class="navbar-nav ml-auto">
<ng-container *ngFor="let item of items" >
<li *ngIf="isVisible(item)" class="nav-item " [routerLinkActive]="'active'">

View File

@ -13,7 +13,7 @@ export class FitNavigationComponent implements OnInit {
items: MenuItem[] = [
{
route: '/home',
label: 'Home',
label: 'Órarend',
roles: ['*']
},
// {

View File

@ -1,22 +1,22 @@
<div
(click)="selectEvent()"
class="event d-flex flex-direction-row py-1 px-1 mb-2 border-radius-1 small text-white "
class="event d-flex flex-direction-row py-1 px-1 mb-2 border-radius-1 small text-white {{getEventThemeClass()}}"
title="Test Event 2"
[class.bg-dark]="maySelect()"
[class.bg-primary]="isRegistered()"
[class.bg-secondary]="isDisabled()"
>
<!-- [class.bg-dark]="maySelect()"-->
<!-- [class.bg-primary]="isRegistered()"-->
<!-- [class.bg-secondary]="isDisabled()"-->
<div class=" event-bar-container flex-grow-0 flex-shrink-0 d-flex" style="flex-basis: 10px;">
<div class="event-bar flex-grow-1 flex-shrink-1 my-1 border-radius-1 " style=" background-color: var(--bs-blue)"></div>
<div class="event-bar flex-grow-1 flex-shrink-1 my-1 border-radius-1 bg-white" ></div>
</div>
<div class="event-info-container flex-grow-1 flex-shrink-1 " style="flex-basis: 0;" >
<div class="event-info ms-1" style="white-space: pre-wrap">
<div class="app-font-size-sm app-font-weight-normal ">{{formatTime()}}</div>
<div class="app-font-size-sm app-font-weight-normal ">{{event.start | eventDate:'time' }}</div>
<div class="app-font-size-sm app-font-weight-bold">{{event.eventType.name}}</div>
<ng-container *ngIf="hasTrainer()">
<div class="app-font-size-sm app-font-weight-normal " style="max-width: 100%; word-break: break-word">{{formatTrainer()}} very long name</div>
<div class="app-font-size-sm app-font-weight-normal " style="max-width: 100%; word-break: break-word">{{formatTrainer()}}</div>
</ng-container>
</div>
</div>

View File

@ -1,6 +1,6 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {Event} from "../../services/event.service";
import {dateToMoment, MonthCalendarEvent} from "../month-calendar/month-calendar.component";
import { MonthCalendarEvent} from "../month-calendar/month-calendar.component";
@Component({
selector: 'app-month-calendar-event',
@ -21,10 +21,6 @@ export class MonthCalendarEventComponent implements OnInit {
ngOnInit() {
}
formatTime() {
return dateToMoment(this.event.start).utc().format('HH:mm');
}
hasTrainer() {
return !!this.event.trainer;
}
@ -42,7 +38,7 @@ export class MonthCalendarEventComponent implements OnInit {
}
maySelect() {
return this.event.registrations?.length == 0 && this.event.hasFreeSeats;
return this.isRegistered() ? true : this.event.hasFreeSeats;
}
isRegistered() {
@ -50,6 +46,30 @@ export class MonthCalendarEventComponent implements OnInit {
}
isDisabled() {
return false;
return !this.isRegistered() && !this.event.hasFreeSeats;
}
getEventThemeClass(): string {
const theme = this.event?.eventType?.theme;
let styleClass = "bg-dark";
if (this.isDisabled()) {
styleClass = "bg-secondary";
} else {
if (theme != null && theme.length > 0) {
if (this.isRegistered()) {
styleClass += " event-theme-active-" + theme;
} else {
styleClass += " event-theme-normal-" + theme;
}
} else {
if (this.isRegistered()) {
styleClass += " bg-primary";
} else {
styleClass += " bg-dark";
}
}
}
return styleClass;
}
}

View File

@ -15,11 +15,11 @@
</div>
<div class="row">
<div class="col-lg-3 col-12 app-font-weight-bold"><span class="title">Edzés kezdési időpontja</span></div>
<div class="col-lg-6 col-12"><span>{{event.start * 1000 | date:'yyyy.MM.dd HH:mm'}}</span></div>
<div class="col-lg-6 col-12"><span>{{event.start | eventDate:'datetime'}}</span></div>
</div>
<div class="row">
<div class="col-lg-3 col-12 app-font-weight-bold"><span class="title">Edzés vége</span></div>
<div class="col-lg-6 col-12"><span>{{event.end * 1000 | date:'yyyy.MM.dd HH:mm'}}</span></div>
<div class="col-lg-6 col-12"><span>{{event.end | eventDate: 'datetime'}}</span></div>
</div>
<div class="row">
<div class="col-lg-3 col-12 app-font-weight-bold"><span class="title">Férőhelyek száma</span></div>

View File

@ -41,8 +41,8 @@ export class EventDetailsComponent implements OnInit {
ngOnInit() {
let idEvent = +this.route.snapshot.paramMap.get('idEvent');
this.eventService.findEvent(idEvent).subscribe(
value => {
this.event = value;
event => {
this.event = event;
this.eventForm.patchValue({"idEvent": this.event.id})
}
);
@ -74,7 +74,7 @@ export class EventDetailsComponent implements OnInit {
this.eventService.register(request)
.subscribe(
value => {
this.toastr.success('Sikeresen Foglalás', 'Foglalás');
this.toastr.success('Sikeres Foglalás', 'Foglalás');
this.goBack();
},
@ -106,6 +106,7 @@ export class EventDetailsComponent implements OnInit {
this.eventService.cancelRegistration(event.registrations[0].id)
.subscribe(
() => {
this.toastr.success("Sikeres lemondás", "Lemondás")
this.goBack();
},
() => {

View File

@ -25,6 +25,18 @@
<div class="col-lg-3 col-sm-12 app-font-weight-bold"><span class="title">Terem</span></div>
<div class="col-lg-9 col-sm-12"><span>{{registration.event?.room?.name }}</span></div>
</div>
<div class="row">
<div class="col-lg-3 col-sm-12 app-font-weight-bold"><span class="title">Regisztráció időpontja</span></div>
<div class="col-lg-9 col-sm-12"><span>{{registration.created_at | eventDate:'datetime' }}</span></div>
</div>
<div class="row" *ngIf="registrationService.isCanceled(registration)">
<div class="col-lg-3 col-sm-12 app-font-weight-bold"><span class="title">Regisztráció lemondásának időpontja</span></div>
<div class="col-lg-9 col-sm-12"><span>{{registration.canceled_at | eventDate:'datetime' }}</span></div>
</div>
<div class="row" *ngIf="registrationService.isDeleted(registration)">
<div class="col-lg-3 col-sm-12 app-font-weight-bold"><span class="title">Regisztráció törlésének időpontja</span></div>
<div class="col-lg-9 col-sm-12"><span>{{registration.deleted_at | eventDate:'datetime' }}</span></div>
</div>
<div class="row">
<div class="col-lg-3 col-sm-12 app-font-weight-bold"><span class="title">Státusz</span></div>
<div class="col-lg-9 col-sm-12">

View File

@ -1,11 +1,22 @@
<!-- <app-fit-weekday-selector [days]="(availableEvents | async)?.days" ></app-fit-weekday-selector>-->
<ng-container *ngIf="registrations | async">
<div class="row text-white mb-2 mx-1 align-middle" *ngFor="let registration of (registrations | async); let i = index; "
<ng-container *ngIf="!(registrations | async)?.length">
Jelenleg nincsen aktív foglalása
</ng-container>
<ng-container *ngIf="(registrations | async)?.length">
<div class="row text-white mb-2 mx-1 align-middle"
*ngFor="let registration of (registrations | async); let i = index; "
(click)="showRegistration(registration)"
[class.mt-2]="i == 0"
>
<div class="col-12 col-md-9 bg-dark d-flex d-flex align-items-center py-2 " >
{{(registration.event.start * 1000) | date:'yyyy.MM.dd HH:mm'}} - {{registration.event.eventType.name}}
<div class="col-12 col-md-9 bg-dark d-lg-flex align-items-lg-center py-2 ">
<fa-icon [classes]="['text-success','me-2']" *ngIf="registrationService.isActive(registration)"
[icon]="faCalendarCheck"></fa-icon>
<fa-icon [classes]="['text-warning','me-2']" *ngIf="registrationService.isCanceled(registration)"
[icon]="faCalendarMinus"></fa-icon>
<fa-icon [classes]="['text-danger','me-2']" *ngIf="registrationService.isDeleted(registration)"
[icon]="faCalendarTimes"></fa-icon>
{{ registration.event.start | eventDate: 'datetime' }} - {{registration.event.eventType.name}}
- {{registration.event.trainer.name}}
</div>
<div class="col-3 bg-dark py-2 d-none d-md-block text-end">
@ -13,4 +24,5 @@
</div>
</div>
</ng-container>
</ng-container>

View File

@ -3,6 +3,9 @@ import {Observable} from "rxjs";
import {EventService, Registration} from "../../services/event.service";
import {NavigationService} from "../../services/navigation.service";
import {flatMap, map, mergeMap} from "rxjs/operators";
import {RegistrationService} from "../../services/reservation.service";
import { faCalendarCheck, faCalendarMinus, faCalendarTimes } from '@fortawesome/free-solid-svg-icons';
@Component({
selector: 'app-registrations',
@ -10,9 +13,14 @@ import {flatMap, map, mergeMap} from "rxjs/operators";
styleUrls: ['./registrations.component.scss']
})
export class RegistrationsComponent implements OnInit {
faCalendarCheck = faCalendarCheck;
faCalendarMinus = faCalendarMinus;
faCalendarTimes = faCalendarTimes;
registrations: Observable<Registration[]>;
constructor(private eventService: EventService, private navigationService: NavigationService) { }
constructor(private eventService: EventService,
private navigationService: NavigationService,
public registrationService: RegistrationService) { }
ngOnInit() {
this.registrations = this.eventService.findRegistrations()

View File

@ -0,0 +1,19 @@
import { Pipe, PipeTransform } from '@angular/core';
import {AppService} from "../app.service";
@Pipe({
name: 'eventDate'
})
export class EventDatePipe implements PipeTransform {
constructor(private appService: AppService) {
}
transform(unixtime: number, format: 'date' | 'time' | 'datetime' ): unknown {
const date = format == 'date' || format == 'datetime';
const time = format == 'time' || format == 'datetime';
return this.appService.formatDateTime(unixtime,date,time);
}
}

View File

@ -88,6 +88,7 @@ export interface Room {
export interface EventType {
id: number;
name: string;
theme: string;
}
export interface DayToDisplay {

View File

@ -8,13 +8,13 @@ export class RegistrationService {
constructor() { }
public isCanceled(registration: Registration){
return registration.canceled_at != null;
}
public isDeleted(registration: Registration){
return registration.deleted_at != null;
}
public isCanceled(registration: Registration){
return !this.isDeleted(registration) && registration.canceled_at != null;
}
public isActive(registration: Registration){
return !this.isDeleted(registration) && !this.isCanceled(registration)

View File

@ -1,6 +1,7 @@
/* You can add global styles to this file, and also import other style files */
$font-size-xs: 0.625rem;
$font-size-sm: 1rem;
$font-size-md: 1.25rem;
@ -54,6 +55,7 @@ $btn-border-radius: $border-radius-0;
@import '~ngx-toastr/toastr';
@import "styles/bootstrap-custom";
@import "styles/fonts";
@import "styles/event.themes";
html{
height: 100%;
}
@ -65,3 +67,6 @@ body{
background-repeat: repeat-y;
}

View File

@ -0,0 +1,52 @@
$event-color-yellow: #ECB809; // - sárga
$event-color-burgundy :#AE173B; // - bordó
$event-color-pink :#DF429B; // - pink
$event-color-purple :#B929B1; // - lila
$event-color-turquoise :#3EBFAE; // - türkiz
$event-color-blue :#6594D1; // - kék
$event-color-orange :#F1591A; // - narancs
$event-color-green :#30B211; // - zöld
$event-color-red :#E82A36; // - piros
$event-color-brown :#98701E; // - barna
$event-theme-0: $event-color-yellow; // - sárga
$event-theme-1 :$event-color-burgundy; // - bordó
$event-theme-2 :$event-color-pink; // - pink
$event-theme-3 :$event-color-purple; // - lila
$event-theme-4 :$event-color-turquoise; // - türkiz
$event-theme-5 :$event-color-blue; // - kék
$event-theme-6 :$event-color-orange; // - narancs
$event-theme-7 :$event-color-green; // - zöld
$event-theme-8 :$event-color-red; // - piros
$event-theme-9 :$event-color-brown; // - barna
$event-themes: (
"0": $event-theme-0,
"1": $event-theme-1,
"2": $event-theme-2,
"3": $event-theme-3,
"4": $event-theme-4,
"5": $event-theme-5,
"6": $event-theme-6,
"7": $event-theme-7,
"8": $event-theme-8,
"9": $event-theme-9
);
@each $name, $color in $event-themes {
@debug "event theme - divider offset:";
.event-theme-normal-#{$name} {
.event-bar{
background-color: #{$color} !important;
}
}
.event-theme-active-#{$name}{
background-color: #{$color} !important;
}
}

View File

@ -9,12 +9,18 @@
namespace customerapi\controllers;
use common\helpers\AppArrayHelper;
use common\models\Event;
use common\models\EventRegistration;
use common\models\EventType;
use common\models\Trainer;
use common\modules\event\manager\EventManager;
use customerapi\manager\EventRegistrationManager;
use customerapi\models\available\EventInterval;
use customerapi\models\available\EventAvailable;
use customerapi\models\available\EventTypeAvailable;
use customerapi\models\available\RoomAvailable;
use customerapi\models\available\TrainerAvailable;
use customerapi\models\DayToDisplay;
use customerapi\models\details\EventDetailsView;
use customerapi\models\details\EventRegistrationView;
@ -23,6 +29,7 @@ use customerapi\models\details\RoomDetailsView;
use customerapi\models\details\TrainerDetailsView;
use DateTime;
use Exception;
use yii\db\ActiveQuery;
use yii\db\Query;
use yii\web\Response;
@ -58,37 +65,42 @@ class EventController extends \customerapi\controllers\CustomerApiController
$dates[] = $dayToDisplay;
}
// get events between active dates
$query = EventAvailable::find();
$query = $query->select(
[
'{{event}}.*',
// 'COUNT({{event_registration}}.id) AS reservationCount'
]);
$eventManager = new EventManager();
$events = $eventManager->findActiveEvents($interval);
$trainers = AppArrayHelper::objectArrayToMapById( TrainerAvailable::find()->all() );
$rooms = AppArrayHelper::objectArrayToMapById( RoomAvailable::find()->all() );
$eventTypes = AppArrayHelper::objectArrayToMapById( EventTypeAvailable::find()->all() );
$paramEventStartMax = clone $interval->lastActiveDate;
$paramEventStartMax = $paramEventStartMax->modify('+1 day');
$paramEventStartMax = $paramEventStartMax->getTimestamp();
$events = $query
->innerJoinWith('trainer')
->innerJoinWith('eventType')
->innerJoinWith('room')
->andWhere(['>=', 'event.start', $interval->firstActiveDate->getTimestamp()])
->andWhere(['<', 'event.start', $paramEventStartMax])
->andWhere(['event.active' => '1'])
->all();
$availableEvents = [];
/** @var $event /common/models/Event $event */
foreach ($events as $event ){
$availableEvent = EventAvailable::fromEvent($event);
$availableEvent->trainer = $trainers[$event->id_trainer];
$availableEvent->room = $rooms[$event->id_room];
$availableEvent->eventType = $eventTypes[$event->id_event_type];
$totalRegistrations = $eventManager->findActiveRegistrations($event->id);
$customerRegistration = EventRegistration::filterForCustomer($totalRegistrations,\Yii::$app->user->id);
$availableEvent->registrationCount = count($totalRegistrations);
$availableEvent->eventRegistrations = $customerRegistration;
$availableEvent->hasFreeSeats = $availableEvent->registrationCount < $availableEvent->seat_count;
$availableEvents[] = $availableEvent;
}
// set events per day
/** @var EventAvailable $event */
foreach ($events as $event) {
foreach ($availableEvents as $event) {
$eventDay = new DateTime();
$eventDay->setTimestamp($event->start);
$eventDay->setTime(0, 0);
$event->reservationCount = $event->getEventRegistrationCount();
$event->hasFreeSeats = $event->reservationCount < $event->seat_count;
/** @var DayToDisplay $date */
foreach ($dates as $date) {
if ($date->date === $eventDay->getTimestamp()) {
@ -122,11 +134,13 @@ class EventController extends \customerapi\controllers\CustomerApiController
$paramEventStartMax = $paramEventStartMax->modify('+1 day');
$paramEventStartMax = $paramEventStartMax->getTimestamp();
/** @var ActiveQuery $query */
return $query
->innerJoinWith('trainer')
->innerJoinWith('eventType')
->innerJoinWith('room')
->joinWith('activeEventRegistrations','event.id = activeEventRegistrations.id_event')
->joinWith('activeEventRegistrations')
->andWhere(['>=', 'event.start', $interval->firstActiveDate->getTimestamp()])
->andWhere(['<', 'event.start', $paramEventStartMax])
->andWhere(['event.active' => '1']);
@ -141,14 +155,10 @@ class EventController extends \customerapi\controllers\CustomerApiController
public function actionEvent($id_event)
{
$interval = EventInterval::createInterval();
$manger = new EventManager();
try {
$query = Event::find();
$query = $this->buildEventQuery($query, $interval);
$query = $query->andWhere(['event.id' => $id_event]);
/** @var Event $event */
$event = $query->one();
$event = $manger->findActiveEvent($id_event,$interval);
$result = new EventDetailsView();
$result->id = $event->id;
$result->start = $event->start;

View File

@ -29,7 +29,7 @@ class EventRegistrationController extends CustomerApiController
public function actionIndex()
{
$registrationManager = new EventRegistrationManager();
return $this->asJson( $registrationManager->findCustomerRegistrationsWithEvent() );
return $this->asJson( $registrationManager->findCustomerRegistrationsWithEvent(\Yii::$app->user->id) );
}
/** @noinspection PhpUnused */
@ -42,7 +42,7 @@ class EventRegistrationController extends CustomerApiController
{
$registrationManager = new EventRegistrationManager();
return $this->asJson(
$registrationManager->findRegistration($id_registration)
$registrationManager->findRegistration($id_registration,\Yii::$app->user->id)
);
}

View File

@ -2,9 +2,11 @@
namespace customerapi\manager;
use common\models\EventRegistration;
use common\modules\event\manager\EventManager;
use customerapi\models\available\EventInterval;
use customerapi\models\registrations\EventRegistrationAvailable;
use yii\db\ActiveQuery;
use customerapi\models\dto\EventDTO;
use customerapi\models\dto\EventRegistrationDTO;
use yii\web\NotFoundHttpException;
class EventRegistrationManager
{
@ -12,44 +14,55 @@ class EventRegistrationManager
/** Get Customer registrations
* @throws \Exception
*/
public function findCustomerRegistrationsWithEvent()
{
return $this->prepareQueryFindRegistrationsForCustomer()->all();
}
public function findCustomerRegistrations($clazz= EventRegistration::class )
public function findCustomerRegistrationsWithEvent($idCustomer)
{
$interval = EventInterval::createInterval();
return EventRegistration::find()
->innerJoinWith('event')
->andWhere(['and',
['>=', 'event.start', $interval->firstActiveDate->getTimestamp()],
['id_customer' => \Yii::$app->user->getId()]
])->all();
}
$now = new \DateTime();
$eventRegistrations = EventRegistration::find()
->andWhere(['id_customer' => $idCustomer])
// ->andWhere(['>=', 'event.start', $now->getTimestamp()])
->all();
public function findRegistration($id_registration)
{
return $this->prepareQueryFindRegistrationsForCustomer()
->andWhere(['event_registration.id' => $id_registration])
->one();
$result = [];
$eventManager = new EventManager();
foreach ($eventRegistrations as $registration ){
$dto = EventRegistrationDTO::fromEventRegistration($registration);
$event = $eventManager->findActiveEvent($registration->id_event, $interval,true);
if ( isset($event)){
$dto->event = EventDTO::fromEventWithRelatedObjects($event);
$result[] = $dto;
}
}
return $result;
}
/**
* Prepare a query to get registrations for customer
* @return ActiveQuery query
* @throws \Exception
* @throws NotFoundHttpException
*/
private function prepareQueryFindRegistrationsForCustomer(){
public function findRegistration($id_registration, $id_customer)
{
$interval = EventInterval::createInterval();
return EventRegistrationAvailable::find()
->innerJoinWith('event')
->andWhere(['and',
['>=', 'event.start', $interval->firstActiveDate->getTimestamp()],
['id_customer' => \Yii::$app->user->getId()]
]);
$registration = EventRegistration::findOne(['id' => $id_registration, 'id_customer' => $id_customer]);
if ( !isset($registration)){
throw new NotFoundHttpException();
}
$eventManager = new EventManager();
$event = $eventManager->findActiveEvent($registration->id_event,$interval,true);
if ( !isset($event)){
throw new NotFoundHttpException();
}
return EventRegistrationDTO::fromEventRegistrationWithEvent($registration,$event);
}
}

View File

@ -5,31 +5,49 @@ namespace customerapi\models\available;
use common\models\Event;
use common\models\EventRegistration;
use common\models\EventType;
use common\models\Room;
use common\models\Trainer;
use yii\base\Model;
class EventAvailable extends Event
class EventAvailable extends Model
{
public $reservationCount;
public $id;
public $start;
public $end;
public $seat_count;
public $created_at;
public $updated_at;
public $deleted_at;
public $active;
public $eventType;
public $trainer;
public $room;
public $eventRegistrations;
public $registrationCount;
public $hasFreeSeats;
protected function getTrainerClass()
/**
* @param $event /common/models/Event
*/
public static function fromEvent($event)
{
// override trainer class to have more control
// about json fields
return TrainerAvailable::class;
}
$available = new EventAvailable();
$available->id = $event->id;
$available->start = $event->start;
$available->end = $event->end;
$available->seat_count = $event->seat_count;
$available->created_at = $event->created_at;
$available->updated_at = $event->updated_at;
$available->deleted_at = $event->deleted_at;
$available->active = $event->active;
protected function getEventTypeClass()
{
return EventTypeAvailable::class;
return $available;
}
protected function getRoomClass()
{
return RoomAvailable::class;
}
function fields()
{
@ -39,13 +57,13 @@ class EventAvailable extends Event
"end" => "end",
"seat_count" => "seat_count",
"active" => "active",
"reservationCount" => "reservationCount",
"reservationCount" => "registrationCount",
"hasFreeSeats" => "hasFreeSeats",
];
$fields['trainer'] = 'trainer';
$fields['eventType'] = 'eventType';
$fields['room'] = 'room';
$fields['registrations'] = 'activeEventRegistrationsForCustomer';
$fields['registrations'] = 'eventRegistrations';
return $fields;
}

View File

@ -13,7 +13,8 @@ class EventTypeAvailable extends EventType
{
return [
'id' => 'id',
'name' => 'name'
'name' => 'name',
'theme' => 'theme'
];
}

View File

@ -0,0 +1,70 @@
<?php
namespace customerapi\models\dto;
use customerapi\models\available\EventAvailable;
class EventDTO extends \yii\base\Model
{
public $id;
public $start;
public $end;
public $seat_count;
public $created_at;
public $updated_at;
public $deleted_at;
public $active;
public $eventType;
public $trainer;
public $room;
public $eventRegistrations;
public $registrationCount;
public $hasFreeSeats;
function fields()
{
$fields = [
"id" => "id",
"start" => "start",
"end" => "end",
"seat_count" => "seat_count",
"active" => "active",
"reservationCount" => "registrationCount",
"hasFreeSeats" => "hasFreeSeats",
"registrations" => "eventRegistrations",
];
$fields['trainer'] = 'trainer';
$fields['eventType'] = 'eventType';
$fields['room'] = 'room';
// $fields['registrations'] = 'eventRegistrations';
return $fields;
}
/**
* @param $event /common/models/Event
*/
public static function fromEvent($event)
{
$dto = new EventDTO();
$dto->id = $event->id;
$dto->start = $event->start;
$dto->end = $event->end;
$dto->seat_count = $event->seat_count;
$dto->created_at = $event->created_at;
$dto->updated_at = $event->updated_at;
$dto->deleted_at = $event->deleted_at;
$dto->active = $event->active;
return $dto;
}
public static function fromEventWithRelatedObjects($event){
$eventDto = EventDTO::fromEvent($event);
$eventDto->trainer = TrainerDTO::fromTrainer($event->trainer);
$eventDto->room = RoomDTO::fromRoom($event->room);
$eventDto->eventType = EventTypeDTO::fromEventType($event->eventType);
return $eventDto;
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace customerapi\models\dto;
use common\helpers\AppDateTimeHelper;
use yii\base\Model;
class EventRegistrationDTO extends Model
{
public $id;
public $id_event;
public $id_customer;
public $id_card;
public $id_ticket;
public $created_at;
public $updated_at;
public $canceled_at;
public $deleted_at;
public $event;
function fields()
{
$fields = [
'id' => 'id',
'id_event' => 'id_event',
'id_customer' => 'id_customer',
'id_card' => 'id_card',
'id_ticket' => 'id_ticket',
'created_at' => 'created_at',
'updated_at' => 'updated_at',
'canceled_at' => 'canceled_at',
'deleted_at' => 'deleted_at',
];
$fields['event'] = 'event';
return $fields;
}
public static function fromEventRegistration($registration){
$dto = new EventRegistrationDTO();
$dto->id = $registration->id;
$dto->id_event = $registration->id_event;
$dto->id_customer = $registration->id_customer;
$dto->id_card = $registration->id_card;
$dto->id_ticket = $registration->id_ticket;
$dto->created_at = AppDateTimeHelper::convertMySqlDatetimeToPhpInteger( $registration->created_at);
$dto->updated_at = AppDateTimeHelper::convertMySqlDatetimeToPhpInteger($registration->updated_at);
$dto->canceled_at =AppDateTimeHelper::convertMySqlDatetimeToPhpInteger( $registration->canceled_at);
$dto->deleted_at = AppDateTimeHelper::convertMySqlDatetimeToPhpInteger($registration->deleted_at);
return $dto;
}
public static function fromEventRegistrationWithEvent($registration,$event){
$registrationDto = EventRegistrationDTO::fromEventRegistration($registration);
$registrationDto->event = EventDTO::fromEventWithRelatedObjects($event);
return $registrationDto;
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace customerapi\models\dto;
use yii\base\Model;
class EventTypeDTO extends Model
{
public $id;
public $name;
public $theme;
public $created_at;
public $updated_at;
public static function fromEventType($eventType){
$dto = new EventTypeDTO();
$dto->id = $eventType->id;
$dto->name = $eventType->name;
$dto->theme = $eventType->theme;
$dto->created_at = $eventType->created_at;
$dto->updated_at = $eventType->updated_at;
return $dto;
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace customerapi\models\dto;
use yii\base\Model;
class RoomDTO extends Model
{
public $id;
public $name;
public $seat_count;
public $created_at;
public $updated_at;
public static function fromRoom($room)
{
$dto = new RoomDTO();
$dto->id = $room->id;
$dto->name = $room->name;
$dto->seat_count = $room->seat_count;
$dto->created_at = $room->created_at;
$dto->updated_at = $room->updated_at;
return $dto;
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace customerapi\models\dto;
use yii\base\Model;
class TrainerDTO extends Model
{
public $id;
public $name;
public $phone;
public $email;
public $password;
public $active;
public $created_at;
public $updated_at;
public static function fromTrainer($trainer){
$dto = new TrainerDTO();
$dto->id = $trainer->id;
$dto->name = $trainer->name;
$dto->phone = $trainer->phone;
$dto->email = $trainer->email;
$dto->password = $trainer->password;
$dto->active = $trainer->active;
$dto->created_at = $trainer->created_at;
$dto->updated_at = $trainer->updated_at;
return $dto;
}
}

View File

@ -242,6 +242,7 @@ class CustomerController extends Controller
$model->customer = $customer;
$model->email = $customer->email;
$model->companyName = Helper::getCompanyName();
$model->groupTrainingUrl = Helper::getGroupTrainingUrl();
if ( \Yii::$app->request->isPost ){
$model->load(\Yii::$app->request->post());

View File

@ -19,6 +19,7 @@ class PasswordChangeModel extends Model
public $card;
public $companyName;
public $plainPassword;
public $groupTrainingUrl;
/**
* @inheritdoc