Newer
Older
import { Toolbar, ToolbarTitle, Card, Button } from 'polythene-mithril';
import { styler } from 'polythene-core-css';
import { DropdownCard, DatalistController, Chip } from 'amiv-web-ui-components';
import { apiUrl } from 'networkConfig';
import { eventsignups as signupConfig } from '../resourceConfig.json';
import TableView from '../views/tableView';
import RelationlistController from '../relationlistcontroller';
import { dateFormatter } from '../utils';
import { Property, FilterChip, icons } from '../views/elements';
import { ResourceHandler } from '../auth';
import { colors } from '../style';
const viewLayout = [
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',
'margin-top': '0px',
];
styler.add('eventView', viewLayout);
// small helper class to display both German and English content together, dependent
// on which content is available.
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),
]) : '',
);
}
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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');
},
},
}),
]);
}
}
// Helper class to either display the signed up participants or those on the
// waiting list.
class ParticipantsTable {
constructor({ attrs: { where, additional_fields_schema: additionalFieldsSchema } }) {
this.ctrl = new RelationlistController({
primary: 'eventsignups',
secondary: 'users',
query: { where },
searchKeys: ['email'],
includeWithoutRelation: true,
});
this.add_fields_schema = additionalFieldsSchema ?
JSON.parse(additionalFieldsSchema).properties : null;
exportAsCSV(filePrefix) {
this.ctrl.getFullList().then((list) => {
const csvData = (list.map((item) => {
const additionalFields = item.additional_fields && JSON.parse(item.additional_fields);
return [
item.position,
item._created,
item.user ? item.user.firstname : '',
item.user ? item.user.lastname : '',
item.user ? item.user.membership : 'none',
item.email,
item.accepted,
item.confirmed,
...Object.keys(this.add_fields_schema || {}).map(key =>
(additionalFields && additionalFields[key] ? additionalFields[key] : '')),
].join(',');
})).join('\n');
const header = [
'Position', 'Date', 'Firstname', 'Lastname', 'Membership', 'Email', 'Accepted', 'Confirmed',
...Object.keys(this.add_fields_schema || {}).map(key => this.add_fields_schema[key].title),
].join(',');
const filename = `${filePrefix}_participants_export.csv`;
const fileContent = `data:text/csv;charset=utf-8,${header}\n${csvData}`;
const link = document.createElement('a');
link.setAttribute('href', encodeURI(fileContent));
link.setAttribute('download', filename);
link.click();
});
}
// TODO list should not have hardcoded size outside of stylesheet
const hasPatchRights = data._links.self.methods.indexOf('PATCH') > -1;
const additionalFields = data.additional_fields && JSON.parse(data.additional_fields);
return [
m('div', { style: { width: '9em' } }, dateFormatter(data._created)),
m('div', { style: { width: '16em' } }, [
...data.user ? [`${data.user.firstname} ${data.user.lastname}`, m('br')] : '',
data.email,
]),
m('div', ...data.user ? `Membership: ${data.user.membership}` : ''),
(additionalFields && this.add_fields_schema) ? Object.keys(additionalFields).map(key =>
m('div', `${this.add_fields_schema[key].title}: ${additionalFields[key]}`)) : '',
),
m('div', { style: { 'flex-grow': '100' } }),
hasPatchRights ? m('div', m(Button, {
// Button to remove this eventsignup
className: 'red-row-button',
borders: false,
label: 'remove',
events: {
onclick: () => {
this.ctrl.handler.delete(data).then(() => {
this.ctrl.refresh();
m.redraw();
});
},
},
})) : '',
return m(Card, {
style: { height: '400px', 'margin-bottom': '10px' },
content: m('div', [
m(Toolbar, { compact: true }, [
m(ToolbarTitle, { text: title }),
m(Button, {
className: 'blue-button',
borders: true,
label: 'export CSV',
events: { onclick: () => this.exportAsCSV(filePrefix) },
}),
tableHeight: '275px',
controller: this.ctrl,
keys: signupConfig.tableKeys,
tileContent: data => this.itemRow(data),
clickOnRows: false,
titles: [
{ text: 'Date of Signup', width: '9em' },
{ text: 'Additional Info', width: '16em' },
});
}
}
this.signupHandler = new ResourceHandler('eventsignups');
this.signupCtrl = new DatalistController((query, search) => this.signupHandler.get({
search, ...query,
}));

Kai Ott
committed
this.advertisement = false;
this.registration = false;
this.signupCtrl.setQuery({ where: { event: this.data._id } });
this.signupCtrl.getFullList().then((list) => { this.allParticipants = list; });
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
cloneEvent() {
const event = Object.assign({}, this.data);
console.log(event);
const eventInfoToDelete = [
'_id',
'_created',
'_etag',
'_links',
'_updated',
'signup_count',
'__proto__',
];
const now = new Date();
console.log(`${now.toISOString().slice(0, -5)}Z`);
if (event.time_end < `${now.toISOString().slice(0, -5)}Z`) {
eventInfoToDelete.push(...[
'time_advertising_end',
'time_advertising_start',
'time_end',
'time_register_end',
'time_register_end',
'time_register_start',
'time_start']);
}
eventInfoToDelete.forEach((key) => {
delete event[key];
});
console.log(event);
this.controller.changeModus('new');
this.controller.data = event;
}
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;
}
this.data.img_thumbnail ? m('img', {

Hermann
committed
src: `${apiUrl}${this.data.img_thumbnail.file}`,
style: { float: 'left', margin: '0 5px' },
(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,
}, `${this.data.location}`),
this.data.time_start && m(Property, {
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(DropdownCard, { title: 'description' }, [
title: 'Catchphrase',
de: this.data.catchphrase_de,
en: this.data.catchphrase_en,
title: 'Description',
de: this.data.description_de,
en: this.data.description_en,
}),
]),
m(DropdownCard, { title: 'advertisement', style: { margin: '10px 0' } }, [
svg: this.data.show_annonce ? icons.checked : icons.clear,
border: '1px #aaaaaa solid',
}, 'announce'),
svg: this.data.show_infoscreen ? icons.checked : icons.clear,
border: '1px #aaaaaa solid',
margin: '4px',
}, 'infoscreen'),
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.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,
),
// 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.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, {
where: { accepted: true, event: this.data._id },
title: 'Accepted Participants',
additional_fields_schema: this.data.additional_fields,
}) : '',
this.data.time_register_start ? m(ParticipantsTable, {
where: { accepted: false, event: this.data._id },
title: 'Participants on Waiting List',
additional_fields_schema: this.data.additional_fields,
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
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(),
},
}),