import m from 'mithril'; import { Button } from 'polythene-mithril'; import Stream from 'mithril/stream'; import { styler } from 'polythene-core-css'; import { DropdownCard, Chip } from 'amiv-web-ui-components'; // eslint-disable-next-line import/extensions import { apiUrl } from 'networkConfig'; import ItemView from '../views/itemView'; import { ParticipantsController, ParticipantsTable } from './participants'; import { dateFormatter } from '../utils'; import { Property, FilterChip, icons } from '../views/elements'; import { colors } from '../style'; const viewLayout = [ { '.propertyLangIndicator': { width: '30px', height: '20px', float: 'left', 'background-color': 'rgb(031,045,084)', 'border-radius': '10px', 'text-align': 'center', 'line-height': '20px', color: 'rgb(255,255,255)', 'margin-right': '10px', 'font-size': '11px', }, '.eventViewLeft': { 'grid-column': 1, }, '.eventViewRight': { 'grid-column': 2, }, '.eventViewRight h4': { 'margin-top': '0px', }, }, ]; styler.add('eventView', viewLayout); // small helper class to display both German and English content together, dependent // on which content is available. class DuoLangProperty { view({ attrs: { title, de, en } }) { // TODO Lang indicators should be smaller and there should be less margin // between languages return m( Property, { title }, de ? m('div', [ m('div', { className: 'propertyLangIndicator' }, 'DE'), m('p', de), ]) : '', en ? m('div', [ m('div', { className: 'propertyLangIndicator' }, 'EN'), m('p', en), ]) : '', ); } } class ParticipantsSummary { constructor() { this.onlyAccepted = true; } view({ attrs: { participants, additionalFields = "{'properties': {}}" } }) { // Parse the JSON from additional fields into an object const parsedParticipants = participants.map(signup => ({ ...signup, additional_fields: signup.additional_fields ? JSON.parse(signup.additional_fields) : {}, })); // Filter if only accepted participants should be shown const filteredParticipants = parsedParticipants.filter( participant => (this.onlyAccepted ? participant.accepted : true), ); // check which additional fields should get summarized let hasSBB = false; let hasFood = false; if (additionalFields) { hasSBB = 'sbb_abo' in JSON.parse(additionalFields).properties; hasFood = 'food' in JSON.parse(additionalFields).properties; } return m('div', [ m('div', { style: { height: '50px', 'overflow-x': 'auto', 'overflow-y': 'hidden', 'white-space': 'nowrap', padding: '0px 5px', }, }, [].concat(['Filters: '], ...[ m(FilterChip, { selected: this.onlyAccepted, onclick: () => { this.onlyAccepted = !this.onlyAccepted; }, }, 'accepted users'), ])), hasSBB ? m('div', { style: { display: 'flex' } }, [ m(Property, { title: 'No SBB', leftAlign: false }, filteredParticipants.filter( signup => signup.additional_fields.sbb_abo === 'None', ).length), m(Property, { title: 'GA', leftAlign: false }, filteredParticipants.filter( signup => signup.additional_fields.sbb_abo === 'GA', ).length), m(Property, { title: 'Halbtax', leftAlign: false }, filteredParticipants.filter( signup => signup.additional_fields.sbb_abo === 'Halbtax', ).length), m(Property, { title: 'Gleis 7', leftAlign: false }, filteredParticipants.filter( signup => signup.additional_fields.sbb_abo === 'Gleis 7', ).length), ]) : '', hasFood ? m('div', { style: { display: 'flex' } }, [ m(Property, { title: 'Omnivors', leftAlign: false }, filteredParticipants.filter( signup => signup.additional_fields.food === 'Omnivor', ).length), m(Property, { title: 'Vegis', leftAlign: false }, filteredParticipants.filter( signup => signup.additional_fields.food === 'Vegi', ).length), m(Property, { title: 'Vegans', leftAlign: false }, filteredParticipants.filter( signup => signup.additional_fields.food === 'Vegan', ).length), ]) : '', m('textarea', { style: { opacity: '0', width: '0px' }, id: 'participantsemails', }, filteredParticipants.map(signup => signup.email).toString().replace(/,/g, '; ')), m(Button, { label: 'Copy Emails', events: { onclick: () => { document.getElementById('participantsemails').select(); document.execCommand('copy'); }, }, }), ]); } } export default class viewEvent extends ItemView { constructor(vnode) { super(vnode); this.participantsCtrl = new ParticipantsController(); this.description = false; this.advertisement = false; this.registration = false; this.modalDisplay = Stream('none'); } oninit() { this.participantsCtrl.setEventId(this.data._id); } cloneEvent() { const event = Object.assign({}, this.data); const eventInfoToDelete = [ '_id', '_created', '_etag', '_links', '_updated', 'signup_count', 'unaccepted_count', '__proto__', ]; const now = new Date(); if (event.time_end < `${now.toISOString().slice(0, -5)}Z`) { eventInfoToDelete.push(...[ 'time_advertising_end', 'time_advertising_start', 'time_end', 'time_register_end', 'time_deregister_end', 'time_register_start', 'time_start']); } eventInfoToDelete.forEach((key) => { delete event[key]; }); this.controller.changeModus('new'); this.controller.data = event; } view() { let displaySpots = '-'; const stdMargin = { margin: '5px' }; // Get the image and insert it inside the modal - // use its "alt" text as a caption const modalImg = document.getElementById('modalImg'); if (this.data.spots !== 0) { displaySpots = this.data.spots; } return this.layout([ // this div is the title line m('div.maincontainer', [ // event image if existing this.data.img_thumbnail ? m('img', { src: `${apiUrl}${this.data.img_thumbnail.file}`, height: '50px', style: { float: 'left', margin: '0 5px' }, }) : '', m('h1', this.data.title_de || this.data.title_en), ]), // below the title, most important details are listed m('div.maincontainer', { style: { display: 'flex' } }, [ this.data.type && m(Property, { style: stdMargin, title: 'Type', }, `${this.data.type.charAt(0).toUpperCase() + this.data.type.slice(1)}`), (this.data.spots !== null && 'signup_count' in this.data && this.data.signup_count !== null) ? m(Property, { style: stdMargin, title: 'Signups', }, `${this.data.signup_count} / ${displaySpots}`) : '', this.data.location && m(Property, { style: stdMargin, title: 'Location', }, `${this.data.location}`), this.data.time_start && m(Property, { title: 'Time', style: stdMargin, }, `${dateFormatter(this.data.time_start)} - ${dateFormatter(this.data.time_end)}`), this.data.moderator && m(Property, { title: 'Moderator', style: stdMargin, }, m.trust(`${this.data.moderator.firstname} ${this.data.moderator.lastname} (<a href='mailto:${this.data.moderator.email}'>${this.data.moderator.email}</a>)`)), ]), // everything else is not listed in DropdownCards, which open only on request m('div.viewcontainer', [ m('div.viewcontainercolumn', [ m(DropdownCard, { title: 'description' }, [ m(DuoLangProperty, { title: 'Catchphrase', de: this.data.catchphrase_de, en: this.data.catchphrase_en, }), m(DuoLangProperty, { title: 'Description', de: this.data.description_de, en: this.data.description_en, }), ]), m(DropdownCard, { title: 'advertisement', style: { margin: '10px 0' } }, [ [ m(Chip, { svg: this.data.show_announce ? icons.checked : icons.clear, border: '1px #aaaaaa solid', }, 'announce'), m(Chip, { svg: this.data.show_infoscreen ? icons.checked : icons.clear, border: '1px #aaaaaa solid', margin: '4px', }, 'infoscreen'), m(Chip, { svg: this.data.show_website ? icons.checked : icons.clear, border: '1px #aaaaaa solid', }, 'website'), ], this.data.time_advertising_start ? m( Property, { title: 'Advertising Time' }, `${dateFormatter(this.data.time_advertising_start)} - ` + `${dateFormatter(this.data.time_advertising_end)}`, ) : '', this.data.priority ? m( Property, { title: 'Priority' }, `${this.data.priority}`, ) : '', ]), m(DropdownCard, { title: 'Registration', style: { margin: '10px 0' } }, [ this.data.price ? m(Property, { title: 'Price' }, `${this.data.price}`) : '', this.data.time_register_start ? m( Property, { title: 'Registration Time' }, `${dateFormatter(this.data.time_register_start)} - ` + `${dateFormatter(this.data.time_register_end)}`, ) : '', this.data.time_deregister_end ? m( Property, { title: 'Deregistration Time' }, `${dateFormatter(this.data.time_deregister_end)}`, ) : '', this.data.selection_strategy ? m( Property, { title: 'Selection Mode' }, m.trust(this.data.selection_strategy), ) : '', this.data.allow_email_signup && m(Property, 'non AMIV-Members allowed'), this.data.additional_fields && m( Property, { title: 'Registration Form' }, this.data.additional_fields, ), this.data.external_registration && m( Property, { title: 'External Registration' }, m('a', { href: this.data.external_registration, target: '_blank' }, this.data.external_registration), ), ]), // a list of email adresses of all participants, easy to copy-paste this.data.spots !== null ? m(DropdownCard, { title: 'Participants Summary', style: { margin: '10px 0' }, }, m(ParticipantsSummary, { participants: this.participantsCtrl.allParticipants, additionalFields: this.data.additional_fields, })) : '', m(DropdownCard, { title: 'Images' }, [ m('div', { style: { display: 'flex', }, }, [ m('div', { style: { width: '40%', padding: '5px', }, }, [ this.data.img_poster && m('div', 'Poster'), this.data.img_poster && m('img', { src: `${apiUrl}${this.data.img_poster.file}`, width: '100%', onclick: () => { this.modalDisplay('block'); modalImg.src = `${apiUrl}${this.data.img_poster.file}`; }, }), ]), m('div', { style: { width: '52%', padding: '5px', }, }, [ m('div', [ this.data.img_infoscreen && m('div', 'Infoscreen'), this.data.img_infoscreen && m('img', { src: `${apiUrl}${this.data.img_infoscreen.file}`, width: '100%', onclick: () => { this.modalDisplay('block'); modalImg.src = `${apiUrl}${this.data.img_infoscreen.file}`; }, }), ]), ]), ]), ]), ]), m('div.viewcontainercolumn', { style: { width: '50em' } }, [ this.data.time_register_start ? m(ParticipantsTable, { title: 'Accepted Participants', filePrefix: 'accepted', event: this.data, waitingList: false, additional_fields_schema: this.data.additional_fields, participantsCtrl: this.participantsCtrl, }) : '', this.data.time_register_start ? m(ParticipantsTable, { title: 'Participants on Waiting List', filePrefix: 'waitinglist', event: this.data, waitingList: true, additional_fields_schema: this.data.additional_fields, participantsCtrl: this.participantsCtrl, }) : '', ]), ]), m('div', { id: 'imgModal', style: { display: this.modalDisplay(), position: 'fixed', 'z-index': '100', 'padding-top': '100px', left: 0, top: 0, width: '100vw', height: '100vh', overflow: 'auto', 'background-color': 'rgba(0, 0, 0, 0.9)', }, }, [ m('img', { id: 'modalImg', style: { margin: 'auto', display: 'block', 'max-width': '80vw', 'max-heigth': '80vh', }, }), m('div', { onclick: () => { this.modalDisplay('none'); }, style: { top: '15px', right: '35px', color: '#f1f1f1', transition: '0.3s', 'z-index': 10, position: 'absolute', 'font-size': '40px', 'font-weight': 'bold', }, }, 'x'), ]), ], [ m(Button, { label: 'Clone Event', border: true, style: { color: colors.light_blue, 'border-color': colors.light_blue, }, events: { // opens 'new event' , // coping All information but the 'event_id', past dates and API generated properties onclick: () => this.cloneEvent(), }, }), ]); } }