mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
Merge branch 'event-card-refacto' into dev
This commit is contained in:
commit
cbe949663e
@ -2,6 +2,7 @@
|
||||
|
||||
## next deploy
|
||||
|
||||
- Feature the next event in the event page
|
||||
- Documentation for installing behind a proxy
|
||||
- Ability to install behind a proxy
|
||||
- Improved docker image building time
|
||||
@ -9,6 +10,8 @@
|
||||
- Run the docker image with the system user
|
||||
- During the setup, autoconfigure the main domain
|
||||
- During the setup, ask to set ALLOW_INSECURE_HTTP if DEFAULT_PROTOCOL was set to http
|
||||
- Fix a bug: unable to edit an event
|
||||
- Fix a bug: times are not shown in admin/events monitoring page
|
||||
- Fix a bug: unable to generate the secret key base during the setup
|
||||
- Fix a bug: error message during the setup: the input device is not a TTY
|
||||
- Fix a bug: when Fab-manager was installed as non-root user, unable to compile the assets during the upgrade
|
||||
|
2
Procfile
2
Procfile
@ -1,3 +1,3 @@
|
||||
#web: bundle exec rails server puma -p $PORT
|
||||
web: bundle exec rails server puma -p $PORT
|
||||
worker: bundle exec sidekiq -C ./config/sidekiq.yml
|
||||
webpack: bin/webpacker-dev-server
|
||||
|
135
app/frontend/src/javascript/components/events/event-card.tsx
Normal file
135
app/frontend/src/javascript/components/events/event-card.tsx
Normal file
@ -0,0 +1,135 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { react2angular } from 'react2angular';
|
||||
import { IApplication } from '../../models/application';
|
||||
import { Loader } from '../base/loader';
|
||||
import { Event } from '../../models/event';
|
||||
import FormatLib from '../../lib/format';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
interface EventCardProps {
|
||||
event: Event,
|
||||
cardType: 'sm' | 'md' | 'lg'
|
||||
}
|
||||
|
||||
export const EventCard: React.FC<EventCardProps> = ({ event, cardType }) => {
|
||||
const { t } = useTranslation('public');
|
||||
|
||||
/**
|
||||
* Format description to remove HTML tags and set a maximum character count
|
||||
*/
|
||||
const formatText = (text: string, count: number) => {
|
||||
text = text.replace(/(<\/p>|<\/h4>|<\/h5>|<\/h6>|<\/pre>|<\/blockquote>)/g, '\n');
|
||||
text = text.replace(/<br\s*\/?>/g, '\n');
|
||||
text = text.replace(/<\/?\w+[^>]*>/g, '');
|
||||
if (text.length > count) {
|
||||
text = text.slice(0, count) + '…';
|
||||
}
|
||||
text = text.replace(/\n+/g, '<br />');
|
||||
return text;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the formatted localized date of the event
|
||||
*/
|
||||
const formatDate = (): string => {
|
||||
const startDate = new Date(event.start_date);
|
||||
const endDate = new Date(event.end_date);
|
||||
const singleDayEvent = startDate.getFullYear() === endDate.getFullYear() &&
|
||||
startDate.getMonth() === endDate.getMonth() &&
|
||||
startDate.getDate() === endDate.getDate();
|
||||
return singleDayEvent
|
||||
? t('app.public.home.on_the_date', { DATE: FormatLib.date(event.start_date) })
|
||||
: t('app.public.home.from_date_to_date', { START: FormatLib.date(event.start_date), END: FormatLib.date(event.end_date) });
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the formatted localized hours of the event
|
||||
*/
|
||||
const formatTime = (): string => {
|
||||
return event.all_day
|
||||
? t('app.public.home.all_day')
|
||||
: t('app.public.home.from_time_to_time', { START: FormatLib.time(event.start_date), END: FormatLib.time(event.end_date) });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`event-card event-card--${cardType}`}>
|
||||
{event.event_image
|
||||
? <div className="event-card-picture">
|
||||
<img src={event.event_image} alt="" />
|
||||
</div>
|
||||
: cardType !== 'sm' &&
|
||||
<div className="event-card-picture">
|
||||
<i className="fas fa-image"></i>
|
||||
</div>
|
||||
}
|
||||
<div className="event-card-desc">
|
||||
<header>
|
||||
<span className={`badge bg-${event.category.slug}`}>{event.category.name}</span>
|
||||
<p className='title'>{event?.title}</p>
|
||||
</header>
|
||||
{cardType !== 'sm' &&
|
||||
<p dangerouslySetInnerHTML={{ __html: formatText(event.description, cardType === 'md' ? 500 : 400) }}></p>
|
||||
}
|
||||
</div>
|
||||
<div className="event-card-info">
|
||||
{cardType !== 'md' &&
|
||||
<p>
|
||||
{formatDate()}
|
||||
<span>{formatTime()}</span>
|
||||
</p>
|
||||
}
|
||||
<div className="grid">
|
||||
{cardType !== 'md' &&
|
||||
event.event_themes.map(theme => {
|
||||
return (<div key={theme.name} className="grid-item">
|
||||
<i className="fa fa-tags"></i>
|
||||
<h6>{theme.name}</h6>
|
||||
</div>);
|
||||
})
|
||||
}
|
||||
{(cardType !== 'md' && event.age_range) &&
|
||||
<div className="grid-item">
|
||||
<i className="fa fa-users"></i>
|
||||
<h6>{event.age_range?.name}</h6>
|
||||
</div>
|
||||
}
|
||||
{cardType === 'md' &&
|
||||
<>
|
||||
<div className="grid-item">
|
||||
<i className="fa fa-calendar"></i>
|
||||
<h6>{formatDate()}</h6>
|
||||
</div>
|
||||
<div className="grid-item">
|
||||
<i className="fa fa-clock"></i>
|
||||
<h6>{formatTime()}</h6>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
<div className="grid-item">
|
||||
<i className="fa fa-user"></i>
|
||||
{event.nb_free_places > 0 && <h6>{t('app.public.home.still_available') + event.nb_free_places}</h6>}
|
||||
{event.nb_total_places > 0 && event.nb_free_places <= 0 && <h6>{t('app.public.home.event_full')}</h6>}
|
||||
{!event.nb_total_places && <h6>{t('app.public.home.without_reservation')}</h6>}
|
||||
</div>
|
||||
<div className="grid-item">
|
||||
<i className="fa fa-bookmark"></i>
|
||||
{event.amount === 0 && <h6>{t('app.public.home.free_admission')}</h6>}
|
||||
{event.amount > 0 && <h6>{t('app.public.home.full_price') + FormatLib.price(event.amount)}</h6>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const EventCardWrapper: React.FC<EventCardProps> = ({ event, cardType }) => {
|
||||
return (
|
||||
<Loader>
|
||||
<EventCard event={event} cardType={cardType} />
|
||||
</Loader>
|
||||
);
|
||||
};
|
||||
|
||||
Application.Components.component('eventCard', react2angular(EventCardWrapper, ['event', 'cardType']));
|
@ -72,6 +72,7 @@ Application.Controllers.controller('EventsController', ['$scope', '$state', 'Eve
|
||||
// reinitialize results datasets
|
||||
$scope.page = 1;
|
||||
$scope.eventsGroupByMonth = {};
|
||||
$scope.featuredEevent = null;
|
||||
$scope.events = [];
|
||||
$scope.monthOrder = [];
|
||||
$scope.noMoreResults = false;
|
||||
@ -94,6 +95,16 @@ Application.Controllers.controller('EventsController', ['$scope', '$state', 'Eve
|
||||
*/
|
||||
$scope.onSingleDay = function (event) { moment(event.start_date).isSame(event.end_date, 'day'); };
|
||||
|
||||
/**
|
||||
* Move down the viewport to the featured event
|
||||
*/
|
||||
$scope.scrollToFeaturedEvent = function () {
|
||||
const card = document.getElementsByClassName('featured-event')[0];
|
||||
if (card) {
|
||||
card.childNodes[0].scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
}
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
/**
|
||||
@ -117,7 +128,8 @@ Application.Controllers.controller('EventsController', ['$scope', '$state', 'Eve
|
||||
});
|
||||
});
|
||||
$scope.eventsGroupByMonth = Object.assign($scope.eventsGroupByMonth, eventsGroupedByMonth);
|
||||
return $scope.monthOrder = Object.keys($scope.eventsGroupByMonth);
|
||||
$scope.monthOrder = Object.keys($scope.eventsGroupByMonth);
|
||||
$scope.featuredEevent = _.minBy(events.filter(e => moment(e.start_date).isAfter()), e => e.start_date);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
@import "modules/base/fab-text-editor";
|
||||
@import "modules/base/labelled-input";
|
||||
@import "modules/calendar/calendar";
|
||||
@import "modules/events/event";
|
||||
@import "modules/form/form-input";
|
||||
@import "modules/form/form-item";
|
||||
@import "modules/form/form-rich-text";
|
||||
|
202
app/frontend/src/stylesheets/modules/events/event.scss
Normal file
202
app/frontend/src/stylesheets/modules/events/event.scss
Normal file
@ -0,0 +1,202 @@
|
||||
.event {
|
||||
&-card {
|
||||
border: 1px solid var(--gray-soft-dark);
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
color: var(--gray-hard-darkest);
|
||||
&:hover {
|
||||
color: var(--gray-hard-darkest);
|
||||
border-color: var(--gray-hard);
|
||||
cursor: pointer;
|
||||
.event-card-picture,
|
||||
.event-card-info { border-color: var(--gray-hard); }
|
||||
}
|
||||
|
||||
&-picture {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
font-size: 8rem;
|
||||
color: var(--gray-soft-light);
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
&-desc {
|
||||
padding: 15px 15px 30px;
|
||||
header {
|
||||
margin-bottom: 1rem;
|
||||
p {
|
||||
margin: 0;
|
||||
font-size: 2rem;
|
||||
font-weight: 900;
|
||||
line-height: 1.3;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.badge {
|
||||
min-width: auto;
|
||||
max-width: min(16ch, 33%);
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
margin: 0 0 10px 15px;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
p { margin: 0; }
|
||||
}
|
||||
&-info {
|
||||
padding: 15px 20px;
|
||||
& > p {
|
||||
font-size: 1.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--main);
|
||||
span {
|
||||
display: block;
|
||||
font-size: 0.75em;
|
||||
font-weight: 400;
|
||||
line-height: 1.2;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
align-items: baseline;
|
||||
gap: 15px;
|
||||
&-item {
|
||||
min-height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
i {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 10px;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
color: var(--main);
|
||||
}
|
||||
h6 { margin: 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Card size specific
|
||||
&-card--sm {
|
||||
display: grid;
|
||||
grid-template-rows: max-content 1fr;
|
||||
grid-template-columns: 1fr max-content;
|
||||
.event-card-desc {
|
||||
grid-area: 1/1/2/2;
|
||||
padding-bottom: 10px;
|
||||
header {
|
||||
margin-bottom: 0;
|
||||
p { font-size: 1.6rem; }
|
||||
}
|
||||
}
|
||||
.event-card-picture {
|
||||
grid-area: 1/2/3/3;
|
||||
width: 160px;
|
||||
display: none;
|
||||
border-left: 1px solid var(--gray-soft-dark);
|
||||
@media (min-width: 500px) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.event-card-info {
|
||||
grid-area: 2/1/3/2;
|
||||
padding: 0 15px 15px;
|
||||
.grid {
|
||||
gap: 10px 15px;
|
||||
&-item i {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
//margin-right: 6px;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
//color: var(--gray-hard-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&-card--md {
|
||||
display: grid;
|
||||
grid-template-rows: min-content 1fr min-content;
|
||||
.event-card-picture {
|
||||
height: 250px;
|
||||
border-bottom: 1px solid var(--gray-soft-dark);
|
||||
}
|
||||
.event-card-info {
|
||||
margin-top: auto;
|
||||
padding-bottom: 30px;
|
||||
border-top: 1px solid var(--gray-soft-dark);
|
||||
}
|
||||
}
|
||||
&-card--lg {
|
||||
border: 1px solid var(--gray-hard);
|
||||
.event-card-info {
|
||||
padding-top: 0;
|
||||
}
|
||||
.event-card-picture {
|
||||
border-bottom: 1px solid var(--gray-hard);
|
||||
img { max-height: 300px; }
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
grid-column: span 2;
|
||||
display: grid;
|
||||
grid-template-columns: 3fr 2fr;
|
||||
.event-card-desc { grid-area: 1/1/2/2; }
|
||||
.event-card-info { grid-area: 2/1/3/2; }
|
||||
.event-card-picture {
|
||||
grid-area: 1/2/3/3;
|
||||
border-bottom: none;
|
||||
border-left: 1px solid var(--gray-hard);
|
||||
img { max-height: none; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// layout specific
|
||||
&-home {
|
||||
h4 {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
column-gap: 1rem;
|
||||
i { margin-right: 1rem;}
|
||||
}
|
||||
&-list {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 30px;
|
||||
margin-bottom: 5rem;
|
||||
@media (min-width: 480px) {
|
||||
grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-focus {
|
||||
display: grid;
|
||||
margin-bottom: 50px;
|
||||
|
||||
@media (min-width: 992px) {
|
||||
grid-template-columns: repeat(auto-fill, minmax(425px, 1fr));
|
||||
gap: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&-monthList {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 15px;
|
||||
margin-bottom: 2rem;
|
||||
@media (min-width: 768px) {
|
||||
grid-template-columns: repeat(auto-fill, minmax(430px, 1fr));
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@
|
||||
<!--One day event-->
|
||||
<span ng-if="(event.start_date | amDateFormat:'LL')==(event.end_date | amDateFormat:'LL')">
|
||||
{{ 'app.admin.events.on_DATE' | translate:{DATE:(event.start_date | amDateFormat:'LL')} }}
|
||||
<span ng-if="event.all_day == 'false'">
|
||||
<span ng-if="event.all_day === false">
|
||||
{{ 'app.admin.events.from_TIME' | translate:{TIME:(event.start_date | amDateFormat:'LT')} }}
|
||||
<span class="text-sm font-thin" translate>{{ 'app.admin.events.to_time' }}</span>
|
||||
{{event.end_date | amDateFormat:'LT'}}
|
||||
@ -39,8 +39,8 @@
|
||||
<span ng-if="(event.start_date | amDateFormat:'LL')!=(event.end_date | amDateFormat:'LL')">
|
||||
{{'app.admin.events.from_DATE' | translate:{DATE:(event.start_date | amDateFormat:'LL')} }}
|
||||
{{'app.admin.events.to_date' | translate}} {{event.end_date | amDateFormat:'LL'}}
|
||||
<br ng-if="event.all_day == 'false'"/>
|
||||
<span ng-if="event.all_day == 'false'">
|
||||
<br ng-if="event.all_day === false"/>
|
||||
<span ng-if="event.all_day === false">
|
||||
{{ 'app.admin.events.from_TIME' | translate:{TIME:(event.start_date | amDateFormat:'LT')} }}
|
||||
<span class="text-sm font-thin" translate>{{ 'app.admin.events.to_time' }}</span>
|
||||
{{event.end_date | amDateFormat:'LT'}}
|
||||
|
@ -138,10 +138,10 @@
|
||||
<label class="v-bottom" translate>{{ 'app.shared.event.all_day' }}</label>
|
||||
<div class="inline v-top">
|
||||
<label class="checkbox-inline">
|
||||
<input type="radio" name="event[all_day]" ng-model="event.all_day" value="true" required/> {{ 'app.shared.buttons.yes' | translate }}
|
||||
<input type="radio" name="event[all_day]" ng-model="event.all_day" ng-value="true" required/> {{ 'app.shared.buttons.yes' | translate }}
|
||||
</label>
|
||||
<label class="checkbox-inline">
|
||||
<input type="radio" name="event[all_day]" ng-model="event.all_day" value="false"/> {{ 'app.shared.buttons.no' | translate }}
|
||||
<input type="radio" name="event[all_day]" ng-model="event.all_day" ng-value="false"/> {{ 'app.shared.buttons.no' | translate }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -180,7 +180,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-b row" ng-if="event.all_day =='false'">
|
||||
<div class="m-b row" ng-if="event.all_day === false">
|
||||
<div class="col-xs-6">
|
||||
<label translate>{{ 'app.shared.event.start_time' }}</label>
|
||||
<div>
|
||||
|
@ -40,41 +40,31 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="event-focus" ng-if="featuredEevent && (!currentUser || currentUser.role === 'member')">
|
||||
<event-card style="display: contents"
|
||||
event="featuredEevent"
|
||||
card-type="'lg'"
|
||||
ui-sref="app.public.events_show({id: featuredEevent.id})">
|
||||
</event-card>
|
||||
</div>
|
||||
<div ng-if="isAuthorized(['admin', 'manager'])">
|
||||
<button class="btn btn-default" ng-click="scrollToFeaturedEvent()" translate>{{ 'app.public.events_list.show_featured' }}</button>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="month in monthOrder">
|
||||
<h1>{{monthNames[month.split(',')[0] - 1]}}, {{month.split(',')[1]}}</h1>
|
||||
|
||||
<div class="month-events-list" ng-repeat="event in (eventsGroupByMonth[month].length/3 | array)">
|
||||
<a class="Event" ng-repeat="event in eventsGroupByMonth[month].slice(3*$index, 3*$index + 3)" ui-sref="app.public.events_show({id: event.id})">
|
||||
<div class="Event-desc">
|
||||
<h5 class="text-xs m-t-n">{{event.category.name}}</h5>
|
||||
<h4 class="m-n text-sm clear l-n">{{event.title}}</h4>
|
||||
<h3 class="m-n" ng-show="onSingleDay(event)">{{event.start_date | amDateFormat:'L'}}</h3>
|
||||
<h3 class="m-n" ng-hide="onSingleDay(event)">{{event.start_date | amDateFormat:'L'}} <span class="text-sm font-thin" translate> {{ 'app.public.events_list.to_date' }} </span> {{event.end_date | amDateFormat:'L'}}</h3>
|
||||
|
||||
<h6 class="m-n" ng-if="!event.amount" translate>{{ 'app.public.events_list.free_admission' }}</h6>
|
||||
<h6 class="m-n" ng-if="event.amount">{{ 'app.public.events_list.full_price_' | translate }} {{event.amount | currency}} <span ng-repeat="price in event.prices">/ {{ price.category.name }} {{price.amount | currency}}</span></h6>
|
||||
|
||||
<div>
|
||||
<span class="text-black-light text-xs m-r-xs" ng-repeat="theme in event.event_themes">
|
||||
<i class="fa fa-tags" aria-hidden="true"></i> {{theme.name}}
|
||||
</span>
|
||||
<span class="text-black-light text-xs" ng-if="event.age_range"><i class="fa fa-users" aria-hidden="true"></i> {{event.age_range.name}}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="text-black-light text-xs" ng-if="event.nb_free_places > 0">{{event.nb_free_places}} {{ 'app.public.events_list.still_available' | translate }}</span>
|
||||
<span class="text-black-light text-xs" ng-if="event.nb_total_places > 0 && event.nb_free_places <= 0" translate>{{ 'app.public.events_list.sold_out' }}</span>
|
||||
<span class="text-black-light text-xs" ng-if="event.nb_total_places == -1" translate>{{ 'app.public.events_list.cancelled' }}</span>
|
||||
<span class="text-black-light text-xs" ng-if="!event.nb_total_places" translate>{{ 'app.public.events_list.without_reservation' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Event Image -->
|
||||
<div class="Event-picture" ng-if="event.event_image">
|
||||
<img ng-src="{{event.event_image_small}}" title="{{event.title}}">
|
||||
</div>
|
||||
</a>
|
||||
<div class="event-monthList">
|
||||
<event-card style="display: contents"
|
||||
event="event"
|
||||
ng-repeat="event in eventsGroupByMonth[month]"
|
||||
card-type="'sm'"
|
||||
ng-if="isAuthorized(['admin', 'manager']) || event.id !== featuredEevent.id"
|
||||
ng-class="{'featured-event': event.id === featuredEevent.id}"
|
||||
ui-sref="app.public.events_show({id: event.id})">
|
||||
</event-card>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
@ -86,5 +76,3 @@
|
||||
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
@ -6,48 +6,12 @@
|
||||
</a>
|
||||
</h4>
|
||||
|
||||
<div class="home-events-list" ng-repeat="event in (upcomingEvents.length/3 | array)">
|
||||
<div class="Event" ng-repeat="event in upcomingEvents.slice(3*$index, 3*$index + 3)" ui-sref="app.public.events_show({id: event.id})">
|
||||
<div class="Event-picture">
|
||||
<img src="data:image/png;base64," data-src="holder.js/100%x100%/text:/font:'Font Awesome 5 Free'/icon" bs-holder ng-if="!event.event_image" class="img-responsive">
|
||||
<img ng-if="event.event_image" src="{{event.event_image_medium}}">
|
||||
</div>
|
||||
|
||||
<div class="Event-desc">
|
||||
<h3>{{event.title}}</h3>
|
||||
<span class="v-middle badge text-xs" ng-class="'bg-{{event.category.slug}}'">{{event.category.name}}</span>
|
||||
<p ng-bind-html="event.description | simpleText | humanize : 500 | breakFilter"></p>
|
||||
</div>
|
||||
|
||||
<div class="Event-info">
|
||||
<div class="Event-info-item">
|
||||
<i class="fa fa-calendar"></i>
|
||||
<h6 class="" ng-hide="isOneDayEvent(event)">{{ 'app.public.home.from_date_to_date' | translate:{START:(event.start_date | amDateFormat:'L'), END:(event.end_date | amDateFormat:'L')} }}</h6>
|
||||
<h6 class="" ng-show="isOneDayEvent(event)">{{ 'app.public.home.on_the_date' | translate:{DATE:(event.start_date | amDateFormat:'L')} }}</h6>
|
||||
</div>
|
||||
<div class="Event-info-item">
|
||||
<i class="fas fa-clock"></i>
|
||||
<h6 class="">
|
||||
<span ng-if="event.all_day == 'true'" translate>{{ 'app.public.home.all_day' }}</span>
|
||||
<span ng-if="event.all_day == 'false'">{{ 'app.public.home.from_time_to_time' | translate:{START:(event.start_date | amDateFormat:'LT'), END:(event.end_date | amDateFormat:'LT')} }}</span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="Event-info-item">
|
||||
<i class="fa fa-user"></i>
|
||||
<h6 class="">
|
||||
<span ng-if="event.nb_free_places > 0">{{ 'app.public.home.still_available' | translate }} {{event.nb_free_places}}</span>
|
||||
<span ng-if="!event.nb_total_places" translate>{{ 'app.public.home.without_reservation' }}</span>
|
||||
<span ng-if="event.nb_total_places > 0 && event.nb_free_places <= 0" translate>{{ 'app.public.home.event_full' }}</span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="Event-info-item">
|
||||
<i class="fa fa-bookmark"></i>
|
||||
<h6 class="">
|
||||
<span ng-if="event.amount == 0" translate>{{ 'app.public.home.free_admission' }}</span>
|
||||
<span ng-if="event.amount > 0">{{ 'app.public.home.full_price' | translate }} {{event.amount | currency}}</span>
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="event-home-list" ng-repeat="event in (upcomingEvents.length/3 | array)">
|
||||
<event-card style="display: contents"
|
||||
event="event"
|
||||
card-type="'md'"
|
||||
ng-repeat="event in upcomingEvents.slice(3*$index, 3*$index + 3)"
|
||||
ui-sref="app.public.events_show({id: event.id})">
|
||||
</event-card>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -84,6 +84,10 @@ class Event < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def all_day?
|
||||
availability.start_at.hour.zero?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def event_recurrence
|
||||
|
@ -6,12 +6,12 @@ class EventPolicy < ApplicationPolicy
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
if user.nil? || (user && !user.admin? && !user.manager?)
|
||||
scope.includes(:event_image, :event_files, :availability, :category)
|
||||
scope.includes(:event_image, :event_files, :availability, :category, :event_price_categories, :age_range, :events_event_themes, :event_themes)
|
||||
.where('availabilities.start_at >= ?', DateTime.current)
|
||||
.order('availabilities.start_at ASC')
|
||||
.references(:availabilities)
|
||||
else
|
||||
scope.includes(:event_image, :event_files, :availability, :category)
|
||||
scope.includes(:event_image, :event_files, :availability, :category, :event_price_categories, :age_range, :events_event_themes, :event_themes)
|
||||
.references(:availabilities)
|
||||
end
|
||||
end
|
||||
|
@ -37,8 +37,8 @@ class EventService
|
||||
start_at = DateTime.new(start_date.year, start_date.month, start_date.day, 0, 0, 0, start_date.zone)
|
||||
end_at = DateTime.new(end_date.year, end_date.month, end_date.day, 23, 59, 59, end_date.zone)
|
||||
else
|
||||
start_at = DateTime.new(start_date.year, start_date.month, start_date.day, start_time.hour, start_time.min, start_time.sec, start_date.zone)
|
||||
end_at = DateTime.new(end_date.year, end_date.month, end_date.day, end_time.hour, end_time.min, end_time.sec, end_date.zone)
|
||||
start_at = DateTime.new(start_date.year, start_date.month, start_date.day, start_time&.hour, start_time&.min, start_time&.sec, start_date.zone)
|
||||
end_at = DateTime.new(end_date.year, end_date.month, end_date.day, end_time&.hour, end_time&.min, end_time&.sec, end_date.zone)
|
||||
end
|
||||
{ start_at: start_at, end_at: end_at }
|
||||
end
|
||||
|
@ -32,7 +32,7 @@ json.end_time event.availability.end_at
|
||||
json.month t('date.month_names')[event.availability.start_at.month]
|
||||
json.month_id event.availability.start_at.month
|
||||
json.year event.availability.start_at.year
|
||||
json.all_day event.availability.start_at.hour.zero? ? 'true' : 'false'
|
||||
json.all_day event.all_day?
|
||||
json.availability do
|
||||
json.id event.availability.id
|
||||
json.start_at event.availability.start_at
|
||||
|
@ -289,6 +289,7 @@ en:
|
||||
full_price_: "Full price:"
|
||||
to_date: "to" #eg. from 01/01 to 01/05
|
||||
all_themes: "All themes"
|
||||
show_featured: "Show the featured event"
|
||||
#details and booking of an event
|
||||
events_show:
|
||||
event_description: "Event description"
|
||||
|
Loading…
x
Reference in New Issue
Block a user